feature #36178 [Mime] allow non-ASCII characters in local part of email (dmaicher)
This PR was merged into the 5.2-dev branch. Discussion ---------- [Mime] allow non-ASCII characters in local part of email | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | https://github.com/symfony/symfony/issues/34932 | License | MIT | Doc PR | - This fixes https://github.com/symfony/symfony/issues/34932 by allowing non-ASCII characters in the local part of emails. I tried this using 3 different smtp servers (gmail, mailgun and local postfix) and for me this just works in case there are non-ASCII characters in the local part of emails. Emails are correctly delivered. PHPMailer does this in the same way: https://github.com/PHPMailer/PHPMailer/blob/master/src/PHPMailer.php#L1411 This is also in line with the behavior of Swiftmailer (< 6.1) **before** this commit that introduced the `IdnAddressEncoder`:6a87efd39b (diff-e5f85d26733017e183b2633ae3c433f0R31)
I'm not an expert when it comes to SMTP and all the different RFCs out there 😕 But for me this exception seems not needed. Maybe @c960657 can help here? Commits -------d057dffcd6
[Mime] allow non-ASCII characters in local part of email
This commit is contained in:
commit
63f8827cf0
@ -41,11 +41,11 @@ final class DelayedEnvelope extends Envelope
|
||||
|
||||
public function getSender(): Address
|
||||
{
|
||||
if ($this->senderSet) {
|
||||
return parent::getSender();
|
||||
if (!$this->senderSet) {
|
||||
parent::setSender(self::getSenderFromHeaders($this->message->getHeaders()));
|
||||
}
|
||||
|
||||
return self::getSenderFromHeaders($this->message->getHeaders());
|
||||
return parent::getSender();
|
||||
}
|
||||
|
||||
public function setRecipients(array $recipients): void
|
||||
|
@ -44,6 +44,10 @@ class Envelope
|
||||
|
||||
public function setSender(Address $sender): void
|
||||
{
|
||||
// to ensure deliverability of bounce emails independent of UTF-8 capabilities of SMTP servers
|
||||
if (!preg_match('/^[^@\x80-\xFF]++@/', $sender->getAddress())) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid sender "%s": non-ASCII characters not supported in local-part of email.', $sender->getAddress()));
|
||||
}
|
||||
$this->sender = new Address($sender->getAddress());
|
||||
}
|
||||
|
||||
|
@ -13,9 +13,11 @@ namespace Symfony\Component\Mailer\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Mailer\Envelope;
|
||||
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Mailer\Exception\LogicException;
|
||||
use Symfony\Component\Mime\Address;
|
||||
use Symfony\Component\Mime\Header\Headers;
|
||||
use Symfony\Component\Mime\Header\PathHeader;
|
||||
use Symfony\Component\Mime\Message;
|
||||
use Symfony\Component\Mime\RawMessage;
|
||||
|
||||
@ -27,6 +29,13 @@ class EnvelopeTest extends TestCase
|
||||
$this->assertEquals(new Address('fabien@symfony.com'), $e->getSender());
|
||||
}
|
||||
|
||||
public function testConstructorWithAddressSenderAndNonAsciiCharactersInLocalPartOfAddress()
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Invalid sender "fabièn@symfony.com": non-ASCII characters not supported in local-part of email.');
|
||||
new Envelope(new Address('fabièn@symfony.com'), [new Address('thomas@symfony.com')]);
|
||||
}
|
||||
|
||||
public function testConstructorWithNamedAddressSender()
|
||||
{
|
||||
$e = new Envelope(new Address('fabien@symfony.com', 'Fabien'), [new Address('thomas@symfony.com')]);
|
||||
@ -57,19 +66,27 @@ class EnvelopeTest extends TestCase
|
||||
$headers->addPathHeader('Return-Path', new Address('return@symfony.com', 'return'));
|
||||
$headers->addMailboxListHeader('To', ['from@symfony.com']);
|
||||
$e = Envelope::create(new Message($headers));
|
||||
$this->assertEquals(new Address('return@symfony.com', 'return'), $e->getSender());
|
||||
$this->assertEquals(new Address('return@symfony.com'), $e->getSender());
|
||||
|
||||
$headers = new Headers();
|
||||
$headers->addMailboxHeader('Sender', new Address('sender@symfony.com', 'sender'));
|
||||
$headers->addMailboxListHeader('To', ['from@symfony.com']);
|
||||
$e = Envelope::create(new Message($headers));
|
||||
$this->assertEquals(new Address('sender@symfony.com', 'sender'), $e->getSender());
|
||||
$this->assertEquals(new Address('sender@symfony.com'), $e->getSender());
|
||||
|
||||
$headers = new Headers();
|
||||
$headers->addMailboxListHeader('From', [new Address('from@symfony.com', 'from'), 'some@symfony.com']);
|
||||
$headers->addMailboxListHeader('To', ['from@symfony.com']);
|
||||
$e = Envelope::create(new Message($headers));
|
||||
$this->assertEquals(new Address('from@symfony.com', 'from'), $e->getSender());
|
||||
$this->assertEquals(new Address('from@symfony.com'), $e->getSender());
|
||||
}
|
||||
|
||||
public function testSenderFromHeadersFailsWithNonAsciiCharactersInLocalPart()
|
||||
{
|
||||
$this->expectException(InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Invalid sender "fabièn@symfony.com": non-ASCII characters not supported in local-part of email.');
|
||||
$message = new Message(new Headers(new PathHeader('Return-Path', new Address('fabièn@symfony.com'))));
|
||||
Envelope::create($message)->getSender();
|
||||
}
|
||||
|
||||
public function testSenderFromHeadersWithoutFrom()
|
||||
@ -78,7 +95,7 @@ class EnvelopeTest extends TestCase
|
||||
$headers->addMailboxListHeader('To', ['from@symfony.com']);
|
||||
$e = Envelope::create($message = new Message($headers));
|
||||
$message->getHeaders()->addMailboxListHeader('From', [new Address('from@symfony.com', 'from')]);
|
||||
$this->assertEquals(new Address('from@symfony.com', 'from'), $e->getSender());
|
||||
$this->assertEquals(new Address('from@symfony.com'), $e->getSender());
|
||||
}
|
||||
|
||||
public function testRecipientsFromHeaders()
|
||||
|
@ -11,16 +11,14 @@
|
||||
|
||||
namespace Symfony\Component\Mime\Encoder;
|
||||
|
||||
use Symfony\Component\Mime\Exception\AddressEncoderException;
|
||||
|
||||
/**
|
||||
* An IDN email address encoder.
|
||||
*
|
||||
* Encodes the domain part of an address using IDN. This is compatible will all
|
||||
* SMTP servers.
|
||||
*
|
||||
* This encoder does not support email addresses with non-ASCII characters in
|
||||
* local-part (the substring before @).
|
||||
* Note: It leaves the local part as is. In case there are non-ASCII characters
|
||||
* in the local part then it depends on the SMTP Server if this is supported.
|
||||
*
|
||||
* @author Christian Schmidt
|
||||
*/
|
||||
@ -28,8 +26,6 @@ final class IdnAddressEncoder implements AddressEncoderInterface
|
||||
{
|
||||
/**
|
||||
* Encodes the domain part of an address using IDN.
|
||||
*
|
||||
* @throws AddressEncoderException If local-part contains non-ASCII characters
|
||||
*/
|
||||
public function encodeString(string $address): string
|
||||
{
|
||||
@ -38,10 +34,6 @@ final class IdnAddressEncoder implements AddressEncoderInterface
|
||||
$local = substr($address, 0, $i);
|
||||
$domain = substr($address, $i + 1);
|
||||
|
||||
if (preg_match('/[^\x00-\x7F]/', $local)) {
|
||||
throw new AddressEncoderException(sprintf('Non-ASCII characters not supported in local-part os "%s".', $address));
|
||||
}
|
||||
|
||||
if (preg_match('/[^\x00-\x7F]/', $domain)) {
|
||||
$address = sprintf('%s@%s', $local, idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46));
|
||||
}
|
||||
|
@ -58,11 +58,10 @@ class MailboxHeaderTest extends TestCase
|
||||
$this->assertEquals('Fabien =?'.$header->getCharset().'?Q?P=8Ftencier?= <fabien@symfony.com>', $header->getBodyAsString());
|
||||
}
|
||||
|
||||
public function testUtf8CharsInLocalPartThrows()
|
||||
public function testUtf8CharsInLocalPart()
|
||||
{
|
||||
$this->expectException('Symfony\Component\Mime\Exception\AddressEncoderException');
|
||||
$header = new MailboxHeader('Sender', new Address('fabïen@symfony.com'));
|
||||
$header->getBodyAsString();
|
||||
$this->assertSame('fabïen@symfony.com', $header->getBodyAsString());
|
||||
}
|
||||
|
||||
public function testToString()
|
||||
|
@ -55,11 +55,10 @@ class MailboxListHeaderTest extends TestCase
|
||||
$this->assertEquals(['Chris Corbyn <chris@xn--swftmailer-78a.org>'], $header->getAddressStrings());
|
||||
}
|
||||
|
||||
public function testUtf8CharsInLocalPartThrows()
|
||||
public function testUtf8CharsInLocalPart()
|
||||
{
|
||||
$this->expectException('Symfony\Component\Mime\Exception\AddressEncoderException');
|
||||
$header = new MailboxListHeader('From', [new Address('chrïs@swiftmailer.org', 'Chris Corbyn')]);
|
||||
$header->getAddressStrings();
|
||||
$this->assertSame(['Chris Corbyn <chrïs@swiftmailer.org>'], $header->getAddressStrings());
|
||||
}
|
||||
|
||||
public function testGetMailboxesReturnsNameValuePairs()
|
||||
|
@ -49,11 +49,10 @@ class PathHeaderTest extends TestCase
|
||||
$this->assertEquals('<chris@xn--swftmailer-78a.org>', $header->getBodyAsString());
|
||||
}
|
||||
|
||||
public function testAddressMustBeEncodable()
|
||||
public function testAddressMustBeEncodableWithUtf8CharsInLocalPart()
|
||||
{
|
||||
$this->expectException('Symfony\Component\Mime\Exception\AddressEncoderException');
|
||||
$header = new PathHeader('Return-Path', new Address('chrïs@swiftmailer.org'));
|
||||
$header->getBodyAsString();
|
||||
$this->assertSame('<chrïs@swiftmailer.org>', $header->getBodyAsString());
|
||||
}
|
||||
|
||||
public function testSetBody()
|
||||
|
Reference in New Issue
Block a user