CakePHP
  • Documentation
    • Book
    • API
    • Videos
    • Reporting Security Issues
    • Privacy Policy
    • Logos & Trademarks
  • Business Solutions
  • Swag
  • Road Trip
  • Team
  • Community
    • Community
    • Get Involved
    • Issues (GitHub)
    • Bakery
    • Featured Resources
    • Training
    • Meetups
    • My CakePHP
    • CakeFest
    • Newsletter
    • Linkedin
    • YouTube
    • Facebook
    • Twitter
    • Mastodon
    • Help & Support
    • Forum
    • Stack Overflow
    • Slack
    • Paid Support
CakePHP

C CakePHP 2.8 API

  • Overview
  • Tree
  • Deprecated
  • Version:
    • 2.8
      • 4.2
      • 4.1
      • 4.0
      • 3.9
      • 3.8
      • 3.7
      • 3.6
      • 3.5
      • 3.4
      • 3.3
      • 3.2
      • 3.1
      • 3.0
      • 2.10
      • 2.9
      • 2.8
      • 2.7
      • 2.6
      • 2.5
      • 2.4
      • 2.3
      • 2.2
      • 2.1
      • 2.0
      • 1.3
      • 1.2

Packages

  • Cake
    • Cache
      • Engine
    • Configure
    • Console
      • Command
        • Task
    • Controller
      • Component
        • Acl
        • Auth
    • Core
    • Error
    • Event
    • I18n
    • Log
      • Engine
    • Model
      • Behavior
      • Datasource
        • Database
        • Session
      • Validator
    • Network
      • Email
      • Http
    • Routing
      • Filter
      • Route
    • TestSuite
      • Coverage
      • Fixture
      • Reporter
    • Utility
    • View
      • Helper
  • None

Classes

  • AbstractTransport
  • CakeEmail
  • DebugTransport
  • MailTransport
  • SmtpTransport
  1: <?php
  2: /**
  3:  * Send mail using SMTP protocol
  4:  *
  5:  * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  6:  * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  7:  *
  8:  * Licensed under The MIT License
  9:  * For full copyright and license information, please see the LICENSE.txt
 10:  * Redistributions of files must retain the above copyright notice.
 11:  *
 12:  * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 13:  * @link          http://cakephp.org CakePHP(tm) Project
 14:  * @package       Cake.Network.Email
 15:  * @since         CakePHP(tm) v 2.0.0
 16:  * @license       http://www.opensource.org/licenses/mit-license.php MIT License
 17:  */
 18: App::uses('AbstractTransport', 'Network/Email');
 19: App::uses('CakeSocket', 'Network');
 20: 
 21: /**
 22:  * Send mail using SMTP protocol
 23:  *
 24:  * @package       Cake.Network.Email
 25:  */
 26: class SmtpTransport extends AbstractTransport {
 27: 
 28: /**
 29:  * Socket to SMTP server
 30:  *
 31:  * @var CakeSocket
 32:  */
 33:     protected $_socket;
 34: 
 35: /**
 36:  * Content of email to return
 37:  *
 38:  * @var string
 39:  */
 40:     protected $_content;
 41: 
 42: /**
 43:  * The response of the last sent SMTP command.
 44:  *
 45:  * @var array
 46:  */
 47:     protected $_lastResponse = array();
 48: 
 49: /**
 50:  * Returns the response of the last sent SMTP command.
 51:  *
 52:  * A response consists of one or more lines containing a response
 53:  * code and an optional response message text:
 54:  * ```
 55:  * array(
 56:  *     array(
 57:  *         'code' => '250',
 58:  *         'message' => 'mail.example.com'
 59:  *     ),
 60:  *     array(
 61:  *         'code' => '250',
 62:  *         'message' => 'PIPELINING'
 63:  *     ),
 64:  *     array(
 65:  *         'code' => '250',
 66:  *         'message' => '8BITMIME'
 67:  *     ),
 68:  *     // etc...
 69:  * )
 70:  * ```
 71:  *
 72:  * @return array
 73:  */
 74:     public function getLastResponse() {
 75:         return $this->_lastResponse;
 76:     }
 77: 
 78: /**
 79:  * Send mail
 80:  *
 81:  * @param CakeEmail $email CakeEmail
 82:  * @return array
 83:  * @throws SocketException
 84:  */
 85:     public function send(CakeEmail $email) {
 86:         $this->_connect();
 87:         $this->_auth();
 88:         $this->_sendRcpt($email);
 89:         $this->_sendData($email);
 90:         $this->_disconnect();
 91: 
 92:         return $this->_content;
 93:     }
 94: 
 95: /**
 96:  * Set the configuration
 97:  *
 98:  * @param array $config Configuration options.
 99:  * @return array Returns configs
100:  */
101:     public function config($config = null) {
102:         if ($config === null) {
103:             return $this->_config;
104:         }
105:         $default = array(
106:             'host' => 'localhost',
107:             'port' => 25,
108:             'timeout' => 30,
109:             'username' => null,
110:             'password' => null,
111:             'client' => null,
112:             'tls' => false,
113:             'ssl_allow_self_signed' => false
114:         );
115:         $this->_config = array_merge($default, $this->_config, $config);
116:         return $this->_config;
117:     }
118: 
119: /**
120:  * Parses and stores the reponse lines in `'code' => 'message'` format.
121:  *
122:  * @param array $responseLines Response lines to parse.
123:  * @return void
124:  */
125:     protected function _bufferResponseLines(array $responseLines) {
126:         $response = array();
127:         foreach ($responseLines as $responseLine) {
128:             if (preg_match('/^(\d{3})(?:[ -]+(.*))?$/', $responseLine, $match)) {
129:                 $response[] = array(
130:                     'code' => $match[1],
131:                     'message' => isset($match[2]) ? $match[2] : null
132:                 );
133:             }
134:         }
135:         $this->_lastResponse = array_merge($this->_lastResponse, $response);
136:     }
137: 
138: /**
139:  * Connect to SMTP Server
140:  *
141:  * @return void
142:  * @throws SocketException
143:  */
144:     protected function _connect() {
145:         $this->_generateSocket();
146:         if (!$this->_socket->connect()) {
147:             throw new SocketException(__d('cake_dev', 'Unable to connect to SMTP server.'));
148:         }
149:         $this->_smtpSend(null, '220');
150: 
151:         if (isset($this->_config['client'])) {
152:             $host = $this->_config['client'];
153:         } elseif ($httpHost = env('HTTP_HOST')) {
154:             list($host) = explode(':', $httpHost);
155:         } else {
156:             $host = 'localhost';
157:         }
158: 
159:         try {
160:             $this->_smtpSend("EHLO {$host}", '250');
161:             if ($this->_config['tls']) {
162:                 $this->_smtpSend("STARTTLS", '220');
163:                 $this->_socket->enableCrypto('tls');
164:                 $this->_smtpSend("EHLO {$host}", '250');
165:             }
166:         } catch (SocketException $e) {
167:             if ($this->_config['tls']) {
168:                 throw new SocketException(__d('cake_dev', 'SMTP server did not accept the connection or trying to connect to non TLS SMTP server using TLS.'));
169:             }
170:             try {
171:                 $this->_smtpSend("HELO {$host}", '250');
172:             } catch (SocketException $e2) {
173:                 throw new SocketException(__d('cake_dev', 'SMTP server did not accept the connection.'));
174:             }
175:         }
176:     }
177: 
178: /**
179:  * Send authentication
180:  *
181:  * @return void
182:  * @throws SocketException
183:  */
184:     protected function _auth() {
185:         if (isset($this->_config['username']) && isset($this->_config['password'])) {
186:             $replyCode = $this->_smtpSend('AUTH LOGIN', '334|500|502|504');
187:             if ($replyCode == '334') {
188:                 try {
189:                     $this->_smtpSend(base64_encode($this->_config['username']), '334');
190:                 } catch (SocketException $e) {
191:                     throw new SocketException(__d('cake_dev', 'SMTP server did not accept the username.'));
192:                 }
193:                 try {
194:                     $this->_smtpSend(base64_encode($this->_config['password']), '235');
195:                 } catch (SocketException $e) {
196:                     throw new SocketException(__d('cake_dev', 'SMTP server did not accept the password.'));
197:                 }
198:             } elseif ($replyCode == '504') {
199:                 throw new SocketException(__d('cake_dev', 'SMTP authentication method not allowed, check if SMTP server requires TLS.'));
200:             } else {
201:                 throw new SocketException(__d('cake_dev', 'AUTH command not recognized or not implemented, SMTP server may not require authentication.'));
202:             }
203:         }
204:     }
205: 
206: /**
207:  * Prepares the `MAIL FROM` SMTP command.
208:  *
209:  * @param string $email The email address to send with the command.
210:  * @return string
211:  */
212:     protected function _prepareFromCmd($email) {
213:         return 'MAIL FROM:<' . $email . '>';
214:     }
215: 
216: /**
217:  * Prepares the `RCPT TO` SMTP command.
218:  *
219:  * @param string $email The email address to send with the command.
220:  * @return string
221:  */
222:     protected function _prepareRcptCmd($email) {
223:         return 'RCPT TO:<' . $email . '>';
224:     }
225: 
226: /**
227:  * Prepares the `from` email address.
228:  *
229:  * @param CakeEmail $email CakeEmail
230:  * @return array
231:  */
232:     protected function _prepareFromAddress(CakeEmail $email) {
233:         $from = $email->returnPath();
234:         if (empty($from)) {
235:             $from = $email->from();
236:         }
237:         return $from;
238:     }
239: 
240: /**
241:  * Prepares the recipient email addresses.
242:  *
243:  * @param CakeEmail $email CakeEmail
244:  * @return array
245:  */
246:     protected function _prepareRecipientAddresses(CakeEmail $email) {
247:         $to = $email->to();
248:         $cc = $email->cc();
249:         $bcc = $email->bcc();
250:         return array_merge(array_keys($to), array_keys($cc), array_keys($bcc));
251:     }
252: 
253: /**
254:  * Prepares the message headers.
255:  *
256:  * @param CakeEmail $email CakeEmail
257:  * @return array
258:  */
259:     protected function _prepareMessageHeaders(CakeEmail $email) {
260:         return $email->getHeaders(array('from', 'sender', 'replyTo', 'readReceipt', 'to', 'cc', 'subject'));
261:     }
262: 
263: /**
264:  * Prepares the message body.
265:  *
266:  * @param CakeEmail $email CakeEmail
267:  * @return string
268:  */
269:     protected function _prepareMessage(CakeEmail $email) {
270:         $lines = $email->message();
271:         $messages = array();
272:         foreach ($lines as $line) {
273:             if ((!empty($line)) && ($line[0] === '.')) {
274:                 $messages[] = '.' . $line;
275:             } else {
276:                 $messages[] = $line;
277:             }
278:         }
279:         return implode("\r\n", $messages);
280:     }
281: 
282: /**
283:  * Send emails
284:  *
285:  * @param CakeEmail $email CakeEmail
286:  * @return void
287:  * @throws SocketException
288:  */
289:     protected function _sendRcpt(CakeEmail $email) {
290:         $from = $this->_prepareFromAddress($email);
291:         $this->_smtpSend($this->_prepareFromCmd(key($from)));
292: 
293:         $emails = $this->_prepareRecipientAddresses($email);
294:         foreach ($emails as $email) {
295:             $this->_smtpSend($this->_prepareRcptCmd($email));
296:         }
297:     }
298: 
299: /**
300:  * Send Data
301:  *
302:  * @param CakeEmail $email CakeEmail
303:  * @return void
304:  * @throws SocketException
305:  */
306:     protected function _sendData(CakeEmail $email) {
307:         $this->_smtpSend('DATA', '354');
308: 
309:         $headers = $this->_headersToString($this->_prepareMessageHeaders($email));
310:         $message = $this->_prepareMessage($email);
311: 
312:         $this->_smtpSend($headers . "\r\n\r\n" . $message . "\r\n\r\n\r\n.");
313:         $this->_content = array('headers' => $headers, 'message' => $message);
314:     }
315: 
316: /**
317:  * Disconnect
318:  *
319:  * @return void
320:  * @throws SocketException
321:  */
322:     protected function _disconnect() {
323:         $this->_smtpSend('QUIT', false);
324:         $this->_socket->disconnect();
325:     }
326: 
327: /**
328:  * Helper method to generate socket
329:  *
330:  * @return void
331:  * @throws SocketException
332:  */
333:     protected function _generateSocket() {
334:         $this->_socket = new CakeSocket($this->_config);
335:     }
336: 
337: /**
338:  * Protected method for sending data to SMTP connection
339:  *
340:  * @param string|null $data Data to be sent to SMTP server
341:  * @param string|bool $checkCode Code to check for in server response, false to skip
342:  * @return string|null The matched code, or null if nothing matched
343:  * @throws SocketException
344:  */
345:     protected function _smtpSend($data, $checkCode = '250') {
346:         $this->_lastResponse = array();
347: 
348:         if ($data !== null) {
349:             $this->_socket->write($data . "\r\n");
350:         }
351:         while ($checkCode !== false) {
352:             $response = '';
353:             $startTime = time();
354:             while (substr($response, -2) !== "\r\n" && ((time() - $startTime) < $this->_config['timeout'])) {
355:                 $response .= $this->_socket->read();
356:             }
357:             if (substr($response, -2) !== "\r\n") {
358:                 throw new SocketException(__d('cake_dev', 'SMTP timeout.'));
359:             }
360:             $responseLines = explode("\r\n", rtrim($response, "\r\n"));
361:             $response = end($responseLines);
362: 
363:             $this->_bufferResponseLines($responseLines);
364: 
365:             if (preg_match('/^(' . $checkCode . ')(.)/', $response, $code)) {
366:                 if ($code[2] === '-') {
367:                     continue;
368:                 }
369:                 return $code[1];
370:             }
371:             throw new SocketException(__d('cake_dev', 'SMTP Error: %s', $response));
372:         }
373:     }
374: 
375: }
376: 
OpenHub
Rackspace
Rackspace
  • Business Solutions
  • Showcase
  • Documentation
  • Book
  • API
  • Videos
  • Reporting Security Issues
  • Privacy Policy
  • Logos & Trademarks
  • Community
  • Get Involved
  • Issues (GitHub)
  • Bakery
  • Featured Resources
  • Training
  • Meetups
  • My CakePHP
  • CakeFest
  • Newsletter
  • Linkedin
  • YouTube
  • Facebook
  • Twitter
  • Mastodon
  • Help & Support
  • Forum
  • Stack Overflow
  • Slack
  • Paid Support

Generated using CakePHP API Docs