3 // +----------------------------------------------------------------------+
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997-2003 The PHP Group |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 2.02 of the PHP license, |
9 // | that is bundled with this package in the file LICENSE, and is |
10 // | available at through the world-wide-web at |
11 // | http://www.php.net/license/2_02.txt. |
12 // | If you did not receive a copy of the PHP license and are unable to |
13 // | obtain it through the world-wide-web, please send a note to |
14 // | license@php.net so we can mail you a copy immediately. |
15 // +----------------------------------------------------------------------+
16 // | Authors: Chuck Hagenbuch <chuck@horde.org> |
17 // | Jon Parise <jon@php.net> |
18 // +----------------------------------------------------------------------+
20 /** Error: Failed to create a Net_SMTP object */
21 define('PEAR_MAIL_SMTP_ERROR_CREATE', 10000);
23 /** Error: Failed to connect to SMTP server */
24 define('PEAR_MAIL_SMTP_ERROR_CONNECT', 10001);
26 /** Error: SMTP authentication failure */
27 define('PEAR_MAIL_SMTP_ERROR_AUTH', 10002);
29 /** Error: No From: address has been provided */
30 define('PEAR_MAIL_SMTP_ERROR_FROM', 10003);
32 /** Error: Failed to set sender */
33 define('PEAR_MAIL_SMTP_ERROR_SENDER', 10004);
35 /** Error: Failed to add recipient */
36 define('PEAR_MAIL_SMTP_ERROR_RECIPIENT', 10005);
38 /** Error: Failed to send data */
39 define('PEAR_MAIL_SMTP_ERROR_DATA', 10006);
42 * SMTP implementation of the PEAR Mail interface. Requires the Net_SMTP class.
45 * @version $Revision: 1.33 $
47 class Mail_smtp extends Mail {
50 * SMTP connection object.
58 * The list of service extension parameters to pass to the Net_SMTP
62 var $_extparams = array();
65 * The SMTP host to connect to.
68 var $host = 'localhost';
71 * The port the SMTP server is on.
77 * Should SMTP authentication be used?
79 * This value may be set to true, false or the name of a specific
80 * authentication method.
82 * If the value is set to true, the Net_SMTP package will attempt to use
83 * the best authentication method advertised by the remote SMTP server.
90 * The username to use if the SMTP server requires authentication.
96 * The password to use if the SMTP server requires authentication.
102 * Hostname or domain that will be sent to the remote SMTP server in the
103 * HELO / EHLO message.
107 var $localhost = 'localhost';
110 * SMTP connection timeout value. NULL indicates no timeout.
117 * Turn on Net_SMTP debugging?
119 * @var boolean $debug
124 * Indicates whether or not the SMTP connection should persist over
125 * multiple calls to the send() method.
129 var $persist = false;
132 * Use SMTP command pipelining (specified in RFC 2920) if the SMTP server
133 * supports it. This speeds up delivery over high-latency connections. By
134 * default, use the default value supplied by Net_SMTP.
142 * Instantiates a new Mail_smtp:: object based on the parameters
143 * passed in. It looks for the following parameters:
144 * host The server to connect to. Defaults to localhost.
145 * port The port to connect to. Defaults to 25.
146 * auth SMTP authentication. Defaults to none.
147 * username The username to use for SMTP auth. No default.
148 * password The password to use for SMTP auth. No default.
149 * localhost The local hostname / domain. Defaults to localhost.
150 * timeout The SMTP connection timeout. Defaults to none.
151 * verp Whether to use VERP or not. Defaults to false.
152 * DEPRECATED as of 1.2.0 (use setMailParams()).
153 * debug Activate SMTP debug mode? Defaults to false.
154 * persist Should the SMTP connection persist?
155 * pipelining Use SMTP command pipelining
157 * If a parameter is present in the $params array, it replaces the
160 * @param array Hash containing any parameters different from the
164 function Mail_smtp($params)
166 if (isset($params['host'])) $this->host = $params['host'];
167 if (isset($params['port'])) $this->port = $params['port'];
168 if (isset($params['auth'])) $this->auth = $params['auth'];
169 if (isset($params['username'])) $this->username = $params['username'];
170 if (isset($params['password'])) $this->password = $params['password'];
171 if (isset($params['localhost'])) $this->localhost = $params['localhost'];
172 if (isset($params['timeout'])) $this->timeout = $params['timeout'];
173 if (isset($params['debug'])) $this->debug = (bool)$params['debug'];
174 if (isset($params['persist'])) $this->persist = (bool)$params['persist'];
175 if (isset($params['pipelining'])) $this->pipelining = (bool)$params['pipelining'];
177 // Deprecated options
178 if (isset($params['verp'])) {
179 $this->addServiceExtensionParameter('XVERP', is_bool($params['verp']) ? null : $params['verp']);
182 register_shutdown_function(array(&$this, '_Mail_smtp'));
186 * Destructor implementation to ensure that we disconnect from any
187 * potentially-alive persistent SMTP connections.
189 function _Mail_smtp()
195 * Implements Mail::send() function using SMTP.
197 * @param mixed $recipients Either a comma-seperated list of recipients
198 * (RFC822 compliant), or an array of recipients,
199 * each RFC822 valid. This may contain recipients not
200 * specified in the headers, for Bcc:, resending
203 * @param array $headers The array of headers to send with the mail, in an
204 * associative array, where the array key is the
205 * header name (e.g., 'Subject'), and the array value
206 * is the header value (e.g., 'test'). The header
207 * produced from those values would be 'Subject:
210 * @param string $body The full text of the message body, including any
213 * @return mixed Returns true on success, or a PEAR_Error
214 * containing a descriptive error message on
218 function send($recipients, $headers, $body)
220 /* If we don't already have an SMTP object, create one. */
221 $result = &$this->getSMTPObject();
222 if (PEAR::isError($result)) {
226 if (!is_array($headers)) {
227 return PEAR::raiseError('$headers must be an array');
230 $this->_sanitizeHeaders($headers);
232 $headerElements = $this->prepareHeaders($headers);
233 if (is_a($headerElements, 'PEAR_Error')) {
234 $this->_smtp->rset();
235 return $headerElements;
237 list($from, $textHeaders) = $headerElements;
239 /* Since few MTAs are going to allow this header to be forged
240 * unless it's in the MAIL FROM: exchange, we'll use
241 * Return-Path instead of From: if it's set. */
242 if (!empty($headers['Return-Path'])) {
243 $from = $headers['Return-Path'];
247 $this->_smtp->rset();
248 return PEAR::raiseError('No From: address has been provided',
249 PEAR_MAIL_SMTP_ERROR_FROM);
253 if (!empty($this->_extparams)) {
254 foreach ($this->_extparams as $key => $val) {
255 $params .= ' ' . $key . (is_null($val) ? '' : '=' . $val);
258 if (PEAR::isError($res = $this->_smtp->mailFrom($from, ltrim($params)))) {
259 $error = $this->_error("Failed to set sender: $from", $res);
260 $this->_smtp->rset();
261 return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_SENDER);
264 $recipients = $this->parseRecipients($recipients);
265 if (is_a($recipients, 'PEAR_Error')) {
266 $this->_smtp->rset();
270 foreach ($recipients as $recipient) {
271 $res = $this->_smtp->rcptTo($recipient);
272 if (is_a($res, 'PEAR_Error')) {
273 $error = $this->_error("Failed to add recipient: $recipient", $res);
274 $this->_smtp->rset();
275 return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_RECIPIENT);
279 /* Send the message's headers and the body as SMTP data. */
280 $res = $this->_smtp->data($textHeaders . "\r\n\r\n" . $body);
281 if (is_a($res, 'PEAR_Error')) {
282 $error = $this->_error('Failed to send data', $res);
283 $this->_smtp->rset();
284 return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_DATA);
287 /* If persistent connections are disabled, destroy our SMTP object. */
288 if ($this->persist === false) {
296 * Connect to the SMTP server by instantiating a Net_SMTP object.
298 * @return mixed Returns a reference to the Net_SMTP object on success, or
299 * a PEAR_Error containing a descriptive error message on
305 function &getSMTPObject()
307 if (is_object($this->_smtp) !== false) {
311 include_once 'Net/SMTP.php';
312 $this->_smtp = &new Net_SMTP($this->host,
316 /* If we still don't have an SMTP object at this point, fail. */
317 if (is_object($this->_smtp) === false) {
318 return PEAR::raiseError('Failed to create a Net_SMTP object',
319 PEAR_MAIL_SMTP_ERROR_CREATE);
322 /* Configure the SMTP connection. */
324 $this->_smtp->setDebug(true);
327 /* Attempt to connect to the configured SMTP server. */
328 if (PEAR::isError($res = $this->_smtp->connect($this->timeout))) {
329 $error = $this->_error('Failed to connect to ' .
330 $this->host . ':' . $this->port,
332 return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_CONNECT);
335 /* Attempt to authenticate if authentication has been enabled. */
337 $method = is_string($this->auth) ? $this->auth : '';
339 if (PEAR::isError($res = $this->_smtp->auth($this->username,
342 $error = $this->_error("$method authentication failure",
344 $this->_smtp->rset();
345 return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_AUTH);
353 * Add parameter associated with a SMTP service extension.
355 * @param string Extension keyword.
356 * @param string Any value the keyword needs.
361 function addServiceExtensionParameter($keyword, $value = null)
363 $this->_extparams[$keyword] = $value;
367 * Disconnect and destroy the current SMTP connection.
369 * @return boolean True if the SMTP connection no longer exists.
374 function disconnect()
376 /* If we have an SMTP object, disconnect and destroy it. */
377 if (is_object($this->_smtp) && $this->_smtp->disconnect()) {
381 /* We are disconnected if we no longer have an SMTP object. */
382 return ($this->_smtp === null);
386 * Build a standardized string describing the current SMTP error.
388 * @param string $text Custom string describing the error context.
389 * @param object $error Reference to the current PEAR_Error object.
391 * @return string A string describing the current SMTP error.
396 function _error($text, &$error)
398 /* Split the SMTP response into a code and a response string. */
399 list($code, $response) = $this->_smtp->getResponse();
401 /* Build our standardized error string. */
403 . ' [SMTP: ' . $error->getMessage()
404 . " (code: $code, response: $response)]";