Skip to content

Commit

Permalink
Make SMTP error storage and reporting more consistent, fixes PHPMaile…
Browse files Browse the repository at this point in the history
  • Loading branch information
Synchro committed Mar 19, 2015
1 parent 795c904 commit 3ea8425
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 33 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* Add Slovenian translation (Thanks to Klemen Tušar)
* More efficient word wrapping
* Add support for S/MIME signing with additional CA certificate (thanks to @IgitBuh)
* Store and report SMTP errors more consistently

## Version 5.2.9 (Sept 25th 2014)
* **Important: The autoloader is no longer autoloaded by the PHPMailer class**
Expand Down
13 changes: 11 additions & 2 deletions class.phpmailer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2820,8 +2820,17 @@ protected function setError($msg)
$this->error_count++;
if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
$lasterror = $this->smtp->getError();
if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
$msg .= '<p>' . $this->lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n";
if (!empty($lasterror['error'])) {
$msg .= $this->lang('smtp_error') . $lasterror['error'];
if (!empty($lasterror['detail'])) {
$msg .= ' Detail: '. $lasterror['detail'];
}
if (!empty($lasterror['smtp_code'])) {
$msg .= ' SMTP code: ' . $lasterror['smtp_code'];
}
if (!empty($lasterror['smtp_code_ex'])) {
$msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
}
}
}
$this->ErrorInfo = $msg;
Expand Down
79 changes: 48 additions & 31 deletions class.smtp.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,15 @@ class SMTP
protected $smtp_conn;

/**
* Error message, if any, for the last call.
* Error information, if any, for the last SMTP command.
* @type array
*/
protected $error = array();
protected $error = array(
'error' => '',
'detail' => '',
'smtp_code' => '',
'smtp_code_ex' => ''
);

/**
* The reply the server sent to us for HELO.
Expand Down Expand Up @@ -248,11 +253,11 @@ public function connect($host, $port = null, $timeout = 30, $options = array())
$streamok = function_exists('stream_socket_client');
}
// Clear errors to avoid confusion
$this->error = array();
$this->setError('');
// Make sure we are __not__ connected
if ($this->connected()) {
// Already connected, generate error
$this->error = array('error' => 'Already connected to a server');
$this->setError('Already connected to a server');
return false;
}
if (empty($port)) {
Expand Down Expand Up @@ -292,10 +297,10 @@ public function connect($host, $port = null, $timeout = 30, $options = array())
}
// Verify we connected properly
if (!is_resource($this->smtp_conn)) {
$this->error = array(
'error' => 'Failed to connect to server',
'errno' => $errno,
'errstr' => $errstr
$this->setError(
'Failed to connect to server',
$errno,
$errstr
);
$this->edebug(
'SMTP ERROR: ' . $this->error['error']
Expand Down Expand Up @@ -362,15 +367,15 @@ public function authenticate(
$workstation = ''
) {
if (!$this->server_caps) {
$this->error = array('error' => 'Authentication is not allowed before HELO/EHLO');
$this->setError('Authentication is not allowed before HELO/EHLO');
return false;
}

if (array_key_exists('EHLO', $this->server_caps)) {
// SMTP extensions are available. Let's try to find a proper authentication method

if (!array_key_exists('AUTH', $this->server_caps)) {
$this->error = array( 'error' => 'Authentication is not allowed at this stage' );
$this->setError('Authentication is not allowed at this stage');
// 'at this stage' means that auth may be allowed after the stage changes
// e.g. after STARTTLS
return false;
Expand All @@ -390,15 +395,14 @@ public function authenticate(
}
}
if (empty($authtype)) {
$this->error = array( 'error' => 'No supported authentication methods found' );
$this->setError('No supported authentication methods found');
return false;
}
self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL);
}

if (!in_array($authtype, $this->server_caps['AUTH'])) {
$this->error = array( 'error' => 'The requested authentication method "'
. $authtype . '" is not supported by the server' );
$this->setError("The requested authentication method \"$authtype\" is not supported by the server");
return false;
}
} elseif (empty($authtype)) {
Expand Down Expand Up @@ -442,11 +446,11 @@ public function authenticate(
* PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
*/
require_once 'extras/ntlm_sasl_client.php';
$temp = new stdClass();
$temp = new stdClass;
$ntlm_client = new ntlm_sasl_client_class;
//Check that functions are available
if (!$ntlm_client->Initialize($temp)) {
$this->error = array('error' => $temp->error);
$this->setError($temp->error);
$this->edebug(
'You need to enable some modules in your php.ini file: '
. $this->error['error'],
Expand Down Expand Up @@ -496,7 +500,7 @@ public function authenticate(
// send encoded credentials
return $this->sendCommand('Username', base64_encode($response), 235);
default:
$this->error = array( 'error' => 'Authentication method "' . $authtype . '" is not supported' );
$this->setError("Authentication method \"$authtype\" is not supported");
return false;
}
return true;
Expand Down Expand Up @@ -570,7 +574,7 @@ public function connected()
*/
public function close()
{
$this->error = array();
$this->setError('');
$this->server_caps = null;
$this->helo_rply = null;
if (is_resource($this->smtp_conn)) {
Expand Down Expand Up @@ -821,9 +825,7 @@ public function reset()
protected function sendCommand($command, $commandstring, $expect)
{
if (!$this->connected()) {
$this->error = array(
'error' => "Called $command without being connected"
);
$this->setError("Called $command without being connected");
return false;
}
$this->client_send($commandstring . self::CRLF);
Expand All @@ -850,11 +852,11 @@ protected function sendCommand($command, $commandstring, $expect)
$this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);

if (!in_array($code, (array)$expect)) {
$this->error = array(
'error' => "$command command failed",
'smtp_code' => $code,
'smtp_code_ex' => $code_ex,
'detail' => $detail
$this->setError(
"$command command failed",
$detail,
$code,
$code_ex
);
$this->edebug(
'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply,
Expand All @@ -863,7 +865,7 @@ protected function sendCommand($command, $commandstring, $expect)
return false;
}

$this->error = array();
$this->setError('');
return true;
}

Expand Down Expand Up @@ -918,9 +920,7 @@ public function noop()
*/
public function turn()
{
$this->error = array(
'error' => 'The SMTP TURN command is not implemented'
);
$this->setError('The SMTP TURN command is not implemented');
$this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT);
return false;
}
Expand Down Expand Up @@ -979,7 +979,7 @@ public function getServerExtList()
public function getServerExt($name)
{
if (!$this->server_caps) {
$this->error = array('No HELO/EHLO was sent');
$this->setError('No HELO/EHLO was sent');
return null;
}

Expand All @@ -991,7 +991,7 @@ public function getServerExt($name)
if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) {
return false;
}
$this->error = array('HELO handshake was used. Client knows nothing about server extensions');
$this->setError('HELO handshake was used. Client knows nothing about server extensions');
return null;
}

Expand Down Expand Up @@ -1079,6 +1079,23 @@ public function getVerp()
return $this->do_verp;
}

/**
* Set error messages and codes.
* @param string $message The error message
* @param string $detail Further detail on the error
* @param string $smtp_code An associated SMTP error code
* @param string $smtp_code_ex Extended SMTP code
*/
protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '')
{
$this->error = array(
'error' => $message,
'detail' => $detail,
'smtp_code' => $smtp_code,
'smtp_code_ex' => $smtp_code_ex
);
}

/**
* Set debug output method.
* @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it.
Expand Down

0 comments on commit 3ea8425

Please sign in to comment.