1 <?php 2 /** 3 * Copyright 2010-2017 Horde LLC (http://www.horde.org/) 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * o Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * o Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * o The names of the authors may not be used to endorse or promote 16 * products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * @category Horde 32 * @copyright 2010-2017 Horde LLC 33 * @license http://www.horde.org/licenses/bsd New BSD License 34 * @package Mail 35 */ 36 37 /** 38 * SMTP implementation. 39 * 40 * @author Chuck Hagenbuch <chuck@horde.org> 41 * @author Jon Parise <jon@php.net> 42 * @author Michael Slusarz <slusarz@horde.org> 43 * @category Horde 44 * @copyright 2010-2016 Horde LLC 45 * @deprecated Use Horde_Mail_Transport_Hordesmtp instead 46 * @license http://www.horde.org/licenses/bsd New BSD License 47 * @package Mail 48 */ 49 class Horde_Mail_Transport_Smtp extends Horde_Mail_Transport 50 { 51 /* Error: Failed to create a Net_SMTP object */ 52 const ERROR_CREATE = 10000; 53 54 /* Error: Failed to connect to SMTP server */ 55 const ERROR_CONNECT = 10001; 56 57 /* Error: SMTP authentication failure */ 58 const ERROR_AUTH = 10002; 59 60 /* Error: No From: address has been provided */ 61 const ERROR_FROM = 10003; 62 63 /* Error: Failed to set sender */ 64 const ERROR_SENDER = 10004; 65 66 /* Error: Failed to add recipient */ 67 const ERROR_RECIPIENT = 10005; 68 69 /* Error: Failed to send data */ 70 const ERROR_DATA = 10006; 71 72 /** 73 * The SMTP greeting. 74 * 75 * @var string 76 */ 77 public $greeting = null; 78 79 /** 80 * The SMTP queued response. 81 * 82 * @var string 83 */ 84 public $queuedAs = null; 85 86 /** 87 * SMTP connection object. 88 * 89 * @var Net_SMTP 90 */ 91 protected $_smtp = null; 92 93 /** 94 * The list of service extension parameters to pass to the Net_SMTP 95 * mailFrom() command. 96 * 97 * @var array 98 */ 99 protected $_extparams = array(); 100 101 /** 102 * Constructor. 103 * 104 * @param array $params Additional parameters: 105 * - auth: (mixed) SMTP authentication. 106 * This value may be set to true, false or the name of a 107 * specific authentication method. If the value is set to true, 108 * the Net_SMTP package will attempt to use the best 109 * authentication method advertised by the remote SMTP server. 110 * DEFAULT: false. 111 * - debug: (boolean) Activate SMTP debug mode? 112 * DEFAULT: false 113 * - host: (string) The server to connect to. 114 * DEFAULT: localhost 115 * - localhost: (string) Hostname or domain that will be sent to the 116 * remote SMTP server in the HELO / EHLO message. 117 * DEFAULT: localhost 118 * - password: (string) The password to use for SMTP auth. 119 * DEFAULT: NONE 120 * - persist: (boolean) Should the SMTP connection persist? 121 * DEFAULT: false 122 * - pipelining: (boolean) Use SMTP command pipelining. 123 * Use SMTP command pipelining (specified in RFC 2920) if 124 * the SMTP server supports it. This speeds up delivery 125 * over high-latency connections. 126 * DEFAULT: false (use default value from Net_SMTP) 127 * - port: (integer) The port to connect to. 128 * DEFAULT: 25 129 * - timeout: (integer) The SMTP connection timeout. 130 * DEFAULT: NONE 131 * - username: (string) The username to use for SMTP auth. 132 * DEFAULT: NONE 133 */ 134 public function __construct(array $params = array()) 135 { 136 $this->_params = array_merge(array( 137 'auth' => false, 138 'debug' => false, 139 'host' => 'localhost', 140 'localhost' => 'localhost', 141 'password' => '', 142 'persist' => false, 143 'pipelining' => false, 144 'port' => 25, 145 'timeout' => null, 146 'username' => '' 147 ), $params); 148 149 /* Destructor implementation to ensure that we disconnect from any 150 * potentially-alive persistent SMTP connections. */ 151 register_shutdown_function(array($this, 'disconnect')); 152 153 /* SMTP requires CRLF line endings. */ 154 $this->sep = "\r\n"; 155 } 156 157 /** 158 */ 159 public function send($recipients, array $headers, $body) 160 { 161 /* If we don't already have an SMTP object, create one. */ 162 $this->getSMTPObject(); 163 164 $headers = $this->_sanitizeHeaders($headers); 165 166 /* Make sure the message has a trailing newline. */ 167 if (is_resource($body)) { 168 fseek($body, -1, SEEK_END); 169 switch (fgetc($body)) { 170 case "\r": 171 if (fgetc($body) != "\n") { 172 fputs($body, "\n"); 173 } 174 break; 175 176 default: 177 fputs($body, "\r\n"); 178 break; 179 } 180 rewind($body); 181 } elseif (substr($body, -2, 0) != "\r\n") { 182 $body .= "\r\n"; 183 } 184 185 try { 186 list($from, $textHeaders) = $this->prepareHeaders($headers); 187 } catch (Horde_Mail_Exception $e) { 188 $this->_smtp->rset(); 189 throw $e; 190 } 191 192 try { 193 $from = $this->_getFrom($from, $headers); 194 } catch (Horde_Mail_Exception $e) { 195 $this->_smtp->rset(); 196 throw new Horde_Mail_Exception('No From: address has been provided', self::ERROR_FROM); 197 } 198 199 $params = ''; 200 foreach ($this->_extparams as $key => $val) { 201 $params .= ' ' . $key . (is_null($val) ? '' : '=' . $val); 202 } 203 204 $res = $this->_smtp->mailFrom($from, ltrim($params)); 205 if ($res instanceof PEAR_Error) { 206 $this->_error(sprintf("Failed to set sender: %s", $from), $res, self::ERROR_SENDER); 207 } 208 209 try { 210 $recipients = $this->parseRecipients($recipients); 211 } catch (Horde_Mail_Exception $e) { 212 $this->_smtp->rset(); 213 throw $e; 214 } 215 216 foreach ($recipients as $recipient) { 217 $res = $this->_smtp->rcptTo($recipient); 218 if ($res instanceof PEAR_Error) { 219 $this->_error("Failed to add recipient: $recipient", $res, self::ERROR_RECIPIENT); 220 } 221 } 222 223 /* Send the message's headers and the body as SMTP data. Net_SMTP does 224 * the necessary EOL conversions. */ 225 $res = $this->_smtp->data($body, $textHeaders); 226 list(,$args) = $this->_smtp->getResponse(); 227 228 if (preg_match("/Ok: queued as (.*)/", $args, $queued)) { 229 $this->queuedAs = $queued[1]; 230 } 231 232 /* We need the greeting; from it we can extract the authorative name 233 * of the mail server we've really connected to. Ideal if we're 234 * connecting to a round-robin of relay servers and need to track 235 * which exact one took the email */ 236 $this->greeting = $this->_smtp->getGreeting(); 237 238 if ($res instanceof PEAR_Error) { 239 $this->_error('Failed to send data', $res, self::ERROR_DATA); 240 } 241 242 /* If persistent connections are disabled, destroy our SMTP object. */ 243 if (!$this->_params['persist']) { 244 $this->disconnect(); 245 } 246 } 247 248 /** 249 * Connect to the SMTP server by instantiating a Net_SMTP object. 250 * 251 * @return Net_SMTP The SMTP object. 252 * @throws Horde_Mail_Exception 253 */ 254 public function getSMTPObject() 255 { 256 if ($this->_smtp) { 257 return $this->_smtp; 258 } 259 260 $this->_smtp = new Net_SMTP( 261 $this->_params['host'], 262 $this->_params['port'], 263 $this->_params['localhost'] 264 ); 265 266 /* Set pipelining. */ 267 if ($this->_params['pipelining']) { 268 $this->_smtp->pipelining = true; 269 } 270 271 /* If we still don't have an SMTP object at this point, fail. */ 272 if (!($this->_smtp instanceof Net_SMTP)) { 273 throw new Horde_Mail_Exception('Failed to create a Net_SMTP object', self::ERROR_CREATE); 274 } 275 276 /* Configure the SMTP connection. */ 277 if ($this->_params['debug']) { 278 $this->_smtp->setDebug(true); 279 } 280 281 /* Attempt to connect to the configured SMTP server. */ 282 $res = $this->_smtp->connect($this->_params['timeout']); 283 if ($res instanceof PEAR_Error) { 284 $this->_error('Failed to connect to ' . $this->_params['host'] . ':' . $this->_params['port'], $res, self::ERROR_CONNECT); 285 } 286 287 /* Attempt to authenticate if authentication has been enabled. */ 288 if ($this->_params['auth']) { 289 $method = is_string($this->_params['auth']) 290 ? $this->_params['auth'] 291 : ''; 292 293 $res = $this->_smtp->auth($this->_params['username'], $this->_params['password'], $method); 294 if ($res instanceof PEAR_Error) { 295 $this->_error("$method authentication failure", $res, self::ERROR_AUTH); 296 } 297 } 298 299 return $this->_smtp; 300 } 301 302 /** 303 * Add parameter associated with a SMTP service extension. 304 * 305 * @param string $keyword Extension keyword. 306 * @param string $value Any value the keyword needs. 307 */ 308 public function addServiceExtensionParameter($keyword, $value = null) 309 { 310 $this->_extparams[$keyword] = $value; 311 } 312 313 /** 314 * Disconnect and destroy the current SMTP connection. 315 * 316 * @return boolean True if the SMTP connection no longer exists. 317 */ 318 public function disconnect() 319 { 320 /* If we have an SMTP object, disconnect and destroy it. */ 321 if (is_object($this->_smtp) && $this->_smtp->disconnect()) { 322 $this->_smtp = null; 323 } 324 325 /* We are disconnected if we no longer have an SMTP object. */ 326 return ($this->_smtp === null); 327 } 328 329 /** 330 * Build a standardized string describing the current SMTP error. 331 * 332 * @param string $text Custom string describing the error context. 333 * @param PEAR_Error $error PEAR_Error object. 334 * @param integer $e_code Error code. 335 * 336 * @throws Horde_Mail_Exception 337 */ 338 protected function _error($text, $error, $e_code) 339 { 340 /* Split the SMTP response into a code and a response string. */ 341 list($code, $response) = $this->_smtp->getResponse(); 342 343 /* Abort current SMTP transaction. */ 344 $this->_smtp->rset(); 345 346 /* Build our standardized error string. */ 347 throw new Horde_Mail_Exception($text . ' [SMTP: ' . $error->getMessage() . " (code: $code, response: $response)]", $e_code); 348 } 349 350 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body