2 /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
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 // | Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar> |
19 // +----------------------------------------------------------------------+
21 // $Id: SMTP.php 293948 2010-01-24 21:46:00Z jon $
23 require_once 'PEAR.php';
24 require_once 'Net/Socket.php';
27 * Provides an implementation of the SMTP protocol using PEAR's
31 * @author Chuck Hagenbuch <chuck@horde.org>
32 * @author Jon Parise <jon@php.net>
33 * @author Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>
35 * @example basic.php A basic implementation of the Net_SMTP package.
40 * The server to connect to.
44 var $host = 'localhost';
47 * The port to connect to.
54 * The value to give when sending EHLO or HELO.
58 var $localhost = 'localhost';
61 * List of supported authentication methods, in preferential order.
65 var $auth_methods = array('DIGEST-MD5', 'CRAM-MD5', 'LOGIN', 'PLAIN');
68 * Use SMTP command pipelining (specified in RFC 2920) if the SMTP
71 * When pipeling is enabled, rcptTo(), mailFrom(), sendFrom(),
72 * somlFrom() and samlFrom() do not wait for a response from the
73 * SMTP server but return immediately.
78 var $pipelining = false;
81 * Number of pipelined commands.
85 var $_pipelined_commands = 0;
88 * Should debugging output be enabled?
95 * Debug output handler.
99 var $_debug_handler = null;
102 * The socket resource being used to connect to the SMTP server.
109 * The most recent server response code.
116 * The most recent server response arguments.
120 var $_arguments = array();
123 * Stores the SMTP server's greeting string.
127 var $_greeting = null;
130 * Stores detected features of the SMTP server.
134 var $_esmtp = array();
137 * Instantiates a new Net_SMTP object, overriding any defaults
138 * with parameters that are passed in.
140 * If you have SSL support in PHP, you can connect to a server
141 * over SSL using an 'ssl://' prefix:
143 * // 465 is a common smtps port.
144 * $smtp = new Net_SMTP('ssl://mail.host.com', 465);
147 * @param string $host The server to connect to.
148 * @param integer $port The port to connect to.
149 * @param string $localhost The value to give when sending EHLO or HELO.
150 * @param boolean $pipeling Use SMTP command pipelining
155 function Net_SMTP($host = null, $port = null, $localhost = null, $pipelining = false)
163 if (isset($localhost)) {
164 $this->localhost = $localhost;
166 $this->pipelining = $pipelining;
168 $this->_socket = new Net_Socket();
170 /* Include the Auth_SASL package. If the package is not
171 * available, we disable the authentication methods that
173 if ((@include_once 'Auth/SASL.php') === false) {
174 $pos = array_search('DIGEST-MD5', $this->auth_methods);
175 unset($this->auth_methods[$pos]);
176 $pos = array_search('CRAM-MD5', $this->auth_methods);
177 unset($this->auth_methods[$pos]);
182 * Set the value of the debugging flag.
184 * @param boolean $debug New value for the debugging flag.
189 function setDebug($debug, $handler = null)
191 $this->_debug = $debug;
192 $this->_debug_handler = $handler;
196 * Write the given debug text to the current debug output handler.
198 * @param string $message Debug mesage text.
203 function _debug($message)
206 if ($this->_debug_handler) {
207 call_user_func_array($this->_debug_handler,
208 array(&$this, $message));
210 echo "DEBUG: $message\n";
216 * Send the given string of data to the server.
218 * @param string $data The string of data to send.
220 * @return mixed True on success or a PEAR_Error object on failure.
225 function _send($data)
227 $this->_debug("Send: $data");
229 $error = $this->_socket->write($data);
230 if ($error === false || PEAR::isError($error)) {
231 $msg = ($error) ? $error->getMessage() : "unknown error";
232 return PEAR::raiseError("Failed to write to socket: $msg");
239 * Send a command to the server with an optional string of
240 * arguments. A carriage return / linefeed (CRLF) sequence will
241 * be appended to each command string before it is sent to the
242 * SMTP server - an error will be thrown if the command string
243 * already contains any newline characters. Use _send() for
244 * commands that must contain newlines.
246 * @param string $command The SMTP command to send to the server.
247 * @param string $args A string of optional arguments to append
250 * @return mixed The result of the _send() call.
255 function _put($command, $args = '')
258 $command .= ' ' . $args;
261 if (strcspn($command, "\r\n") !== strlen($command)) {
262 return PEAR::raiseError('Commands cannot contain newlines');
265 return $this->_send($command . "\r\n");
269 * Read a reply from the SMTP server. The reply consists of a response
270 * code and a response message.
272 * @param mixed $valid The set of valid response codes. These
273 * may be specified as an array of integer
274 * values or as a single integer value.
275 * @param bool $later Do not parse the response now, but wait
276 * until the last command in the pipelined
279 * @return mixed True if the server returned a valid response code or
280 * a PEAR_Error object is an error condition is reached.
287 function _parseResponse($valid, $later = false)
290 $this->_arguments = array();
293 $this->_pipelined_commands++;
297 for ($i = 0; $i <= $this->_pipelined_commands; $i++) {
298 while ($line = $this->_socket->readLine()) {
299 $this->_debug("Recv: $line");
301 /* If we receive an empty line, the connection has been closed. */
304 return PEAR::raiseError('Connection was unexpectedly closed');
307 /* Read the code and store the rest in the arguments array. */
308 $code = substr($line, 0, 3);
309 $this->_arguments[] = trim(substr($line, 4));
311 /* Check the syntax of the response code. */
312 if (is_numeric($code)) {
313 $this->_code = (int)$code;
319 /* If this is not a multiline response, we're done. */
320 if (substr($line, 3, 1) != '-') {
326 $this->_pipelined_commands = 0;
328 /* Compare the server's response code with the valid code/codes. */
329 if (is_int($valid) && ($this->_code === $valid)) {
331 } elseif (is_array($valid) && in_array($this->_code, $valid, true)) {
335 return PEAR::raiseError('Invalid response code received from server',
340 * Return a 2-tuple containing the last response from the SMTP server.
342 * @return array A two-element array: the first element contains the
343 * response code as an integer and the second element
344 * contains the response's arguments as a string.
349 function getResponse()
351 return array($this->_code, join("\n", $this->_arguments));
355 * Return the SMTP server's greeting string.
357 * @return string A string containing the greeting string, or null if a
358 * greeting has not been received.
363 function getGreeting()
365 return $this->_greeting;
369 * Attempt to connect to the SMTP server.
371 * @param int $timeout The timeout value (in seconds) for the
373 * @param bool $persistent Should a persistent socket connection
376 * @return mixed Returns a PEAR_Error with an error message on any
377 * kind of failure, or true on success.
381 function connect($timeout = null, $persistent = false)
383 $this->_greeting = null;
384 $result = $this->_socket->connect($this->host, $this->port,
385 $persistent, $timeout);
386 if (PEAR::isError($result)) {
387 return PEAR::raiseError('Failed to connect socket: ' .
388 $result->getMessage());
391 if (PEAR::isError($error = $this->_parseResponse(220))) {
395 /* Extract and store a copy of the server's greeting string. */
396 list(, $this->_greeting) = $this->getResponse();
398 if (PEAR::isError($error = $this->_negotiate())) {
406 * Attempt to disconnect from the SMTP server.
408 * @return mixed Returns a PEAR_Error with an error message on any
409 * kind of failure, or true on success.
413 function disconnect()
415 if (PEAR::isError($error = $this->_put('QUIT'))) {
418 if (PEAR::isError($error = $this->_parseResponse(221))) {
421 if (PEAR::isError($error = $this->_socket->disconnect())) {
422 return PEAR::raiseError('Failed to disconnect socket: ' .
423 $error->getMessage());
430 * Attempt to send the EHLO command and obtain a list of ESMTP
431 * extensions available, and failing that just send HELO.
433 * @return mixed Returns a PEAR_Error with an error message on any
434 * kind of failure, or true on success.
439 function _negotiate()
441 if (PEAR::isError($error = $this->_put('EHLO', $this->localhost))) {
445 if (PEAR::isError($this->_parseResponse(250))) {
446 /* If we receive a 503 response, we're already authenticated. */
447 if ($this->_code === 503) {
451 /* If the EHLO failed, try the simpler HELO command. */
452 if (PEAR::isError($error = $this->_put('HELO', $this->localhost))) {
455 if (PEAR::isError($this->_parseResponse(250))) {
456 return PEAR::raiseError('HELO was not accepted: ', $this->_code);
462 foreach ($this->_arguments as $argument) {
463 $verb = strtok($argument, ' ');
464 $arguments = substr($argument, strlen($verb) + 1,
465 strlen($argument) - strlen($verb) - 1);
466 $this->_esmtp[$verb] = $arguments;
469 if (!isset($this->_esmtp['PIPELINING'])) {
470 $this->pipelining = false;
477 * Returns the name of the best authentication method that the server
480 * @return mixed Returns a string containing the name of the best
481 * supported authentication method or a PEAR_Error object
482 * if a failure condition is encountered.
486 function _getBestAuthMethod()
488 $available_methods = explode(' ', $this->_esmtp['AUTH']);
490 foreach ($this->auth_methods as $method) {
491 if (in_array($method, $available_methods)) {
496 return PEAR::raiseError('No supported authentication methods');
500 * Attempt to do SMTP authentication.
502 * @param string The userid to authenticate as.
503 * @param string The password to authenticate with.
504 * @param string The requested authentication method. If none is
505 * specified, the best supported method will be used.
506 * @param bool Flag indicating whether or not TLS should be attempted.
508 * @return mixed Returns a PEAR_Error with an error message on any
509 * kind of failure, or true on success.
513 function auth($uid, $pwd , $method = '', $tls = true)
515 /* We can only attempt a TLS connection if one has been requested,
516 * we're running PHP 5.1.0 or later, have access to the OpenSSL
517 * extension, are connected to an SMTP server which supports the
518 * STARTTLS extension, and aren't already connected over a secure
519 * (SSL) socket connection. */
520 if ($tls && version_compare(PHP_VERSION, '5.1.0', '>=') &&
521 extension_loaded('openssl') && isset($this->_esmtp['STARTTLS']) &&
522 strncasecmp($this->host, 'ssl://', 6) !== 0) {
523 /* Start the TLS connection attempt. */
524 if (PEAR::isError($result = $this->_put('STARTTLS'))) {
527 if (PEAR::isError($result = $this->_parseResponse(220))) {
530 if (PEAR::isError($result = $this->_socket->enableCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT))) {
532 } elseif ($result !== true) {
533 return PEAR::raiseError('STARTTLS failed');
536 /* Send EHLO again to recieve the AUTH string from the
541 if (empty($this->_esmtp['AUTH'])) {
542 return PEAR::raiseError('SMTP server does not support authentication');
545 /* If no method has been specified, get the name of the best
546 * supported method advertised by the SMTP server. */
547 if (empty($method)) {
548 if (PEAR::isError($method = $this->_getBestAuthMethod())) {
549 /* Return the PEAR_Error object from _getBestAuthMethod(). */
553 $method = strtoupper($method);
554 if (!in_array($method, $this->auth_methods)) {
555 return PEAR::raiseError("$method is not a supported authentication method");
561 $result = $this->_authDigest_MD5($uid, $pwd);
565 $result = $this->_authCRAM_MD5($uid, $pwd);
569 $result = $this->_authLogin($uid, $pwd);
573 $result = $this->_authPlain($uid, $pwd);
577 $result = PEAR::raiseError("$method is not a supported authentication method");
581 /* If an error was encountered, return the PEAR_Error object. */
582 if (PEAR::isError($result)) {
590 * Authenticates the user using the DIGEST-MD5 method.
592 * @param string The userid to authenticate as.
593 * @param string The password to authenticate with.
595 * @return mixed Returns a PEAR_Error with an error message on any
596 * kind of failure, or true on success.
600 function _authDigest_MD5($uid, $pwd)
602 if (PEAR::isError($error = $this->_put('AUTH', 'DIGEST-MD5'))) {
605 /* 334: Continue authentication request */
606 if (PEAR::isError($error = $this->_parseResponse(334))) {
607 /* 503: Error: already authenticated */
608 if ($this->_code === 503) {
614 $challenge = base64_decode($this->_arguments[0]);
615 $digest = &Auth_SASL::factory('digestmd5');
616 $auth_str = base64_encode($digest->getResponse($uid, $pwd, $challenge,
617 $this->host, "smtp"));
619 if (PEAR::isError($error = $this->_put($auth_str))) {
622 /* 334: Continue authentication request */
623 if (PEAR::isError($error = $this->_parseResponse(334))) {
627 /* We don't use the protocol's third step because SMTP doesn't
628 * allow subsequent authentication, so we just silently ignore
630 if (PEAR::isError($error = $this->_put(''))) {
633 /* 235: Authentication successful */
634 if (PEAR::isError($error = $this->_parseResponse(235))) {
640 * Authenticates the user using the CRAM-MD5 method.
642 * @param string The userid to authenticate as.
643 * @param string The password to authenticate with.
645 * @return mixed Returns a PEAR_Error with an error message on any
646 * kind of failure, or true on success.
650 function _authCRAM_MD5($uid, $pwd)
652 if (PEAR::isError($error = $this->_put('AUTH', 'CRAM-MD5'))) {
655 /* 334: Continue authentication request */
656 if (PEAR::isError($error = $this->_parseResponse(334))) {
657 /* 503: Error: already authenticated */
658 if ($this->_code === 503) {
664 $challenge = base64_decode($this->_arguments[0]);
665 $cram = &Auth_SASL::factory('crammd5');
666 $auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge));
668 if (PEAR::isError($error = $this->_put($auth_str))) {
672 /* 235: Authentication successful */
673 if (PEAR::isError($error = $this->_parseResponse(235))) {
679 * Authenticates the user using the LOGIN method.
681 * @param string The userid to authenticate as.
682 * @param string The password to authenticate with.
684 * @return mixed Returns a PEAR_Error with an error message on any
685 * kind of failure, or true on success.
689 function _authLogin($uid, $pwd)
691 if (PEAR::isError($error = $this->_put('AUTH', 'LOGIN'))) {
694 /* 334: Continue authentication request */
695 if (PEAR::isError($error = $this->_parseResponse(334))) {
696 /* 503: Error: already authenticated */
697 if ($this->_code === 503) {
703 if (PEAR::isError($error = $this->_put(base64_encode($uid)))) {
706 /* 334: Continue authentication request */
707 if (PEAR::isError($error = $this->_parseResponse(334))) {
711 if (PEAR::isError($error = $this->_put(base64_encode($pwd)))) {
715 /* 235: Authentication successful */
716 if (PEAR::isError($error = $this->_parseResponse(235))) {
724 * Authenticates the user using the PLAIN method.
726 * @param string The userid to authenticate as.
727 * @param string The password to authenticate with.
729 * @return mixed Returns a PEAR_Error with an error message on any
730 * kind of failure, or true on success.
734 function _authPlain($uid, $pwd)
736 if (PEAR::isError($error = $this->_put('AUTH', 'PLAIN'))) {
739 /* 334: Continue authentication request */
740 if (PEAR::isError($error = $this->_parseResponse(334))) {
741 /* 503: Error: already authenticated */
742 if ($this->_code === 503) {
748 $auth_str = base64_encode(chr(0) . $uid . chr(0) . $pwd);
750 if (PEAR::isError($error = $this->_put($auth_str))) {
754 /* 235: Authentication successful */
755 if (PEAR::isError($error = $this->_parseResponse(235))) {
763 * Send the HELO command.
765 * @param string The domain name to say we are.
767 * @return mixed Returns a PEAR_Error with an error message on any
768 * kind of failure, or true on success.
772 function helo($domain)
774 if (PEAR::isError($error = $this->_put('HELO', $domain))) {
777 if (PEAR::isError($error = $this->_parseResponse(250))) {
785 * Return the list of SMTP service extensions advertised by the server.
787 * @return array The list of SMTP service extensions.
791 function getServiceExtensions()
793 return $this->_esmtp;
797 * Send the MAIL FROM: command.
799 * @param string $sender The sender (reverse path) to set.
800 * @param string $params String containing additional MAIL parameters,
801 * such as the NOTIFY flags defined by RFC 1891
802 * or the VERP protocol.
804 * If $params is an array, only the 'verp' option
805 * is supported. If 'verp' is true, the XVERP
806 * parameter is appended to the MAIL command. If
807 * the 'verp' value is a string, the full
808 * XVERP=value parameter is appended.
810 * @return mixed Returns a PEAR_Error with an error message on any
811 * kind of failure, or true on success.
815 function mailFrom($sender, $params = null)
817 $args = "FROM:<$sender>";
819 /* Support the deprecated array form of $params. */
820 if (is_array($params) && isset($params['verp'])) {
822 if ($params['verp'] === true) {
825 /* XVERP=something */
826 } elseif (trim($params['verp'])) {
827 $args .= ' XVERP=' . $params['verp'];
829 } elseif (is_string($params)) {
830 $args .= ' ' . $params;
833 if (PEAR::isError($error = $this->_put('MAIL', $args))) {
836 if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
844 * Send the RCPT TO: command.
846 * @param string $recipient The recipient (forward path) to add.
847 * @param string $params String containing additional RCPT parameters,
848 * such as the NOTIFY flags defined by RFC 1891.
850 * @return mixed Returns a PEAR_Error with an error message on any
851 * kind of failure, or true on success.
856 function rcptTo($recipient, $params = null)
858 $args = "TO:<$recipient>";
859 if (is_string($params)) {
860 $args .= ' ' . $params;
863 if (PEAR::isError($error = $this->_put('RCPT', $args))) {
866 if (PEAR::isError($error = $this->_parseResponse(array(250, 251), $this->pipelining))) {
874 * Quote the data so that it meets SMTP standards.
876 * This is provided as a separate public function to facilitate
877 * easier overloading for the cases where it is desirable to
878 * customize the quoting behavior.
880 * @param string $data The message text to quote. The string must be passed
881 * by reference, and the text will be modified in place.
886 function quotedata(&$data)
888 /* Change Unix (\n) and Mac (\r) linefeeds into
889 * Internet-standard CRLF (\r\n) linefeeds. */
890 $data = preg_replace(array('/(?<!\r)\n/','/\r(?!\n)/'), "\r\n", $data);
892 /* Because a single leading period (.) signifies an end to the
893 * data, legitimate leading periods need to be "doubled"
895 $data = str_replace("\n.", "\n..", $data);
899 * Send the DATA command.
901 * @param mixed $data The message data, either as a string or an open
903 * @param string $headers The message headers. If $headers is provided,
904 * $data is assumed to contain only body data.
906 * @return mixed Returns a PEAR_Error with an error message on any
907 * kind of failure, or true on success.
911 function data($data, $headers = null)
913 /* Verify that $data is a supported type. */
914 if (!is_string($data) && !is_resource($data)) {
915 return PEAR::raiseError('Expected a string or file resource');
918 /* RFC 1870, section 3, subsection 3 states "a value of zero
919 * indicates that no fixed maximum message size is in force".
920 * Furthermore, it says that if "the parameter is omitted no
921 * information is conveyed about the server's fixed maximum
923 if (isset($this->_esmtp['SIZE']) && ($this->_esmtp['SIZE'] > 0)) {
924 /* Start by considering the size of the optional headers string.
925 * We also account for the addition 4 character "\r\n\r\n"
926 * separator sequence. */
927 $size = (is_null($headers)) ? 0 : strlen($headers) + 4;
929 if (is_resource($data)) {
930 $stat = fstat($data);
931 if ($stat === false) {
932 return PEAR::raiseError('Failed to get file size');
934 $size += $stat['size'];
936 $size += strlen($data);
939 if ($size >= $this->_esmtp['SIZE']) {
941 return PEAR::raiseError('Message size exceeds server limit');
945 /* Initiate the DATA command. */
946 if (PEAR::isError($error = $this->_put('DATA'))) {
949 if (PEAR::isError($error = $this->_parseResponse(354))) {
953 /* If we have a separate headers string, send it first. */
954 if (!is_null($headers)) {
955 $this->quotedata($headers);
956 if (PEAR::isError($result = $this->_send($headers . "\r\n\r\n"))) {
961 /* Now we can send the message body data. */
962 if (is_resource($data)) {
963 /* Stream the contents of the file resource out over our socket
964 * connection, line by line. Each line must be run through the
965 * quoting routine. */
966 while ($line = fgets($data, 1024)) {
967 $this->quotedata($line);
968 if (PEAR::isError($result = $this->_send($line))) {
973 /* Finally, send the DATA terminator sequence. */
974 if (PEAR::isError($result = $this->_send("\r\n.\r\n"))) {
978 /* Just send the entire quoted string followed by the DATA
980 $this->quotedata($data);
981 if (PEAR::isError($result = $this->_send($data . "\r\n.\r\n"))) {
986 /* Verify that the data was successfully received by the server. */
987 if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
995 * Send the SEND FROM: command.
997 * @param string The reverse path to send.
999 * @return mixed Returns a PEAR_Error with an error message on any
1000 * kind of failure, or true on success.
1004 function sendFrom($path)
1006 if (PEAR::isError($error = $this->_put('SEND', "FROM:<$path>"))) {
1009 if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
1017 * Backwards-compatibility wrapper for sendFrom().
1019 * @param string The reverse path to send.
1021 * @return mixed Returns a PEAR_Error with an error message on any
1022 * kind of failure, or true on success.
1028 function send_from($path)
1030 return sendFrom($path);
1034 * Send the SOML FROM: command.
1036 * @param string The reverse path to send.
1038 * @return mixed Returns a PEAR_Error with an error message on any
1039 * kind of failure, or true on success.
1043 function somlFrom($path)
1045 if (PEAR::isError($error = $this->_put('SOML', "FROM:<$path>"))) {
1048 if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
1056 * Backwards-compatibility wrapper for somlFrom().
1058 * @param string The reverse path to send.
1060 * @return mixed Returns a PEAR_Error with an error message on any
1061 * kind of failure, or true on success.
1067 function soml_from($path)
1069 return somlFrom($path);
1073 * Send the SAML FROM: command.
1075 * @param string The reverse path to send.
1077 * @return mixed Returns a PEAR_Error with an error message on any
1078 * kind of failure, or true on success.
1082 function samlFrom($path)
1084 if (PEAR::isError($error = $this->_put('SAML', "FROM:<$path>"))) {
1087 if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
1095 * Backwards-compatibility wrapper for samlFrom().
1097 * @param string The reverse path to send.
1099 * @return mixed Returns a PEAR_Error with an error message on any
1100 * kind of failure, or true on success.
1106 function saml_from($path)
1108 return samlFrom($path);
1112 * Send the RSET command.
1114 * @return mixed Returns a PEAR_Error with an error message on any
1115 * kind of failure, or true on success.
1121 if (PEAR::isError($error = $this->_put('RSET'))) {
1124 if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) {
1132 * Send the VRFY command.
1134 * @param string The string to verify
1136 * @return mixed Returns a PEAR_Error with an error message on any
1137 * kind of failure, or true on success.
1141 function vrfy($string)
1143 /* Note: 251 is also a valid response code */
1144 if (PEAR::isError($error = $this->_put('VRFY', $string))) {
1147 if (PEAR::isError($error = $this->_parseResponse(array(250, 252)))) {
1155 * Send the NOOP command.
1157 * @return mixed Returns a PEAR_Error with an error message on any
1158 * kind of failure, or true on success.
1164 if (PEAR::isError($error = $this->_put('NOOP'))) {
1167 if (PEAR::isError($error = $this->_parseResponse(250))) {
1175 * Backwards-compatibility method. identifySender()'s functionality is
1176 * now handled internally.
1178 * @return boolean This method always return true.
1183 function identifySender()