[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?PHP 2 /** 3 * Copyright 2010-2014 Horde LLC (http://www.horde.org/) 4 * Copyright (c) 2010 Gerd Schaufelberger 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * o Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * o Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * o The names of the authors may not be used to endorse or promote 17 * products derived from this software without specific prior written 18 * permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * @category Horde 33 * @copyright 2010-2014 Horde LLC 34 * @copyright 2010 Gerd Schaufelberger 35 * @license http://www.horde.org/licenses/bsd New BSD License 36 * @package Mail 37 */ 38 39 /** 40 * SMTP MX implementation. 41 * 42 * @author Gerd Schaufelberger <gerd@php-tools.net> 43 * @author Michael Slusarz <slusarz@horde.org> 44 * @category Horde 45 * @copyright 2010-2014 Horde LLC 46 * @copyright 2010 Gerd Schaufelberger 47 * @license http://www.horde.org/licenses/bsd New BSD License 48 * @package Mail 49 */ 50 class Horde_Mail_Transport_Smtpmx extends Horde_Mail_Transport 51 { 52 /** 53 * SMTP connection object. 54 * 55 * @var Net_SMTP 56 */ 57 protected $_smtp = null; 58 59 /** 60 * Net_DNS2_Resolver object. 61 * 62 * @var Net_DNS2_Resolver 63 */ 64 protected $_resolver; 65 66 /** 67 * Internal error codes. 68 * Translate internal error identifier to human readable messages. 69 * 70 * @var array 71 */ 72 protected $_errorCode = array( 73 'not_connected' => array( 74 'code' => 1, 75 'msg' => 'Could not connect to any mail server ({HOST}) at port {PORT} to send mail to {RCPT}.' 76 ), 77 'failed_vrfy_rcpt' => array( 78 'code' => 2, 79 'msg' => 'Recipient "{RCPT}" could not be veryfied.' 80 ), 81 'failed_set_from' => array( 82 'code' => 3, 83 'msg' => 'Failed to set sender: {FROM}.' 84 ), 85 'failed_set_rcpt' => array( 86 'code' => 4, 87 'msg' => 'Failed to set recipient: {RCPT}.' 88 ), 89 'failed_send_data' => array( 90 'code' => 5, 91 'msg' => 'Failed to send mail to: {RCPT}.' 92 ), 93 'no_from' => array( 94 'code' => 5, 95 'msg' => 'No from address has be provided.' 96 ), 97 'send_data' => array( 98 'code' => 7, 99 'msg' => 'Failed to create Net_SMTP object.' 100 ), 101 'no_mx' => array( 102 'code' => 8, 103 'msg' => 'No MX-record for {RCPT} found.' 104 ), 105 'no_resolver' => array( 106 'code' => 9, 107 'msg' => 'Could not start resolver! Install PEAR:Net_DNS2 or switch off "netdns"' 108 ), 109 'failed_rset' => array( 110 'code' => 10, 111 'msg' => 'RSET command failed, SMTP-connection corrupt.' 112 ) 113 ); 114 115 /** 116 * @param array $params Additional options: 117 * - debug: (boolean) Activate SMTP debug mode? 118 * DEFAULT: false 119 * - mailname: (string) The name of the local mail system (a valid 120 * hostname which matches the reverse lookup) 121 * DEFAULT: Auto-determined 122 * - netdns: (boolean) Use PEAR:Net_DNS2 (true) or the PHP builtin 123 * getmxrr(). 124 * DEFAULT: true 125 * - port: (integer) Port. 126 * DEFAULT: Auto-determined 127 * - test: (boolean) Activate test mode? 128 * DEFAULT: false 129 * - timeout: (integer) The SMTP connection timeout (in seconds). 130 * DEFAULT: 10 131 * - verp: (boolean) Whether to use VERP. 132 * If not a boolean, the string value will be used as the VERP 133 * separators. 134 * DEFAULT: false 135 * - vrfy: (boolean) Whether to use VRFY. 136 * DEFAULT: false 137 */ 138 public function __construct(array $params = array()) 139 { 140 /* Try to find a valid mailname. */ 141 if (!isset($params['mailname']) && function_exists('posix_uname')) { 142 $uname = posix_uname(); 143 $params['mailname'] = $uname['nodename']; 144 } 145 146 if (!isset($params['port'])) { 147 $params['port'] = getservbyname('smtp', 'tcp'); 148 } 149 150 $this->_params = array_merge(array( 151 'debug' => false, 152 'mailname' => 'localhost', 153 'netdns' => true, 154 'port' => 25, 155 'test' => false, 156 'timeout' => 10, 157 'verp' => false, 158 'vrfy' => false 159 ), $params); 160 161 /* SMTP requires CRLF line endings. */ 162 $this->sep = "\r\n"; 163 } 164 165 /** 166 * Destructor implementation to ensure that we disconnect from any 167 * potentially-alive persistent SMTP connections. 168 */ 169 public function __destruct() 170 { 171 if (is_object($this->_smtp)) { 172 $this->_smtp->disconnect(); 173 $this->_smtp = null; 174 } 175 } 176 177 /** 178 */ 179 public function send($recipients, array $headers, $body) 180 { 181 $headers = $this->_sanitizeHeaders($headers); 182 183 // Prepare headers 184 list($from, $textHeaders) = $this->prepareHeaders($headers); 185 186 try { 187 $from = $this->_getFrom($from, $headers); 188 } catch (Horde_Mail_Exception $e) { 189 $this->_error('no_from'); 190 } 191 192 // Prepare recipients 193 foreach ($this->parseRecipients($recipients) as $rcpt) { 194 list(,$host) = explode('@', $rcpt); 195 196 $mx = $this->_getMx($host); 197 if (!$mx) { 198 $this->_error('no_mx', array('rcpt' => $rcpt)); 199 } 200 201 $connected = false; 202 foreach (array_keys($mx) as $mserver) { 203 $this->_smtp = new Net_SMTP($mserver, $this->_params['port'], $this->_params['mailname']); 204 205 // configure the SMTP connection. 206 if ($this->_params['debug']) { 207 $this->_smtp->setDebug(true); 208 } 209 210 // attempt to connect to the configured SMTP server. 211 $res = $this->_smtp->connect($this->_params['timeout']); 212 if ($res instanceof PEAR_Error) { 213 $this->_smtp = null; 214 continue; 215 } 216 217 // connection established 218 if ($res) { 219 $connected = true; 220 break; 221 } 222 } 223 224 if (!$connected) { 225 $this->_error('not_connected', array( 226 'host' => implode(', ', array_keys($mx)), 227 'port' => $this->_params['port'], 228 'rcpt' => $rcpt 229 )); 230 } 231 232 // Verify recipient 233 if ($this->_params['vrfy']) { 234 $res = $this->_smtp->vrfy($rcpt); 235 if ($res instanceof PEAR_Error) { 236 $this->_error('failed_vrfy_rcpt', array('rcpt' => $rcpt)); 237 } 238 } 239 240 // mail from: 241 $args['verp'] = $this->_params['verp']; 242 $res = $this->_smtp->mailFrom($from, $args); 243 if ($res instanceof PEAR_Error) { 244 $this->_error('failed_set_from', array('from' => $from)); 245 } 246 247 // rcpt to: 248 $res = $this->_smtp->rcptTo($rcpt); 249 if ($res instanceof PEAR_Error) { 250 $this->_error('failed_set_rcpt', array('rcpt' => $rcpt)); 251 } 252 253 // Don't send anything in test mode 254 if ($this->_params['test']) { 255 $res = $this->_smtp->rset(); 256 if ($res instanceof PEAR_Error) { 257 $this->_error('failed_rset'); 258 } 259 260 $this->_smtp->disconnect(); 261 $this->_smtp = null; 262 return; 263 } 264 265 // Send data. Net_SMTP does necessary EOL conversions. 266 $res = $this->_smtp->data($body, $textHeaders); 267 if ($res instanceof PEAR_Error) { 268 $this->_error('failed_send_data', array('rcpt' => $rcpt)); 269 } 270 271 $this->_smtp->disconnect(); 272 $this->_smtp = null; 273 } 274 } 275 276 /** 277 * Recieve MX records for a host. 278 * 279 * @param string $host Mail host. 280 * 281 * @return mixed Sorted MX list or false on error. 282 */ 283 protected function _getMx($host) 284 { 285 $mx = array(); 286 287 if ($this->params['netdns']) { 288 $this->_loadNetDns(); 289 290 try { 291 $response = $this->_resolver->query($host, 'MX'); 292 if (!$response) { 293 return false; 294 } 295 } catch (Exception $e) { 296 throw new Horde_Mail_Exception($e); 297 } 298 299 foreach ($response->answer as $rr) { 300 if ($rr->type == 'MX') { 301 $mx[$rr->exchange] = $rr->preference; 302 } 303 } 304 } else { 305 $mxHost = $mxWeight = array(); 306 307 if (!getmxrr($host, $mxHost, $mxWeight)) { 308 return false; 309 } 310 311 for ($i = 0; $i < count($mxHost); ++$i) { 312 $mx[$mxHost[$i]] = $mxWeight[$i]; 313 } 314 } 315 316 asort($mx); 317 318 return $mx; 319 } 320 321 /** 322 * Initialize Net_DNS2_Resolver. 323 */ 324 protected function _loadNetDns() 325 { 326 if (!$this->_resolver) { 327 if (!class_exists('Net_DNS2_Resolver')) { 328 $this->_error('no_resolver'); 329 } 330 $this->_resolver = new Net_DNS2_Resolver(); 331 } 332 } 333 334 /** 335 * Format error message. 336 * 337 * @param string $id Maps error ids to codes and message. 338 * @param array $info Optional information in associative array. 339 * 340 * @throws Horde_Mail_Exception 341 */ 342 protected function _error($id, $info = array()) 343 { 344 $msg = $this->_errorCode[$id]['msg']; 345 346 // include info to messages 347 if (!empty($info)) { 348 $replace = $search = array(); 349 350 foreach ($info as $key => $value) { 351 $search[] = '{' . strtoupper($key) . '}'; 352 $replace[] = $value; 353 } 354 355 $msg = str_replace($search, $replace, $msg); 356 } 357 358 throw new Horde_Mail_Exception($msg, $this->_errorCode[$id]['code']); 359 } 360 361 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |