Set UseSMTPUTF8 fully automatically when needed

This makes SMTPUTF8 support the default when the user chooses to use UTF-8
as charset, without affecting code that uses ISO 8859-1.
This commit is contained in:
Arnt Gulbrandsen 2024-10-23 15:34:11 +02:00 committed by Marcus Bointon
parent 0e7b094a32
commit 2f0af94d33
No known key found for this signature in database
GPG Key ID: DE31CD6EB646AA24
2 changed files with 51 additions and 8 deletions

View File

@ -580,6 +580,10 @@ class PHPMailer
* May be a callable to inject your own validator, but there are several built-in validators.
* The default validator uses PHP's FILTER_VALIDATE_EMAIL filter_var option.
*
* If CharSet is UTF8, the validator is left at the default value,
* and you send to addresses that use non-ASCII locallparts, then
* PHPMailer automatically changes to the 'eai' validator.
*
* @see PHPMailer::validateAddress()
*
* @var string|callable
@ -1168,6 +1172,11 @@ class PHPMailer
*/
protected function addAnAddress($kind, $address, $name = '')
{
if ($this->CharSet === self::CHARSET_UTF8 &&
self::$validator === 'php' &&
$this->addressHasUnicodeLocalpart($address)) {
self::$validator = 'eai';
}
if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) {
$error_message = sprintf(
'%s: %s',
@ -4343,6 +4352,18 @@ class PHPMailer
return false;
}
/**
* Check whether the message requires SMTPUTF8 based on what's
* known so far.
*
* @return bool
*/
public function needsSMTPUTF8()
{
return $this->UseSMTPUTF8;
}
/**
* Get an error message in the current language.
*

View File

@ -1193,13 +1193,33 @@ EOT;
}
/**
* Test SMTPUTF8 usage, including when it is not to be used.
* Test that validation doesn't accidentally succeed.
*/
public function testUnsupportedSmtpUTF8()
{
$this->Mail = new PHPMailer(true);
$this->Mail->CharSet = PHPMailer::CHARSET_UTF8;
PHPMailer::$validator = 'html5';
self::assertFalse($this->Mail->addAddress('spın̈altap@example.com', ''));
self::assertFalse(PHPMailer::validateAddress('spın̈altap@example.com'));
PHPMailer::$validator = 'eai';
self::assertTrue(PHPMailer::validateAddress('spın̈altap@example.com'));
}
/**
* Test that SMTPUTF8 is automatically allowed if charset is UTF8.
*/
public function testAutomaticEaiValidation()
{
$this->Mail->CharSet = PHPMailer::CHARSET_UTF8;
$this->Mail = new PHPMailer(true);
PHPMailer::$validator = 'php';
$this->Mail->CharSet = PHPMailer::CHARSET_UTF8;
$this->Mail->Body = 'Test';
$this->Mail->isSMTP();
self::assertTrue($this->Mail->addAddress('spın̈altap@example.com', ''));
$this->Mail->preSend();
self::assertTrue($this->Mail->needsSMTPUTF8());
}
/**
@ -1207,24 +1227,26 @@ EOT;
*/
public function testSmtpUTF8()
{
//No reason to use SMTPUTF8
PHPMailer::$validator = "eai";
$this->Mail = new PHPMailer(true);
$this->Mail->Body = 'Test';
$this->Mail->isSMTP();
$this->Mail->addAddress('foo@example.com', '');
$this->Mail->preSend();
self::assertFalse($this->Mail->needsSMTPUTF8());
//Using a punycoded domain does not need SMTPUTF8
self::assertFalse($this->Mail->UseSMTPUTF8);
self::assertFalse($this->Mail->needsSMTPUTF8());
PHPMailer::$validator = "eai";
$this->Mail->addAddress('foo@spın̈altap.example', '');
$this->Mail->preSend();
self::assertFalse($this->Mail->UseSMTPUTF8);
self::assertFalse($this->Mail->needsSMTPUTF8());
//Need to use SMTPUTF8, and can.
$this->Mail->CharSet = PHPMailer::CHARSET_UTF8;
PHPMailer::$validator = 'eai';
self::assertTrue(PHPMailer::validateAddress('spın̈altap@example.com'));
self::assertTrue($this->Mail->addAddress('spın̈altap@example.com', ''));
$this->Mail->preSend();
self::assertTrue($this->Mail->UseSMTPUTF8);
self::assertTrue($this->Mail->needsSMTPUTF8());
//If using SMTPUTF8, then the To header should contain
//Unicode@Unicode, for better rendering by clients like Mac