ILIAS  Release_4_4_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
smtpmx.php
Go to the documentation of this file.
1 <?PHP
2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3 
50 require_once 'Net/SMTP.php';
51 
61 class Mail_smtpmx extends Mail {
62 
69  var $_smtp = null;
70 
76  var $port = 25;
77 
85  var $mailname = 'localhost';
86 
92  var $timeout = 10;
93 
99  var $withNetDns = true;
100 
107 
114  var $verp = false;
115 
121  var $vrfy = false;
122 
128  var $test = false;
129 
135  var $debug = false;
136 
149  var $errorCode = array(
150  'not_connected' => array(
151  'code' => 1,
152  'msg' => 'Could not connect to any mail server ({HOST}) at port {PORT} to send mail to {RCPT}.'
153  ),
154  'failed_vrfy_rcpt' => array(
155  'code' => 2,
156  'msg' => 'Recipient "{RCPT}" could not be veryfied.'
157  ),
158  'failed_set_from' => array(
159  'code' => 3,
160  'msg' => 'Failed to set sender: {FROM}.'
161  ),
162  'failed_set_rcpt' => array(
163  'code' => 4,
164  'msg' => 'Failed to set recipient: {RCPT}.'
165  ),
166  'failed_send_data' => array(
167  'code' => 5,
168  'msg' => 'Failed to send mail to: {RCPT}.'
169  ),
170  'no_from' => array(
171  'code' => 5,
172  'msg' => 'No from address has be provided.'
173  ),
174  'send_data' => array(
175  'code' => 7,
176  'msg' => 'Failed to create Net_SMTP object.'
177  ),
178  'no_mx' => array(
179  'code' => 8,
180  'msg' => 'No MX-record for {RCPT} found.'
181  ),
182  'no_resolver' => array(
183  'code' => 9,
184  'msg' => 'Could not start resolver! Install PEAR:Net_DNS or switch off "netdns"'
185  ),
186  'failed_rset' => array(
187  'code' => 10,
188  'msg' => 'RSET command failed, SMTP-connection corrupt.'
189  ),
190  );
191 
214  function __construct($params)
215  {
216  if (isset($params['mailname'])) {
217  $this->mailname = $params['mailname'];
218  } else {
219  // try to find a valid mailname
220  if (function_exists('posix_uname')) {
221  $uname = posix_uname();
222  $this->mailname = $uname['nodename'];
223  }
224  }
225 
226  // port number
227  if (isset($params['port'])) {
228  $this->_port = $params['port'];
229  } else {
230  $this->_port = getservbyname('smtp', 'tcp');
231  }
232 
233  if (isset($params['timeout'])) $this->timeout = $params['timeout'];
234  if (isset($params['verp'])) $this->verp = $params['verp'];
235  if (isset($params['test'])) $this->test = $params['test'];
236  if (isset($params['peardebug'])) $this->test = $params['peardebug'];
237  if (isset($params['netdns'])) $this->withNetDns = $params['netdns'];
238  }
239 
247  function Mail_smtpmx($params)
248  {
249  $this->__construct($params);
250  register_shutdown_function(array(&$this, '__destruct'));
251  }
252 
257  function __destruct()
258  {
259  if (is_object($this->_smtp)) {
260  $this->_smtp->disconnect();
261  $this->_smtp = null;
262  }
263  }
264 
274  function send($recipients, $headers, $body)
275  {
276  if (!is_array($headers)) {
277  return PEAR::raiseError('$headers must be an array');
278  }
279 
280  $result = $this->_sanitizeHeaders($headers);
281  if (is_a($result, 'PEAR_Error')) {
282  return $result;
283  }
284 
285  // Prepare headers
286  $headerElements = $this->prepareHeaders($headers);
287  if (is_a($headerElements, 'PEAR_Error')) {
288  return $headerElements;
289  }
290  list($from, $textHeaders) = $headerElements;
291 
292  // use 'Return-Path' if possible
293  if (!empty($headers['Return-Path'])) {
294  $from = $headers['Return-Path'];
295  }
296  if (!isset($from)) {
297  return $this->_raiseError('no_from');
298  }
299 
300  // Prepare recipients
301  $recipients = $this->parseRecipients($recipients);
302  if (is_a($recipients, 'PEAR_Error')) {
303  return $recipients;
304  }
305 
306  foreach ($recipients as $rcpt) {
307  list($user, $host) = explode('@', $rcpt);
308 
309  $mx = $this->_getMx($host);
310  if (is_a($mx, 'PEAR_Error')) {
311  return $mx;
312  }
313 
314  if (empty($mx)) {
315  $info = array('rcpt' => $rcpt);
316  return $this->_raiseError('no_mx', $info);
317  }
318 
319  $connected = false;
320  foreach ($mx as $mserver => $mpriority) {
321  $this->_smtp = new Net_SMTP($mserver, $this->port, $this->mailname);
322 
323  // configure the SMTP connection.
324  if ($this->debug) {
325  $this->_smtp->setDebug(true);
326  }
327 
328  // attempt to connect to the configured SMTP server.
329  $res = $this->_smtp->connect($this->timeout);
330  if (is_a($res, 'PEAR_Error')) {
331  $this->_smtp = null;
332  continue;
333  }
334 
335  // connection established
336  if ($res) {
337  $connected = true;
338  break;
339  }
340  }
341 
342  if (!$connected) {
343  $info = array(
344  'host' => implode(', ', array_keys($mx)),
345  'port' => $this->port,
346  'rcpt' => $rcpt,
347  );
348  return $this->_raiseError('not_connected', $info);
349  }
350 
351  // Verify recipient
352  if ($this->vrfy) {
353  $res = $this->_smtp->vrfy($rcpt);
354  if (is_a($res, 'PEAR_Error')) {
355  $info = array('rcpt' => $rcpt);
356  return $this->_raiseError('failed_vrfy_rcpt', $info);
357  }
358  }
359 
360  // mail from:
361  $args['verp'] = $this->verp;
362  $res = $this->_smtp->mailFrom($from, $args);
363  if (is_a($res, 'PEAR_Error')) {
364  $info = array('from' => $from);
365  return $this->_raiseError('failed_set_from', $info);
366  }
367 
368  // rcpt to:
369  $res = $this->_smtp->rcptTo($rcpt);
370  if (is_a($res, 'PEAR_Error')) {
371  $info = array('rcpt' => $rcpt);
372  return $this->_raiseError('failed_set_rcpt', $info);
373  }
374 
375  // Don't send anything in test mode
376  if ($this->test) {
377  $result = $this->_smtp->rset();
378  $res = $this->_smtp->rset();
379  if (is_a($res, 'PEAR_Error')) {
380  return $this->_raiseError('failed_rset');
381  }
382 
383  $this->_smtp->disconnect();
384  $this->_smtp = null;
385  return true;
386  }
387 
388  // Send data
389  $res = $this->_smtp->data("$textHeaders\r\n$body");
390  if (is_a($res, 'PEAR_Error')) {
391  $info = array('rcpt' => $rcpt);
392  return $this->_raiseError('failed_send_data', $info);
393  }
394 
395  $this->_smtp->disconnect();
396  $this->_smtp = null;
397  }
398 
399  return true;
400  }
401 
411  function _getMx($host)
412  {
413  $mx = array();
414 
415  if ($this->withNetDns) {
416  $res = $this->_loadNetDns();
417  if (is_a($res, 'PEAR_Error')) {
418  return $res;
419  }
420 
421  $response = $this->resolver->query($host, 'MX');
422  if (!$response) {
423  return false;
424  }
425 
426  foreach ($response->answer as $rr) {
427  if ($rr->type == 'MX') {
428  $mx[$rr->exchange] = $rr->preference;
429  }
430  }
431  } else {
432  $mxHost = array();
433  $mxWeight = array();
434 
435  if (!getmxrr($host, $mxHost, $mxWeight)) {
436  return false;
437  }
438  for ($i = 0; $i < count($mxHost); ++$i) {
439  $mx[$mxHost[$i]] = $mxWeight[$i];
440  }
441  }
442 
443  asort($mx);
444  return $mx;
445  }
446 
453  function _loadNetDns()
454  {
455  if (is_object($this->resolver)) {
456  return true;
457  }
458 
459  if (!include_once 'Net/DNS.php') {
460  return $this->_raiseError('no_resolver');
461  }
462 
463  $this->resolver = new Net_DNS_Resolver();
464  if ($this->debug) {
465  $this->resolver->test = 1;
466  }
467 
468  return true;
469  }
470 
481  function _raiseError($id, $info = array())
482  {
483  $code = $this->errorCode[$id]['code'];
484  $msg = $this->errorCode[$id]['msg'];
485 
486  // include info to messages
487  if (!empty($info)) {
488  $search = array();
489  $replace = array();
490 
491  foreach ($info as $key => $value) {
492  array_push($search, '{' . strtoupper($key) . '}');
493  array_push($replace, $value);
494  }
495 
496  $msg = str_replace($search, $replace, $msg);
497  }
498 
499  return PEAR::raiseError($msg, $code);
500  }
501 
502 }