2011-03-01 16:47:05 +00:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Send mail using SMTP protocol
|
|
|
|
*
|
|
|
|
* PHP 5
|
|
|
|
*
|
|
|
|
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
|
|
|
|
* Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
|
|
|
*
|
|
|
|
* Licensed under The MIT License
|
|
|
|
* Redistributions of files must retain the above copyright notice.
|
|
|
|
*
|
|
|
|
* @copyright Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
|
|
|
|
* @link http://cakephp.org CakePHP(tm) Project
|
2011-07-26 06:16:14 +00:00
|
|
|
* @package Cake.Network.Email
|
2011-03-01 16:47:05 +00:00
|
|
|
* @since CakePHP(tm) v 2.0.0
|
|
|
|
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
|
|
|
|
*/
|
2011-04-13 03:29:34 +00:00
|
|
|
App::uses('CakeSocket', 'Network');
|
2011-03-01 16:47:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* SendEmail class
|
|
|
|
*
|
2011-07-26 06:16:14 +00:00
|
|
|
* @package Cake.Network.Email
|
2011-03-01 16:47:05 +00:00
|
|
|
*/
|
|
|
|
class SmtpTransport extends AbstractTransport {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Socket to SMTP server
|
|
|
|
*
|
|
|
|
* @var object CakeScoket
|
|
|
|
*/
|
|
|
|
protected $_socket;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* CakeEmail
|
|
|
|
*
|
|
|
|
* @var object CakeEmail
|
|
|
|
*/
|
|
|
|
protected $_cakeEmail;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send mail
|
|
|
|
*
|
|
|
|
* @params object $email CakeEmail
|
|
|
|
* @return boolean
|
2011-04-29 01:25:18 +00:00
|
|
|
* @throws SocketException
|
2011-03-01 16:47:05 +00:00
|
|
|
*/
|
|
|
|
public function send(CakeEmail $email) {
|
|
|
|
$this->_cakeEmail = $email;
|
|
|
|
|
|
|
|
$this->_connect();
|
|
|
|
$this->_auth();
|
|
|
|
$this->_sendRcpt();
|
|
|
|
$this->_sendData();
|
|
|
|
$this->_disconnect();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-04-13 04:04:37 +00:00
|
|
|
/**
|
|
|
|
* Set the configuration
|
|
|
|
*
|
|
|
|
* @param array $config
|
|
|
|
* @return object $this
|
|
|
|
*/
|
|
|
|
public function config($config = array()) {
|
|
|
|
$default = array(
|
|
|
|
'host' => 'localhost',
|
|
|
|
'port' => 25,
|
|
|
|
'timeout' => 30,
|
|
|
|
'username' => null,
|
|
|
|
'password' => null,
|
|
|
|
'client' => null
|
|
|
|
);
|
|
|
|
$this->_config = $config + $default;
|
|
|
|
}
|
|
|
|
|
2011-03-01 16:47:05 +00:00
|
|
|
/**
|
|
|
|
* Connect to SMTP Server
|
|
|
|
*
|
|
|
|
* @return void
|
2011-04-29 01:25:18 +00:00
|
|
|
* @throws SocketException
|
2011-03-01 16:47:05 +00:00
|
|
|
*/
|
|
|
|
protected function _connect() {
|
|
|
|
$this->_generateSocket();
|
|
|
|
if (!$this->_socket->connect()) {
|
2011-04-13 03:37:50 +00:00
|
|
|
throw new SocketException(__d('cake', 'Unable to connect in SMTP server.'));
|
2011-03-01 16:47:05 +00:00
|
|
|
}
|
|
|
|
$this->_smtpSend(null, '220');
|
|
|
|
|
|
|
|
if (isset($this->_config['client'])) {
|
|
|
|
$host = $this->_config['client'];
|
|
|
|
} elseif ($httpHost = env('HTTP_HOST')) {
|
|
|
|
list($host) = explode(':', $httpHost);
|
|
|
|
} else {
|
|
|
|
$host = 'localhost';
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
$this->_smtpSend("EHLO {$host}", '250');
|
|
|
|
} catch (SocketException $e) {
|
|
|
|
try {
|
|
|
|
$this->_smtpSend("HELO {$host}", '250');
|
|
|
|
} catch (SocketException $e2) {
|
2011-04-13 03:37:50 +00:00
|
|
|
throw new SocketException(__d('cake', 'SMTP server not accepted the connection.'));
|
2011-03-01 16:47:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send authentication
|
|
|
|
*
|
|
|
|
* @return void
|
2011-04-29 01:25:18 +00:00
|
|
|
* @throws SocketException
|
2011-03-01 16:47:05 +00:00
|
|
|
*/
|
|
|
|
protected function _auth() {
|
|
|
|
if (isset($this->_config['username']) && isset($this->_config['password'])) {
|
|
|
|
$authRequired = $this->_smtpSend('AUTH LOGIN', '334|503');
|
|
|
|
if ($authRequired == '334') {
|
|
|
|
if (!$this->_smtpSend(base64_encode($this->_config['username']), '334')) {
|
2011-04-13 03:37:50 +00:00
|
|
|
throw new SocketException(__d('cake', 'SMTP server not accepted the username.'));
|
2011-03-01 16:47:05 +00:00
|
|
|
}
|
|
|
|
if (!$this->_smtpSend(base64_encode($this->_config['password']), '235')) {
|
2011-04-13 03:37:50 +00:00
|
|
|
throw new SocketException(__d('cake', 'SMTP server not accepted the password.'));
|
2011-03-01 16:47:05 +00:00
|
|
|
}
|
|
|
|
} elseif ($authRequired != '503') {
|
2011-04-13 03:37:50 +00:00
|
|
|
throw new SocketException(__d('cake', 'SMTP do not require authentication.'));
|
2011-03-01 16:47:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send emails
|
|
|
|
*
|
|
|
|
* @return void
|
2011-04-29 01:25:18 +00:00
|
|
|
* @throws SocketException
|
2011-03-01 16:47:05 +00:00
|
|
|
*/
|
|
|
|
protected function _sendRcpt() {
|
2011-04-04 03:37:29 +00:00
|
|
|
$from = $this->_cakeEmail->from();
|
2011-03-01 22:14:34 +00:00
|
|
|
$this->_smtpSend('MAIL FROM:<' . key($from) . '>');
|
2011-03-01 16:47:05 +00:00
|
|
|
|
2011-04-04 03:37:29 +00:00
|
|
|
$to = $this->_cakeEmail->to();
|
|
|
|
$cc = $this->_cakeEmail->cc();
|
|
|
|
$bcc = $this->_cakeEmail->bcc();
|
2011-03-01 16:47:05 +00:00
|
|
|
$emails = array_merge(array_keys($to), array_keys($cc), array_keys($bcc));
|
|
|
|
foreach ($emails as $email) {
|
2011-03-01 22:14:34 +00:00
|
|
|
$this->_smtpSend('RCPT TO:<' . $email . '>');
|
2011-03-01 16:47:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send Data
|
|
|
|
*
|
|
|
|
* @return void
|
2011-04-29 01:25:18 +00:00
|
|
|
* @throws SocketException
|
2011-03-01 16:47:05 +00:00
|
|
|
*/
|
|
|
|
protected function _sendData() {
|
|
|
|
$this->_smtpSend('DATA', '354');
|
|
|
|
|
2011-04-20 00:18:02 +00:00
|
|
|
$headers = $this->_cakeEmail->getHeaders(array_fill_keys(array('from', 'sender', 'replyTo', 'readReceipt', 'returnPath', 'to', 'cc', 'bcc', 'subject'), true));
|
2011-03-01 18:24:38 +00:00
|
|
|
$headers = $this->_headersToString($headers);
|
2011-04-04 03:37:29 +00:00
|
|
|
$message = implode("\r\n", $this->_cakeEmail->message());
|
2011-03-01 18:24:38 +00:00
|
|
|
$this->_smtpSend($headers . "\r\n\r\n" . $message . "\r\n\r\n\r\n.");
|
2011-03-01 16:47:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Disconnect
|
|
|
|
*
|
|
|
|
* @return void
|
2011-04-29 01:25:18 +00:00
|
|
|
* @throws SocketException
|
2011-03-01 16:47:05 +00:00
|
|
|
*/
|
|
|
|
protected function _disconnect() {
|
|
|
|
$this->_smtpSend('QUIT', false);
|
|
|
|
$this->_socket->disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper method to generate socket
|
|
|
|
*
|
|
|
|
* @return void
|
2011-04-29 01:25:18 +00:00
|
|
|
* @throws SocketException
|
2011-03-01 16:47:05 +00:00
|
|
|
*/
|
|
|
|
protected function _generateSocket() {
|
|
|
|
$this->_socket = new CakeSocket($this->_config);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Protected method for sending data to SMTP connection
|
|
|
|
*
|
|
|
|
* @param string $data data to be sent to SMTP server
|
|
|
|
* @param mixed $checkCode code to check for in server response, false to skip
|
|
|
|
* @return void
|
2011-04-29 01:25:18 +00:00
|
|
|
* @throws SocketException
|
2011-03-01 16:47:05 +00:00
|
|
|
*/
|
2011-05-28 20:38:46 +00:00
|
|
|
protected function _smtpSend($data, $checkCode = '250') {
|
2011-03-01 16:47:05 +00:00
|
|
|
if (!is_null($data)) {
|
|
|
|
$this->_socket->write($data . "\r\n");
|
|
|
|
}
|
|
|
|
while ($checkCode !== false) {
|
|
|
|
$response = '';
|
|
|
|
$startTime = time();
|
2011-04-04 02:41:40 +00:00
|
|
|
while (substr($response, -2) !== "\r\n" && ((time() - $startTime) < $this->_config['timeout'])) {
|
2011-03-01 16:47:05 +00:00
|
|
|
$response .= $this->_socket->read();
|
|
|
|
}
|
|
|
|
if (substr($response, -2) !== "\r\n") {
|
2011-04-13 03:37:50 +00:00
|
|
|
throw new SocketException(__d('cake', 'SMTP timeout.'));
|
2011-03-01 16:47:05 +00:00
|
|
|
}
|
|
|
|
$response = end(explode("\r\n", rtrim($response, "\r\n")));
|
|
|
|
|
|
|
|
if (preg_match('/^(' . $checkCode . ')(.)/', $response, $code)) {
|
|
|
|
if ($code[2] === '-') {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
return $code[1];
|
|
|
|
}
|
2011-04-13 03:37:50 +00:00
|
|
|
throw new SocketException(__d('cake', 'SMTP Error: %s', $response));
|
2011-03-01 16:47:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|