From 2f0af94d33aeb0838d0095574730f39bf8989d54 Mon Sep 17 00:00:00 2001 From: Arnt Gulbrandsen Date: Wed, 23 Oct 2024 15:34:11 +0200 Subject: [PATCH] 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. --- src/PHPMailer.php | 21 ++++++++++++++++++ test/PHPMailer/PHPMailerTest.php | 38 +++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/PHPMailer.php b/src/PHPMailer.php index e5840ebb..5417d507 100644 --- a/src/PHPMailer.php +++ b/src/PHPMailer.php @@ -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. * diff --git a/test/PHPMailer/PHPMailerTest.php b/test/PHPMailer/PHPMailerTest.php index 671a021c..15693a0a 100644 --- a/test/PHPMailer/PHPMailerTest.php +++ b/test/PHPMailer/PHPMailerTest.php @@ -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