Source for file smtp.php
Documentation is available at smtp.php
.---------------------------------------------------------------------------.
| Software: PHPMailer - PHP email class |
| Site: https://github.com/PHPMailer/PHPMailer/ |
| ------------------------------------------------------------------------- |
| Admins: Marcus Bointon |
| Admins: Jim Jagielski |
| Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
| : Marcus Bointon (coolbru) phpmailer@synchromedia.co.uk |
| : Jim Jagielski (jimjag) jimjag@gmail.com |
| Founder: Brent R. Matzelle (original founder) |
| Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. |
| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
| Copyright (c) 2001-2003, Brent R. Matzelle |
| ------------------------------------------------------------------------- |
| License: Distributed under the Lesser General Public License (LGPL) |
| http://www.gnu.org/copyleft/lesser.html |
| This program is distributed in the hope that it will be useful - WITHOUT |
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. |
'---------------------------------------------------------------------------'
* PHPMailer - PHP SMTP email transport class
* NOTE: Designed for use with PHP version 5 and up
* @copyright 2004 - 2008 Andy Prevost
* @copyright 2010 - 2012 Jim Jagielski
* @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
* Implements all the RFC 821 SMTP commands except TURN which will always return a not implemented error.
* SMTP also provides some utility methods for sending mail to an SMTP server.
* SMTP reply line ending (don't change)
* Debug output level; 0 for no output
* Sets the function/method to use for debugging output.
* Right now we only honor 'echo', 'html' or 'error_log'
* Sets VERP use on/off (default is off)
* Sets the SMTP timeout value for reads, in seconds
* Sets the SMTP timelimit value for reads, in seconds
* Sets the SMTP PHPMailer Version number
/////////////////////////////////////////////////
// PROPERTIES, PRIVATE AND PROTECTED
/////////////////////////////////////////////////
* @var resource The socket to the server
* @var string Error message, if any, for the last call
* @var string The reply the server sent to us for HELO
* Outputs debugging info via user-defined method
protected function edebug($str) {
//Cleans up output a bit for a better looking display that's HTML-safe
//Just echoes exactly what was received
* Initialize the class so that the data is in a known state.
/////////////////////////////////////////////////
/////////////////////////////////////////////////
* Connect to an SMTP server
* @param string $host SMTP server IP or host name
* @param int $port The port number to connect to, or use the default port if not specified
* @param int $timeout How long to wait for the connection to open
* @param array $options An array of options compatible with stream_context_create()
public function Connect($host, $port =
0, $timeout =
30, $options =
array()) {
// Clear errors to avoid confusion
// Make sure we are __not__ connected
// Already connected, generate error
$this->error =
array('error' =>
'Already connected to a server');
// Connect to the SMTP server
//Need to suppress errors here as connection failures can be handled at a higher level
// Verify we connected properly
$this->error =
array('error' =>
'Failed to connect to server',
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
": $errstr ($errno)");
// SMTP server can take longer to respond, give longer timeout for first read
// Windows does not have support for this timeout function
if(substr(PHP_OS, 0, 3) !=
'WIN') {
$max =
ini_get('max_execution_time');
if ($max !=
0 &&
$timeout >
$max) { // Don't bother if unlimited
$this->edebug('SMTP -> FROM SERVER:' .
$announce);
* Initiate a TLS communication with the server.
* SMTP CODE 220 Ready to start TLS
* SMTP CODE 501 Syntax error (no parameters allowed)
* SMTP CODE 454 TLS not available due to temporary reason
$this->error =
null; # to avoid confusion
if(!$this->connected()) {
$this->error =
array('error' =>
'Called StartTLS() without being connected');
$this->edebug('SMTP -> FROM SERVER:' .
$rply);
array('error' =>
'STARTTLS not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
// Begin encrypted connection
* Performs SMTP authentication. Must be run after running the
* Hello() method. Returns true if successfully authenticated.
* @param string $username
* @param string $password
* @param string $authtype
* @param string $workstation
public function Authenticate($username, $password, $authtype=
'LOGIN', $realm=
'', $workstation=
'') {
array('error' =>
'AUTH not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
// Send encoded username and password
array('error' =>
'Authentication not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
array('error' =>
'AUTH not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
array('error' =>
'Username not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
array('error' =>
'Password not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
** Bundled with Permission
** How to telnet in windows: http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
** PROTOCOL Documentation http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
require_once 'extras/ntlm_sasl_client.php';
$ntlm_client =
new ntlm_sasl_client_class;
if(! $ntlm_client->Initialize($temp)){//let's test if every function its available
$this->error =
array('error' =>
$temp->error);
$this->edebug('You need to enable some modules in your php.ini file: ' .
$this->error['error']);
$msg1 =
$ntlm_client->TypeMsg1($realm, $workstation);//msg1
array('error' =>
'AUTH not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
$challenge =
substr($rply, 3);//though 0 based, there is a white space after the 3 digit number....//msg2
$ntlm_res =
$ntlm_client->NTLMResponse(substr($challenge, 24, 8), $password);
$msg3 =
$ntlm_client->TypeMsg3($ntlm_res, $username, $realm, $workstation);//msg3
array('error' =>
'Could not authenticate',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
array('error' =>
'AUTH not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
$response =
$username .
' ' .
$this->hmac($challenge, $password);
// Send encoded credentials
array('error' =>
'Credentials not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
* Works like hash_hmac('md5', $data, $key) in case that function is not available
protected function hmac($data, $key) {
// The following borrowed from http://php.net/manual/en/function.mhash.php#27225
// RFC 2104 HMAC implementation for php.
// Eliminates the need to install mhash to compute a HMAC
// Hacked by Lance Rushing
$b =
64; // byte length for md5
return md5($k_opad .
pack('H*', md5($k_ipad .
$data)));
* Returns true if connected to a server otherwise false
if($sock_status['eof']) {
// the socket is valid but we are not connected
$this->edebug('SMTP -> NOTICE: EOF caught while checking if connected');
return true; // everything looks good
* Closes the socket and cleans up the state of the class.
* It is not considered good to use this function without
* first trying to use QUIT.
public function Close() {
$this->error =
null; // so there is no confusion
// close the connection and cleanup
/////////////////////////////////////////////////
/////////////////////////////////////////////////
* Issues a data command and sends the msg_data to the server
* finializing the mail transaction. $msg_data is the message
* that is to be send with the headers. Each header needs to be
* on a single line followed by a <CRLF> with the message headers
* and the message body being separated by and additional <CRLF>.
* Implements rfc 821: DATA <CRLF>
* SMTP CODE INTERMEDIATE: 354
* SMTP CODE FAILURE: 552, 554, 451, 452
* SMTP CODE FAILURE: 451, 554
* SMTP CODE ERROR : 500, 501, 503, 421
* @param string $msg_data
public function Data($msg_data) {
$this->error =
null; // so no confusion is caused
if(!$this->connected()) {
'error' =>
'Called Data() without being connected');
$this->edebug('SMTP -> FROM SERVER:' .
$rply);
array('error' =>
'DATA command not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
/* the server is ready to accept data!
* according to rfc 821 we should not send more than 1000
* characters on a single line so we will break the data up
* into lines by \r and/or \n then if needed we will break
* each of those into smaller lines to fit within the limit.
* in addition we will be looking for lines that start with
* a period '.' and append and additional period '.' to that
* line. NOTE: this does not count towards limit.
// normalize the line breaks so we know the explode works
/* we need to find a good way to determine is headers are
* in the msg_data or if it is a straight msg body
* currently I am assuming rfc 822 definitions of msg headers
* and if the first field of the first line (':' sperated)
* does not contain a space then it _should_ be a header
* and we can process all lines before a blank "" line as
if(!empty($field) &&
!strstr($field, ' ')) {
$max_line_length =
998; // used below; set here for ease in change
while(list
(, $line) =
@each($lines)) {
if($line ==
'' &&
$in_headers) {
// ok we need to break this line up into several smaller lines
while(strlen($line) >
$max_line_length) {
// Patch to fix DOS attack
$pos =
$max_line_length -
1;
$lines_out[] =
substr($line, 0, $pos);
$lines_out[] =
substr($line, 0, $pos);
$line =
substr($line, $pos +
1);
/* if processing headers add a LWSP-char to the front of new line
* rfc 822 on long msg headers
// send the lines to the server
while(list
(, $line_out) =
@each($lines_out)) {
if(substr($line_out, 0, 1) ==
'.') {
$line_out =
'.' .
$line_out;
// message data has been sent
$this->edebug('SMTP -> FROM SERVER:' .
$rply);
array('error' =>
'DATA not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
* Sends the HELO command to the smtp server.
* This makes sure that we and the server are in
* Implements from rfc 821: HELO <SP> <domain> <CRLF>
* SMTP CODE ERROR : 500, 501, 504, 421
public function Hello($host =
'') {
$this->error =
null; // so no confusion is caused
if(!$this->connected()) {
'error' =>
'Called Hello() without being connected');
// if hostname for HELO was not specified send default
// determine appropriate default to send to server
// Send extended hello first (RFC 2821)
* Sends a HELO/EHLO command.
protected function SendHello($hello, $host) {
$this->edebug('SMTP -> FROM SERVER: ' .
$rply);
array('error' =>
$hello .
' not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
* Starts a mail transaction from the email address specified in
* $from. Returns true if successful or false otherwise. If True
* the mail transaction is started and then one or more Recipient
* commands may be called followed by a Data command.
* Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
* SMTP CODE SUCCESS: 552, 451, 452
* SMTP CODE SUCCESS: 500, 501, 421
public function Mail($from) {
$this->error =
null; // so no confusion is caused
if(!$this->connected()) {
'error' =>
'Called Mail() without being connected');
$useVerp =
($this->do_verp ?
' XVERP' :
'');
$this->edebug('SMTP -> FROM SERVER:' .
$rply);
array('error' =>
'MAIL not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
* Sends the quit command to the server and then closes the socket
* if there is no error or the $close_on_error argument is true.
* Implements from rfc 821: QUIT <CRLF>
* @param bool $close_on_error
public function Quit($close_on_error =
true) {
$this->error =
null; // so there is no confusion
if(!$this->connected()) {
'error' =>
'Called Quit() without being connected');
// send the quit command to the server
// get any good-bye messages
$this->edebug('SMTP -> FROM SERVER:' .
$byemsg);
$code =
substr($byemsg, 0, 3);
// use e as a tmp var cause Close will overwrite $this->error
$e =
array('error' =>
'SMTP server rejected quit command',
'smtp_rply' =>
substr($byemsg, 4));
$this->edebug('SMTP -> ERROR: ' .
$e['error'] .
': ' .
$byemsg);
if(empty($e) ||
$close_on_error) {
* Sends the command RCPT to the SMTP server with the TO: argument of $to.
* Returns true if the recipient was accepted false if it was rejected.
* Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
* SMTP CODE SUCCESS: 250, 251
* SMTP CODE FAILURE: 550, 551, 552, 553, 450, 451, 452
* SMTP CODE ERROR : 500, 501, 503, 421
$this->error =
null; // so no confusion is caused
if(!$this->connected()) {
'error' =>
'Called Recipient() without being connected');
$this->edebug('SMTP -> FROM SERVER:' .
$rply);
if($code !=
250 &&
$code !=
251) {
array('error' =>
'RCPT not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
* Sends the RSET command to abort and transaction that is
* currently in progress. Returns true if successful false
* Implements rfc 821: RSET <CRLF>
* SMTP CODE ERROR : 500, 501, 504, 421
public function Reset() {
$this->error =
null; // so no confusion is caused
if(!$this->connected()) {
$this->error =
array('error' =>
'Called Reset() without being connected');
$this->edebug('SMTP -> FROM SERVER:' .
$rply);
array('error' =>
'RSET failed',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
* Starts a mail transaction from the email address specified in
* $from. Returns true if successful or false otherwise. If True
* the mail transaction is started and then one or more Recipient
* commands may be called followed by a Data command. This command
* will send the message to the users terminal if they are logged
* in and send them an email.
* Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
* SMTP CODE SUCCESS: 552, 451, 452
* SMTP CODE SUCCESS: 500, 501, 502, 421
$this->error =
null; // so no confusion is caused
if(!$this->connected()) {
'error' =>
'Called SendAndMail() without being connected');
$this->edebug('SMTP -> FROM SERVER:' .
$rply);
array('error' =>
'SAML not accepted from server',
'smtp_msg' =>
substr($rply, 4));
$this->edebug('SMTP -> ERROR: ' .
$this->error['error'] .
': ' .
$rply);
* This is an optional command for SMTP that this class does not
* support. This method is here to make the RFC821 Definition
* complete for this class and __may__ be implimented in the future
* Implements from rfc 821: TURN <CRLF>
* SMTP CODE ERROR : 500, 503
$this->error =
array('error' =>
'This method, TURN, of the SMTP '.
$this->edebug('SMTP -> NOTICE: ' .
$this->error['error']);
* Sends data to the server
* @return Integer number of bytes sent to the server or FALSE on error
$this->edebug("CLIENT -> SMTP: $data");
/////////////////////////////////////////////////
/////////////////////////////////////////////////
* Read in as many lines as possible
* either before eof or socket timeout occurs on the operation.
* With SMTP we can tell if we have more lines to read if the
* 4th character is '-' symbol. If it is a space then we don't
* need to read anything else.
/* If for some reason the fp is bad, don't inf loop */
$this->edebug("SMTP -> get_lines(): \$data was \"$data\"");
$this->edebug("SMTP -> get_lines(): \$str is \"$str\"");
$this->edebug("SMTP -> get_lines(): \$data is \"$data\"");
// if 4th character is a space, we are done reading, break the loop
if(substr($str, 3, 1) ==
' ') { break; }
// Timed-out? Log and break
if ($info['timed_out']) {
$this->edebug('SMTP -> get_lines(): timed-out (' .
$this->Timeout .
' seconds)');
// Now check if reads took too long
$this->edebug('SMTP -> get_lines(): timelimit reached (' .
$this->Timelimit .
' seconds)');
Documentation generated on Tue, 19 Nov 2013 15:13:59 +0100 by phpDocumentor 1.4.3