|
|
@@ -47,6 +47,42 @@ class SmtpTransport extends AbstractTransport {
|
|
|
protected $_content;
|
|
|
|
|
|
/**
|
|
|
+ * The response of the last sent SMTP command.
|
|
|
+ *
|
|
|
+ * @var array
|
|
|
+ */
|
|
|
+ protected $_lastResponse = array();
|
|
|
+
|
|
|
+/**
|
|
|
+ * Returns the response of the last sent SMTP command.
|
|
|
+ *
|
|
|
+ * A response consists of one or more lines containing a response
|
|
|
+ * code and an optional response message text:
|
|
|
+ * {{{
|
|
|
+ * array(
|
|
|
+ * array(
|
|
|
+ * 'code' => '250',
|
|
|
+ * 'message' => 'mail.example.com'
|
|
|
+ * ),
|
|
|
+ * array(
|
|
|
+ * 'code' => '250',
|
|
|
+ * 'message' => 'PIPELINING'
|
|
|
+ * ),
|
|
|
+ * array(
|
|
|
+ * 'code' => '250',
|
|
|
+ * 'message' => '8BITMIME'
|
|
|
+ * ),
|
|
|
+ * // etc...
|
|
|
+ * )
|
|
|
+ * }}}
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public function getLastResponse() {
|
|
|
+ return $this->_lastResponse;
|
|
|
+ }
|
|
|
+
|
|
|
+/**
|
|
|
* Send mail
|
|
|
*
|
|
|
* @param CakeEmail $email CakeEmail
|
|
|
@@ -89,6 +125,25 @@ class SmtpTransport extends AbstractTransport {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * Parses and stores the reponse lines in `'code' => 'message'` format.
|
|
|
+ *
|
|
|
+ * @param array $responseLines
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ protected function _bufferResponseLines(array $responseLines) {
|
|
|
+ $response = array();
|
|
|
+ foreach ($responseLines as $responseLine) {
|
|
|
+ if (preg_match('/^(\d{3})(?:[ -]+(.*))?$/', $responseLine, $match)) {
|
|
|
+ $response[] = array(
|
|
|
+ 'code' => $match[1],
|
|
|
+ 'message' => isset($match[2]) ? $match[2] : null
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $this->_lastResponse = array_merge($this->_lastResponse, $response);
|
|
|
+ }
|
|
|
+
|
|
|
+/**
|
|
|
* Connect to SMTP Server
|
|
|
*
|
|
|
* @return void
|
|
|
@@ -153,38 +208,65 @@ class SmtpTransport extends AbstractTransport {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Send emails
|
|
|
+ * Prepares the `MAIL FROM` SMTP command.
|
|
|
*
|
|
|
- * @return void
|
|
|
- * @throws SocketException
|
|
|
+ * @param string $email The email address to send with the command.
|
|
|
+ * @return string
|
|
|
*/
|
|
|
- protected function _sendRcpt() {
|
|
|
+ protected function _prepareFromCmd($email) {
|
|
|
+ return 'MAIL FROM:<' . $email . '>';
|
|
|
+ }
|
|
|
+
|
|
|
+/**
|
|
|
+ * Prepares the `RCPT TO` SMTP command.
|
|
|
+ *
|
|
|
+ * @param string $email The email address to send with the command.
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ protected function _prepareRcptCmd($email) {
|
|
|
+ return 'RCPT TO:<' . $email . '>';
|
|
|
+ }
|
|
|
+
|
|
|
+/**
|
|
|
+ * Prepares the `from` email address.
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ protected function _prepareFromAddress() {
|
|
|
$from = $this->_cakeEmail->returnPath();
|
|
|
if (empty($from)) {
|
|
|
$from = $this->_cakeEmail->from();
|
|
|
}
|
|
|
- $this->_smtpSend('MAIL FROM:<' . key($from) . '>');
|
|
|
+ return $from;
|
|
|
+ }
|
|
|
|
|
|
+/**
|
|
|
+ * Prepares the recipient email addresses.
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ protected function _prepareRecipientAddresses() {
|
|
|
$to = $this->_cakeEmail->to();
|
|
|
$cc = $this->_cakeEmail->cc();
|
|
|
$bcc = $this->_cakeEmail->bcc();
|
|
|
- $emails = array_merge(array_keys($to), array_keys($cc), array_keys($bcc));
|
|
|
- foreach ($emails as $email) {
|
|
|
- $this->_smtpSend('RCPT TO:<' . $email . '>');
|
|
|
- }
|
|
|
+ return array_merge(array_keys($to), array_keys($cc), array_keys($bcc));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Send Data
|
|
|
+ * Prepares the message headers.
|
|
|
*
|
|
|
- * @return void
|
|
|
- * @throws SocketException
|
|
|
+ * @return array
|
|
|
*/
|
|
|
- protected function _sendData() {
|
|
|
- $this->_smtpSend('DATA', '354');
|
|
|
+ protected function _prepareMessageHeaders() {
|
|
|
+ return $this->_cakeEmail->getHeaders(array('from', 'sender', 'replyTo', 'readReceipt', 'to', 'cc', 'subject'));
|
|
|
+ }
|
|
|
|
|
|
- $headers = $this->_cakeEmail->getHeaders(array('from', 'sender', 'replyTo', 'readReceipt', 'to', 'cc', 'subject'));
|
|
|
- $headers = $this->_headersToString($headers);
|
|
|
+/**
|
|
|
+ * Prepares the message body.
|
|
|
+ *
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ protected function _prepareMessage() {
|
|
|
$lines = $this->_cakeEmail->message();
|
|
|
$messages = array();
|
|
|
foreach ($lines as $line) {
|
|
|
@@ -194,7 +276,37 @@ class SmtpTransport extends AbstractTransport {
|
|
|
$messages[] = $line;
|
|
|
}
|
|
|
}
|
|
|
- $message = implode("\r\n", $messages);
|
|
|
+ return implode("\r\n", $messages);
|
|
|
+ }
|
|
|
+
|
|
|
+/**
|
|
|
+ * Send emails
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @throws SocketException
|
|
|
+ */
|
|
|
+ protected function _sendRcpt() {
|
|
|
+ $from = $this->_prepareFromAddress();
|
|
|
+ $this->_smtpSend($this->_prepareFromCmd(key($from)));
|
|
|
+
|
|
|
+ $emails = $this->_prepareRecipientAddresses();
|
|
|
+ foreach ($emails as $email) {
|
|
|
+ $this->_smtpSend($this->_prepareRcptCmd($email));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+/**
|
|
|
+ * Send Data
|
|
|
+ *
|
|
|
+ * @return void
|
|
|
+ * @throws SocketException
|
|
|
+ */
|
|
|
+ protected function _sendData() {
|
|
|
+ $this->_smtpSend('DATA', '354');
|
|
|
+
|
|
|
+ $headers = $this->_headersToString($this->_prepareMessageHeaders());
|
|
|
+ $message = $this->_prepareMessage();
|
|
|
+
|
|
|
$this->_smtpSend($headers . "\r\n\r\n" . $message . "\r\n\r\n\r\n.");
|
|
|
$this->_content = array('headers' => $headers, 'message' => $message);
|
|
|
}
|
|
|
@@ -229,6 +341,8 @@ class SmtpTransport extends AbstractTransport {
|
|
|
* @throws SocketException
|
|
|
*/
|
|
|
protected function _smtpSend($data, $checkCode = '250') {
|
|
|
+ $this->_lastResponse = array();
|
|
|
+
|
|
|
if ($data !== null) {
|
|
|
$this->_socket->write($data . "\r\n");
|
|
|
}
|
|
|
@@ -244,6 +358,8 @@ class SmtpTransport extends AbstractTransport {
|
|
|
$responseLines = explode("\r\n", rtrim($response, "\r\n"));
|
|
|
$response = end($responseLines);
|
|
|
|
|
|
+ $this->_bufferResponseLines($responseLines);
|
|
|
+
|
|
|
if (preg_match('/^(' . $checkCode . ')(.)/', $response, $code)) {
|
|
|
if ($code[2] === '-') {
|
|
|
continue;
|