Add support for RFC6530, using it only when required.
This adds the ability to send email to addresses like grå@grå.org, but preserves phpmailer's old behaviour for all addresses that worked before (such as info@grå.org).
This commit is contained in:
parent
e7b1334cf2
commit
9278e5774a
|
|
@ -659,6 +659,14 @@ class PHPMailer
|
|||
*/
|
||||
protected $ReplyToQueue = [];
|
||||
|
||||
/**
|
||||
* Whether the need for SMTPUTF8 has been detected. Set by
|
||||
* preSend() if necessary.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $UseSMTPUTF8 = false;
|
||||
|
||||
/**
|
||||
* The array of attachments.
|
||||
*
|
||||
|
|
@ -1362,6 +1370,7 @@ class PHPMailer
|
|||
* * `pcre` Use old PCRE implementation;
|
||||
* * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
|
||||
* * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
|
||||
* * `eai` Use a pattern similar to the HTML5 spec for 'email' and to firefox, extended to support EAI (RFC6530).
|
||||
* * `noregex` Don't use a regex: super fast, really dumb.
|
||||
* Alternatively you may pass in a callable to inject your own validator, for example:
|
||||
*
|
||||
|
|
@ -1432,6 +1441,17 @@ class PHPMailer
|
|||
'[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
|
||||
$address
|
||||
);
|
||||
case 'eai':
|
||||
/*
|
||||
* This is the pattern used in the HTML5 spec for validation of 'email' type form input elements, modified to accept unicode email addresses. This is also more lenient than Firefox' html5 spec, in order to make the regex faster.
|
||||
*
|
||||
* @see https://html.spec.whatwg.org/#e-mail-state-(type=email)
|
||||
*/
|
||||
return (bool) preg_match(
|
||||
'/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~\x80-\xff-]+@[a-zA-Z0-9\x80-\xff](?:[a-zA-Z0-9\x80-\xff-]{0,61}' .
|
||||
'[a-zA-Z0-9\x80-\xff])?(?:\.[a-zA-Z0-9\x80-\xff](?:[a-zA-Z0-9\x80-\xff-]{0,61}[a-zA-Z0-9\x80-\xff])?)*$/sD',
|
||||
$address
|
||||
);
|
||||
case 'php':
|
||||
default:
|
||||
return filter_var($address, FILTER_VALIDATE_EMAIL) !== false;
|
||||
|
|
@ -1565,9 +1585,24 @@ class PHPMailer
|
|||
$this->error_count = 0; //Reset errors
|
||||
$this->mailHeader = '';
|
||||
|
||||
//The code below tries to support full use of unicode,
|
||||
//while remaining compatible with legacy SMTP servers to
|
||||
//the greatest degree possible: If the message uses
|
||||
//unicode in the localparts of any addresses, it is sent
|
||||
//using SMTPUTF8. If not, it it sent using
|
||||
//pynycode-encoded domains and plain SMTP.
|
||||
if (static::CHARSET_UTF8 === strtolower($this->CharSet) &&
|
||||
($this->anyAddressHasUnicodeLocalpart($this->RecipientsQueue) ||
|
||||
$this->anyAddressHasUnicodeLocalpart(array_keys($this->all_recipients)) ||
|
||||
$this->anyAddressHasUnicodeLocalpart($this->ReplyToQueue) ||
|
||||
$this->addressHasUnicodeLocalpart($this->From))) {
|
||||
$this->UseSMTPUTF8 = true;
|
||||
}
|
||||
//Dequeue recipient and Reply-To addresses with IDN
|
||||
foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
|
||||
$params[1] = $this->punyencodeAddress($params[1]);
|
||||
if (!$this->UseSMTPUTF8) {
|
||||
$params[1] = $this->punyencodeAddress($params[1]);
|
||||
}
|
||||
call_user_func_array([$this, 'addAnAddress'], $params);
|
||||
}
|
||||
if (count($this->to) + count($this->cc) + count($this->bcc) < 1) {
|
||||
|
|
@ -2159,6 +2194,7 @@ class PHPMailer
|
|||
$this->smtp->setDebugLevel($this->SMTPDebug);
|
||||
$this->smtp->setDebugOutput($this->Debugoutput);
|
||||
$this->smtp->setVerp($this->do_verp);
|
||||
$this->smtp->setSMTPUTF8($this->UseSMTPUTF8);
|
||||
if ($this->Host === null) {
|
||||
$this->Host = 'localhost';
|
||||
}
|
||||
|
|
@ -4267,6 +4303,35 @@ class PHPMailer
|
|||
return filter_var('https://' . $host, FILTER_VALIDATE_URL) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the supplied address uses unicode in the localpart.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function addressHasUnicodeLocalpart($address)
|
||||
{
|
||||
return (bool) preg_match( '/[\x80-\xFF].*@/', $address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether any of the supplied addresses use unicode in the
|
||||
* localpart.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function anyAddressHasUnicodeLocalpart($addresses)
|
||||
{
|
||||
foreach ($addresses as $address) {
|
||||
if (is_array($address)) {
|
||||
$address = $address[0];
|
||||
}
|
||||
if ($this->addressHasUnicodeLocalpart($address)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an error message in the current language.
|
||||
*
|
||||
|
|
|
|||
42
src/SMTP.php
42
src/SMTP.php
|
|
@ -159,6 +159,15 @@ class SMTP
|
|||
*/
|
||||
public $do_verp = false;
|
||||
|
||||
/**
|
||||
* Whether to use SMTPUTF8.
|
||||
*
|
||||
* @see https://www.rfc-editor.org/rfc/rfc6531
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $do_smtputf8 = false;
|
||||
|
||||
/**
|
||||
* The timeout value for connection, in seconds.
|
||||
* Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2.
|
||||
|
|
@ -913,7 +922,15 @@ class SMTP
|
|||
* $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>.
|
||||
* Implements RFC 821: MAIL <SP> FROM:<reverse-path> <CRLF> and
|
||||
* two extensions, namely XVERP and SMTPUTF8.
|
||||
*
|
||||
* The server's EHLO response is not checked. If use of either
|
||||
* extensions is enabled even though the server does not support
|
||||
* that, mail submission will fail.
|
||||
*
|
||||
* XVERP is documented at https://www.postfix.org/VERP_README.html
|
||||
* and SMTPUTF8 is specified in RFC 6531.
|
||||
*
|
||||
* @param string $from Source address of this message
|
||||
*
|
||||
|
|
@ -922,10 +939,11 @@ class SMTP
|
|||
public function mail($from)
|
||||
{
|
||||
$useVerp = ($this->do_verp ? ' XVERP' : '');
|
||||
$useSmtputf8 = ($this->do_smtputf8 ? ' SMTPUTF8' : '');
|
||||
|
||||
return $this->sendCommand(
|
||||
'MAIL FROM',
|
||||
'MAIL FROM:<' . $from . '>' . $useVerp,
|
||||
'MAIL FROM:<' . $from . '>' . $useSmtputf8 . $useVerp,
|
||||
250
|
||||
);
|
||||
}
|
||||
|
|
@ -1364,6 +1382,26 @@ class SMTP
|
|||
return $this->do_verp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable use of SMTPUTF8.
|
||||
*
|
||||
* @param bool $enabled
|
||||
*/
|
||||
public function setSMTPUTF8($enabled = false)
|
||||
{
|
||||
$this->do_smtputf8 = $enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SMTPUTF8 use.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getSMTPUTF8()
|
||||
{
|
||||
return $this->do_smtputf8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set error messages and codes.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1192,6 +1192,46 @@ EOT;
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test SMTPUTF8 usage, including when it is not to be used.
|
||||
*/
|
||||
public function testUnsuppoortedSmtpUTF8()
|
||||
{
|
||||
$this->Mail->CharSet = PHPMailer::CHARSET_ISO88591;
|
||||
self::assertFalse($this->Mail->addAddress('spın̈altap@example.com', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test SMTPUTF8 usage, including when it is not to be used.
|
||||
*/
|
||||
public function testSmtpUTF8()
|
||||
{
|
||||
//No reason to use SMTPUTF8
|
||||
$this->Mail->isSMTP();
|
||||
$this->Mail->addAddress('foo@example.com', '');
|
||||
$this->Mail->preSend();
|
||||
|
||||
//Using a punycoded domain is enough
|
||||
self::assertFalse($this->Mail->UseSMTPUTF8);
|
||||
$this->Mail->addAddress('foo@spın̈altap.example', '');
|
||||
$this->Mail->preSend();
|
||||
self::assertFalse($this->Mail->UseSMTPUTF8);
|
||||
|
||||
//Need to use SMTPUTF8, and can.
|
||||
$this->Mail->CharSet = PHPMailer::CHARSET_UTF8;
|
||||
PHPMailer::$validator = 'eai';
|
||||
self::assertTrue($this->Mail->addAddress('spın̈altap@example.com', ''));
|
||||
$this->Mail->preSend();
|
||||
self::assertTrue($this->Mail->UseSMTPUTF8);
|
||||
|
||||
//If using SMTPUTF8, then the To header should contain
|
||||
//unicode@unicode, for better rendering by clients like Mac
|
||||
//Outlook.
|
||||
$this->Mail->addAddress('spın̈altap@spın̈altap.invalid', '');
|
||||
$this->Mail->preSend();
|
||||
self::assertStringContainsString("spın̈altap@spın̈altap.invalid", $this->Mail->createHeader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test SMTP Xclient options
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue