External Libraries: Upgrade PHPMailer to version 6.3.0.

This is a maintenance release. Changes include:

* Handle early connection errors such as 421 during connection and EHLO states.
* Make the `mail()` and sendmail transports set the envelope sender the same way as SMTP does, i.e. use whatever `From` is set to, only falling back to the `sendmail_from` php.ini setting if `From` is unset. This avoids errors from the `mail()` function if `Sender` is not set explicitly and php.ini is not configured. This is a minor functionality change, so bumps the minor version number.
* Extend `parseAddresses` to decode encoded names.

Release notes: https://github.com/PHPMailer/PHPMailer/releases/tag/v6.3.0

For a full list of changes in this update, see the PHPMailer GitHub:
https://github.com/PHPMailer/PHPMailer/compare/v6.2.0...v6.3.0

Props ayeshrajans.
Fixes #52577.
Built from https://develop.svn.wordpress.org/trunk@50397


git-svn-id: http://core.svn.wordpress.org/trunk@50008 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Sergey Biryukov 2021-02-21 09:34:05 +00:00
parent eac91ec9c5
commit 0d8da2d665
3 changed files with 287 additions and 213 deletions

View File

@ -748,7 +748,7 @@ class PHPMailer
*
* @var string
*/
const VERSION = '6.2.0';
const VERSION = '6.3.0';
/**
* Error severity: message only, continue processing.
@ -862,18 +862,25 @@ class PHPMailer
$subject = $this->encodeHeader($this->secureHeader($subject));
}
//Calling mail() with null params breaks
$this->edebug('Sending with mail()');
$this->edebug('Sendmail path: ' . ini_get('sendmail_path'));
$this->edebug("Envelope sender: {$this->Sender}");
$this->edebug("To: {$to}");
$this->edebug("Subject: {$subject}");
$this->edebug("Headers: {$header}");
if (!$this->UseSendmailOptions || null === $params) {
$result = @mail($to, $subject, $body, $header);
} else {
$this->edebug("Additional params: {$params}");
$result = @mail($to, $subject, $body, $header, $params);
}
$this->edebug('Result: ' . ($result ? 'true' : 'false'));
return $result;
}
/**
* Output debugging info via user-defined method.
* Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
* Output debugging info via a user-defined method.
* Only generates output if debug output is enabled.
*
* @see PHPMailer::$Debugoutput
* @see PHPMailer::$SMTPDebug
@ -1191,6 +1198,11 @@ class PHPMailer
$address->mailbox . '@' . $address->host
)
) {
//Decode the name part if it's present and encoded
if (property_exists($address, 'personal') && preg_match('/^=\?.*\?=$/', $address->personal)) {
$address->personal = mb_decode_mimeheader($address->personal);
}
$addresses[] = [
'name' => (property_exists($address, 'personal') ? $address->personal : ''),
'address' => $address->mailbox . '@' . $address->host,
@ -1214,9 +1226,15 @@ class PHPMailer
} else {
list($name, $email) = explode('<', $address);
$email = trim(str_replace('>', '', $email));
$name = trim($name);
if (static::validateAddress($email)) {
//If this name is encoded, decode it
if (preg_match('/^=\?.*\?=$/', $name)) {
$name = mb_decode_mimeheader($name);
}
$addresses[] = [
'name' => trim(str_replace(['"', "'"], '', $name)),
//Remove any surrounding quotes and spaces from the name
'name' => trim($name, '\'" '),
'address' => $email,
];
}
@ -1405,15 +1423,19 @@ class PHPMailer
$domain = substr($address, ++$pos);
//Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
if ($this->has8bitChars($domain) && @mb_check_encoding($domain, $this->CharSet)) {
$domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
//Convert the domain from whatever charset it's in to UTF-8
$domain = mb_convert_encoding($domain, self::CHARSET_UTF8, $this->CharSet);
//Ignore IDE complaints about this line - method signature changed in PHP 5.4
$errorcode = 0;
if (defined('INTL_IDNA_VARIANT_UTS46')) {
$punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_UTS46);
//Use the current punycode standard (appeared in PHP 7.2)
$punycode = idn_to_ascii($domain, $errorcode, \INTL_IDNA_VARIANT_UTS46);
} elseif (defined('INTL_IDNA_VARIANT_2003')) {
//Fall back to this old, deprecated/removed encoding
// phpcs:ignore PHPCompatibility.Constants.RemovedConstants.intl_idna_variant_2003Deprecated
$punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_2003);
$punycode = idn_to_ascii($domain, $errorcode, \INTL_IDNA_VARIANT_2003);
} else {
//Fall back to a default we don't know about
// phpcs:ignore PHPCompatibility.ParameterValues.NewIDNVariantDefault.NotSet
$punycode = idn_to_ascii($domain, $errorcode);
}
@ -1464,7 +1486,7 @@ class PHPMailer
{
if (
'smtp' === $this->Mailer
|| ('mail' === $this->Mailer && (PHP_VERSION_ID >= 80000 || stripos(PHP_OS, 'WIN') === 0))
|| ('mail' === $this->Mailer && (\PHP_VERSION_ID >= 80000 || stripos(PHP_OS, 'WIN') === 0))
) {
//SMTP mandates RFC-compliant line endings
//and it's also used with mail() on Windows
@ -1476,8 +1498,8 @@ class PHPMailer
//Check for buggy PHP versions that add a header with an incorrect line break
if (
'mail' === $this->Mailer
&& ((PHP_VERSION_ID >= 70000 && PHP_VERSION_ID < 70017)
|| (PHP_VERSION_ID >= 70100 && PHP_VERSION_ID < 70103))
&& ((\PHP_VERSION_ID >= 70000 && \PHP_VERSION_ID < 70017)
|| (\PHP_VERSION_ID >= 70100 && \PHP_VERSION_ID < 70103))
&& ini_get('mail.add_x_header') === '1'
&& stripos(PHP_OS, 'WIN') === 0
) {
@ -1647,22 +1669,45 @@ class PHPMailer
*/
protected function sendmailSend($header, $body)
{
if ($this->Mailer === 'qmail') {
$this->edebug('Sending with qmail');
} else {
$this->edebug('Sending with sendmail');
}
$header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
//This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
//A space after `-f` is optional, but there is a long history of its presence
//causing problems, so we don't use one
//Exim docs: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
//Sendmail docs: http://www.sendmail.org/~ca/email/man/sendmail.html
//Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html
//Example problem: https://www.drupal.org/node/1057954
//CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
if (!empty($this->Sender) && self::isShellSafe($this->Sender)) {
if ('qmail' === $this->Mailer) {
if ('' === $this->Sender) {
$this->Sender = $this->From;
}
if (empty($this->Sender) && !empty(ini_get('sendmail_from'))) {
//PHP config has a sender address we can use
$this->Sender = ini_get('sendmail_from');
}
//CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
//But sendmail requires this param, so fail without it
if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) {
if ($this->Mailer === 'qmail') {
$sendmailFmt = '%s -f%s';
} else {
$sendmailFmt = '%s -oi -f%s -t';
}
} elseif ('qmail' === $this->Mailer) {
$sendmailFmt = '%s';
} else {
$sendmailFmt = '%s -oi -t';
$this->edebug('Sender address unusable or missing: ' . $this->Sender);
return false;
}
$sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
$this->edebug('Sendmail path: ' . $this->Sendmail);
$this->edebug('Sendmail command: ' . $sendmail);
$this->edebug('Envelope sender: ' . $this->Sender);
$this->edebug("Headers: {$header}");
if ($this->SingleTo) {
foreach ($this->SingleToArray as $toAddr) {
@ -1670,6 +1715,7 @@ class PHPMailer
if (!$mail) {
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
$this->edebug("To: {$toAddr}");
fwrite($mail, 'To: ' . $toAddr . "\n");
fwrite($mail, $header);
fwrite($mail, $body);
@ -1684,6 +1730,7 @@ class PHPMailer
$this->From,
[]
);
$this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
if (0 !== $result) {
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
@ -1706,6 +1753,7 @@ class PHPMailer
$this->From,
[]
);
$this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
if (0 !== $result) {
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
}
@ -1812,10 +1860,17 @@ class PHPMailer
//Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html
//Example problem: https://www.drupal.org/node/1057954
//CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) {
$params = sprintf('-f%s', $this->Sender);
if ('' === $this->Sender) {
$this->Sender = $this->From;
}
if (empty($this->Sender) && !empty(ini_get('sendmail_from'))) {
//PHP config has a sender address we can use
$this->Sender = ini_get('sendmail_from');
}
if (!empty($this->Sender) && static::validateAddress($this->Sender)) {
if (self::isShellSafe($this->Sender)) {
$params = sprintf('-f%s', $this->Sender);
}
$old_from = ini_get('sendmail_from');
ini_set('sendmail_from', $this->Sender);
}
@ -2023,7 +2078,7 @@ class PHPMailer
$secure = static::ENCRYPTION_SMTPS;
} elseif ('tls' === $hostinfo[1]) {
$tls = true;
// tls doesn't use a prefix
//TLS doesn't use a prefix
$secure = static::ENCRYPTION_STARTTLS;
}
//Do we need the OpenSSL extension?
@ -2546,10 +2601,6 @@ class PHPMailer
}
}
if ('mail' !== $this->Mailer) {
// $result .= static::$LE;
}
return $result;
}
@ -3948,13 +3999,13 @@ class PHPMailer
protected function lang($key)
{
if (count($this->language) < 1) {
$this->setLanguage(); // set the default language
$this->setLanguage(); //Set the default language
}
if (array_key_exists($key, $this->language)) {
if ('smtp_connect_failed' === $key) {
//Include a link to troubleshooting docs on SMTP connection failure
//this is by far the biggest cause of support questions
//Include a link to troubleshooting docs on SMTP connection failure.
//This is by far the biggest cause of support questions
//but it's usually not PHPMailer's fault.
return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
}
@ -4528,13 +4579,13 @@ class PHPMailer
$privKey = openssl_pkey_get_private($privKeyStr);
}
if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
if (PHP_MAJOR_VERSION < 8) {
if (\PHP_MAJOR_VERSION < 8) {
openssl_pkey_free($privKey);
}
return base64_encode($signature);
}
if (PHP_MAJOR_VERSION < 8) {
if (\PHP_MAJOR_VERSION < 8) {
openssl_pkey_free($privKey);
}
@ -4724,7 +4775,8 @@ class PHPMailer
$headerKeys = ' h=' . implode(':', $headersToSignKeys) . ';' . static::$LE;
$headerValues = implode(static::$LE, $headersToSign);
$body = $this->DKIM_BodyC($body);
$DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body
//Base64 of packed binary SHA-256 hash of body
$DKIMb64 = base64_encode(pack('H*', hash('sha256', $body)));
$ident = '';
if ('' !== $this->DKIM_identity) {
$ident = ' i=' . $this->DKIM_identity . ';' . static::$LE;

View File

@ -35,7 +35,7 @@ class SMTP
*
* @var string
*/
const VERSION = '6.2.0';
const VERSION = '6.3.0';
/**
* SMTP line break constant.
@ -343,9 +343,21 @@ class SMTP
//Get any announcement
$this->last_reply = $this->get_lines();
$this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
$responseCode = (int)substr($this->last_reply, 0, 3);
if ($responseCode === 220) {
return true;
}
//Anything other than a 220 response means something went wrong
//RFC 5321 says the server will wait for us to send a QUIT in response to a 554 error
//https://tools.ietf.org/html/rfc5321#section-3.1
if ($responseCode === 554) {
$this->quit();
}
//This will handle 421 responses which may not wait for a QUIT (e.g. if the server is being shut down)
$this->edebug('Connection: closing due to error', self::DEBUG_CONNECTION);
$this->close();
return false;
}
/**
* Create connection to the SMTP server.
@ -671,7 +683,7 @@ class SMTP
$this->server_caps = null;
$this->helo_rply = null;
if (is_resource($this->smtp_conn)) {
// close the connection and cleanup
//Close the connection and cleanup
fclose($this->smtp_conn);
$this->smtp_conn = null; //Makes for cleaner serialization
$this->edebug('Connection: closed', self::DEBUG_CONNECTION);
@ -752,7 +764,8 @@ class SMTP
//Send the lines to the server
foreach ($lines_out as $line_out) {
//RFC2821 section 4.5.2
//Dot-stuffing as per RFC5321 section 4.5.2
//https://tools.ietf.org/html/rfc5321#section-4.5.2
if (!empty($line_out) && $line_out[0] === '.') {
$line_out = '.' . $line_out;
}
@ -786,7 +799,16 @@ class SMTP
public function hello($host = '')
{
//Try extended hello first (RFC 2821)
return $this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host);
if ($this->sendHello('EHLO', $host)) {
return true;
}
//Some servers shut down the SMTP service here (RFC 5321)
if (substr($this->helo_rply, 0, 3) == '421') {
return false;
}
return $this->sendHello('HELO', $host);
}
/**

View File

@ -13,7 +13,7 @@
*
* @global string $wp_version
*/
$wp_version = '5.7-beta3-50396';
$wp_version = '5.7-beta3-50397';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.