Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 67 additions & 27 deletions system/Email/Email.php
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ class Email
*/
protected $SMTPAuth = false;

/**
* Which SMTP AUTH method to use ('LOGIN', 'PLAIN')
*
* @var string
*/
protected $SMTPAuthMethod = 'LOGIN';

/**
* Whether to send a Reply-To header
*
Expand Down Expand Up @@ -1920,9 +1927,9 @@ protected function SMTPConnect()
$this->SMTPConnect,
true,
STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT
| STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
| STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
| STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT,
| STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
| STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
| STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT,
);

if ($crypto !== true) {
Expand Down Expand Up @@ -2015,54 +2022,87 @@ protected function sendCommand($cmd, $data = '')
*/
protected function SMTPAuthenticate()
{
if (! $this->SMTPAuth) {
if (!$this->SMTPAuth) {
return true;
}

if ($this->SMTPUser === '' && $this->SMTPPass === '') {
// If no username or password is set
if ($this->SMTPUser === '' || $this->SMTPPass === '') {
$this->setErrorMessage(lang('Email.noSMTPAuth'));

return false;
}

$this->sendData('AUTH LOGIN');
$reply = $this->getSMTPData();
switch ($this->SMTPAuthMethod) {
case 'LOGIN':
$this->sendData('AUTH LOGIN'); // Start authentication
if (!$this->checkSMTPAuthResponse($this->getSMTPData())) {
return false;
}

if (str_starts_with($reply, '503')) { // Already authenticated
return true;
}
// Send encoded username
$this->sendData(base64_encode($this->SMTPUser));
if (!$this->checkSMTPAuthResponse($this->getSMTPData())) {
return false;
}

if (! str_starts_with($reply, '334')) {
$this->setErrorMessage(lang('Email.failedSMTPLogin', [$reply]));
// Send encoded password
$this->sendData(base64_encode($this->SMTPPass));
$reply = $this->getSMTPData();

return false;
}
// Authentication success (235 expected)
if (!str_starts_with($reply, '235')) {
$this->setErrorMessage(lang('Email.SMTPAuthPassword', [$reply]));
return false;
}
break;
case 'PLAIN':
// Generate single command for PLAIN authentication
$authString = "\0" . $this->SMTPUser . "\0" . $this->SMTPPass;

$this->sendData(base64_encode($this->SMTPUser));
$reply = $this->getSMTPData();
$this->sendData('AUTH PLAIN ' . base64_encode($authString));

if (! str_starts_with($reply, '334')) {
$this->setErrorMessage(lang('Email.SMTPAuthUsername', [$reply]));
if (!$this->checkSMTPAuthResponse($this->getSMTPData())) {
return false;
}

return false;
break;
default:
$this->setErrorMessage(lang('Email.noSMTPAuthMethod'));
return false;
break;
}

$this->sendData(base64_encode($this->SMTPPass));
$reply = $this->getSMTPData();
if ($this->SMTPKeepAlive) {
$this->SMTPAuth = false; // Prevent re-authentication for keep-alive sessions
}

if (! str_starts_with($reply, '235')) {
$this->setErrorMessage(lang('Email.SMTPAuthPassword', [$reply]));
return true;
}


private function checkSMTPAuthResponse($replyData)
{
// 503 already authenticated || 235 authentication success ('AUTH PLAIN')
if (str_starts_with($replyData, '503') || str_starts_with($replyData, '235')) {
return true;
}

if (str_starts_with($replyData, '535')) { // Authentication failed (bad credentials)
$this->setErrorMessage(lang('Email.failedSMTPLogin', [$replyData]));
return false;
}

if ($this->SMTPKeepAlive) {
$this->SMTPAuth = false;
if (str_starts_with($replyData, '334')) { // Server requesting username or password
return true;
}

return true;
// Unexpected response
$this->setErrorMessage(lang('Email.SMTPUnexpectedResponse', [$replyData]));
return false;
}



/**
* @param string $data
*
Expand Down
3 changes: 2 additions & 1 deletion user_guide_src/source/libraries/email.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Here is a basic example demonstrating how you might send email:
Setting Email Preferences
=========================

There are 21 different preferences available to tailor how your email
There are 22 different preferences available to tailor how your email
messages are sent. You can either set them manually as described here,
or automatically via preferences stored in your config file, described
in `Email Preferences`_.
Expand Down Expand Up @@ -120,6 +120,7 @@ Preference Default Value Options Description
or ``smtp``
**mailPath** /usr/sbin/sendmail The server path to Sendmail.
**SMTPHost** SMTP Server Hostname.
**SMTPAuthMethod** LOGIN ``LOGIN``, ``PLAIN`` SMTP Authentication Method.
**SMTPUser** SMTP Username.
**SMTPPass** SMTP Password.
**SMTPPort** 25 SMTP Port. (If set to ``465``, TLS will be used for the connection
Expand Down