Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationLatte
      • ApplicationTracy
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsLatte
      • Framework
      • HttpTracy
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Templating
    • Utils
  • NetteModule
  • none
  • Tracy

Classes

  • Message
  • MimePart
  • SendmailMailer
  • SmtpMailer

Interfaces

  • IMailer

Exceptions

  • SmtpException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Mail;
  9: 
 10: use Nette;
 11: 
 12: 
 13: /**
 14:  * Sends emails via the SMTP server.
 15:  *
 16:  * @author     David Grudl
 17:  */
 18: class SmtpMailer extends Nette\Object implements IMailer
 19: {
 20:     /** @var resource */
 21:     private $connection;
 22: 
 23:     /** @var string */
 24:     private $host;
 25: 
 26:     /** @var int */
 27:     private $port;
 28: 
 29:     /** @var string */
 30:     private $username;
 31: 
 32:     /** @var string */
 33:     private $password;
 34: 
 35:     /** @var string ssl | tls | (empty) */
 36:     private $secure;
 37: 
 38:     /** @var int */
 39:     private $timeout;
 40: 
 41:     /** @var bool */
 42:     private $persistent;
 43: 
 44: 
 45:     public function __construct(array $options = array())
 46:     {
 47:         if (isset($options['host'])) {
 48:             $this->host = $options['host'];
 49:             $this->port = isset($options['port']) ? (int) $options['port'] : NULL;
 50:         } else {
 51:             $this->host = ini_get('SMTP');
 52:             $this->port = (int) ini_get('smtp_port');
 53:         }
 54:         $this->username = isset($options['username']) ? $options['username'] : '';
 55:         $this->password = isset($options['password']) ? $options['password'] : '';
 56:         $this->secure = isset($options['secure']) ? $options['secure'] : '';
 57:         $this->timeout = isset($options['timeout']) ? (int) $options['timeout'] : 20;
 58:         if (!$this->port) {
 59:             $this->port = $this->secure === 'ssl' ? 465 : 25;
 60:         }
 61:         $this->persistent = !empty($options['persistent']);
 62:     }
 63: 
 64: 
 65:     /**
 66:      * Sends email.
 67:      * @return void
 68:      */
 69:     public function send(Message $mail)
 70:     {
 71:         $mail = clone $mail;
 72: 
 73:         try {
 74:             if (!$this->connection) {
 75:                 $this->connect();
 76:             }
 77: 
 78:             if (($from = $mail->getHeader('Return-Path'))
 79:                 || ($from = key($mail->getHeader('From')))
 80:             ) {
 81:                 $this->write("MAIL FROM:<$from>", 250);
 82:             }
 83: 
 84:             foreach (array_merge(
 85:                 (array) $mail->getHeader('To'),
 86:                 (array) $mail->getHeader('Cc'),
 87:                 (array) $mail->getHeader('Bcc')
 88:             ) as $email => $name) {
 89:                 $this->write("RCPT TO:<$email>", array(250, 251));
 90:             }
 91: 
 92:             $mail->setHeader('Bcc', NULL);
 93:             $data = $mail->generateMessage();
 94:             $this->write('DATA', 354);
 95:             $data = preg_replace('#^\.#m', '..', $data);
 96:             $this->write($data);
 97:             $this->write('.', 250);
 98: 
 99:             if (!$this->persistent) {
100:                 $this->write('QUIT', 221);
101:                 $this->disconnect();
102:             }
103:         } catch (SmtpException $e) {
104:             if ($this->connection) {
105:                 $this->disconnect();
106:             }
107:             throw $e;
108:         }
109:     }
110: 
111: 
112:     /**
113:      * Connects and authenticates to SMTP server.
114:      * @return void
115:      */
116:     protected function connect()
117:     {
118:         $this->connection = @fsockopen( // intentionally @
119:             ($this->secure === 'ssl' ? 'ssl://' : '') . $this->host,
120:             $this->port, $errno, $error, $this->timeout
121:         );
122:         if (!$this->connection) {
123:             throw new SmtpException($error, $errno);
124:         }
125:         stream_set_timeout($this->connection, $this->timeout, 0);
126:         $this->read(); // greeting
127: 
128:         $self = isset($_SERVER['HTTP_HOST']) && preg_match('#^[\w.-]+\z#', $_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
129:         $this->write("EHLO $self");
130:         if ((int) $this->read() !== 250) {
131:             $this->write("HELO $self", 250);
132:         }
133: 
134:         if ($this->secure === 'tls') {
135:             $this->write('STARTTLS', 220);
136:             if (!stream_socket_enable_crypto($this->connection, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
137:                 throw new SmtpException('Unable to connect via TLS.');
138:             }
139:             $this->write("EHLO $self", 250);
140:         }
141: 
142:         if ($this->username != NULL && $this->password != NULL) {
143:             $this->write('AUTH LOGIN', 334);
144:             $this->write(base64_encode($this->username), 334, 'username');
145:             $this->write(base64_encode($this->password), 235, 'password');
146:         }
147:     }
148: 
149: 
150:     /**
151:      * Disconnects from SMTP server.
152:      * @return void
153:      */
154:     protected function disconnect()
155:     {
156:         fclose($this->connection);
157:         $this->connection = NULL;
158:     }
159: 
160: 
161:     /**
162:      * Writes data to server and checks response against expected code if some provided.
163:      * @param  string
164:      * @param  int   response code
165:      * @param  string  error message
166:      * @return void
167:      */
168:     protected function write($line, $expectedCode = NULL, $message = NULL)
169:     {
170:         fwrite($this->connection, $line . Message::EOL);
171:         if ($expectedCode) {
172:             $response = $this->read();
173:             if (!in_array((int) $response, (array) $expectedCode, TRUE)) {
174:                 throw new SmtpException('SMTP server did not accept ' . ($message ? $message : $line) . ' with error: ' . trim($response));
175:             }
176:         }
177:     }
178: 
179: 
180:     /**
181:      * Reads response from server.
182:      * @return string
183:      */
184:     protected function read()
185:     {
186:         $s = '';
187:         while (($line = fgets($this->connection, 1e3)) != NULL) { // intentionally ==
188:             $s .= $line;
189:             if (substr($line, 3, 1) === ' ') {
190:                 break;
191:             }
192:         }
193:         return $s;
194:     }
195: 
196: }
197: 
198: 
199: /**
200:  * SMTP mailer exception.
201:  *
202:  * @author     David Grudl
203:  */
204: class SmtpException extends \Exception
205: {
206: }
207: 
Nette 2.2 API documentation generated by ApiGen 2.8.0