8000 feature #36178 [Mime] allow non-ASCII characters in local part of ema… · symfony/symfony@63f8827 · GitHub
[go: up one dir, main page]

8000
Skip to content

Commit 63f8827

Browse files
committed
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 | #34932 | License | MIT | Doc PR | - This fixes #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`: swiftmailer/swiftmailer@6a87efd#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 ------- d057dff [Mime] allow non-ASCII characters in local part of email
2 parents dfc3267 + d057dff commit 63f8827

File tree

7 files changed

+36
-26
lines changed

7 files changed

+36
-26
lines changed

src/Symfony/Component/Mailer/DelayedEnvelope.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ public function setSender(Address $sender): void
4141

4242
public function getSender(): Address
4343
{
44-
if ($this->senderSet) {
45-
return parent::getSender();
44+
if (!$this->senderSet) {
45+
parent::setSender(self::getSenderFromHeaders($this->message->getHeaders()));
4646
}
4747

48-
return self::getSenderFromHeaders($this->message->getHeaders());
48+
return parent::getSender();
4949
}
5050

5151
public function setRecipients(array $recipients): void

src/Symfony/Component/Mailer/Envelope.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ public static function create(RawMessage $message): self
4444

4545
public function setSender(Address $sender): void
4646
{
47+
// to ensure deliverability of bounce emails independent of UTF-8 capabilities of SMTP servers
48+
if (!preg_match('/^[^@\x80-\xFF]++@/', $sender->getAddress())) {
49+
throw new InvalidArgumentException(sprintf('Invalid sender "%s": non-ASCII characters not supported in local-part of email.', $sender->getAddress()));
50+
}
4751
$this->sender = new Address($sender->getAddress());
4852
}
4953

src/Symfony/Component/Mailer/Tests/EnvelopeTest.php

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Mailer\Envelope;
16+
use Symfony\Component\Mailer\Exception\InvalidArgumentException;
1617
use Symfony\Component\Mailer\Exception\LogicException;
1718
use Symfony\Component\Mime\Address;
1819
use Symfony\Component\Mime\Header\Headers;
20+
use Symfony\Component\Mime\Header\PathHeader;
1921
use Symfony\Component\Mime\Message;
2022
use Symfony\Component\Mime\RawMessage;
2123

@@ -27,6 +29,13 @@ public function testConstructorWithAddressSender()
2729
$this->assertEquals(new Address('fabien@symfony.com'), $e->getSender());
2830
}
2931

32+
public function testConstructorWithAddressSenderAndNonAsciiCharactersInLocalPartOfAddress()
33+
{
34+
$this->expectException(InvalidArgumentException::class);
35+
$this->expectExceptionMessage('Invalid sender "fabièn@symfony.com": non-ASCII characters not supported in local-part of email.');
36+
new Envelope(new Address('fabièn@symfony.com'), [new Address('thomas@symfony.com')]);
37+
}
38+
3039
public function testConstructorWithNamedAddressSender()
3140
{
3241
$e = new Envelope(new Address('fabien@symfony.com', 'Fabien'), [new Address('thomas@symfony.com')]);
@@ -57,19 +66,27 @@ public function testSenderFromHeaders()
5766
$headers->addPathHeader('Return-Path', new Address('return@symfony.com', 'return'));
5867
$headers->addMailboxListHeader('To', ['from@symfony.com']);
5968
$e = Envelope::create(new Message($headers));
60-
$this->assertEquals(new Address('return@symfony.com', 'return'), $e->getSender());
69+
$this->assertEquals(new Address('return@symfony.com'), $e->getSender());
6170

6271
$headers = new Headers();
6372
$headers->addMailboxHeader('Sender', new Address('sender@symfony.com', 'sender'));
6473
$headers->addMailboxListHeader('To', ['from@symfony.com']);
6574
$e = Envelope::create(new Message($headers));
66-
$this->assertEquals(new Address('sender@symfony.com', 'sender'), $e->getSender());
75+
$this->assertEquals(new Address('sender@symfony.com'), $e->getSender());
6776

6877
$headers = new Headers();
6978
$headers->addMailboxListHeader('From', [new Address('from@symfony.com', 'from'), 'some@symfony.com']);
7079
$headers->addMailboxListHeader('To', ['from@symfony.com']);
7180
$e = Envelope::create(new Message($headers));
72-
$this->assertEquals(new Address('from@symfony.com', 'from'), $e->getSender());
81+
$this->assertEquals(new Address('from@symfony.com'), $e->getSender());
82+
}
83+
84+
public function testSenderFromHeadersFailsWithNonAsciiCharactersInLocalPart()
85+
{
86+
$this->expectException(InvalidArgumentException::class);
87+
$this->expectExceptionMessage('Invalid sender "fabièn@symfony.com": non-ASCII characters not supported in local-part of email.');
88+
$message = new Message(new Headers(new PathHeader('Return-Path', new Address('fabièn@symfony.com'))));
89+
Envelope::create($message)->getSender();
7390
}
7491

7592
public function testSenderFromHeadersWithoutFrom()
@@ -78,7 +95,7 @@ public function testSenderFromHeadersWithoutFrom()
7895
$headers->addMailboxListHeader('To', ['from@symfony.com']);
7996
$e = Envelope::create($message = new Message($headers));
8097
$message->getHeaders()->addMailboxListHeader('From', [new Address('from@symfony.com', 'from')]);
81-
$this->assertEquals(new Address('from@symfony.com', 'from'), $e->getSender());
98+
$this->assertEquals(new Address('from@symfony.com'), $e->getSender());
8299
}
83100

84101
public function testRecipientsFromHeaders()

src/Symfony/Component/Mime/Encoder/IdnAddressEncoder.php

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,21 @@
1111

1212
namespace Symfony\Component\Mime\Encoder;
1313

14-
use Symfony\Component\Mime\Exception\AddressEncoderException;
15-
1614
/**
1715
* An IDN email address encoder.
1816
*
1917
* Encodes the domain part of an address using IDN. This is compatible will all
2018
* SMTP servers.
2119
*
22-
* This encoder does not support email addresses with non-ASCII characters in
23-
* local-part (the substring before @).
20+
* Note: It leaves the local part as is. In case there are non-ASCII characters
21+
* in the local part then it depends on the SMTP Server if this is supported.
2422
*
2523
* @author Christian Schmidt
2624
*/
2725
final class IdnAddressEncoder implements AddressEncoderInterface
2826
{
2927
/**
3028
* Encodes the domain part of an address using IDN.
31-
*
32-
* @throws AddressEncoderException If local-part contains non-ASCII characters
3329
*/
3430
public function encodeString(string $address): string
3531
{
@@ -38,10 +34,6 @@ public function encodeString(string $address): string
3834
$local = substr($address, 0, $i);
3935
$domain = substr($address, $i + 1);
4036

41-
if (preg_match('/[^\x00-\x7F]/', $local)) {
42-
throw new AddressEncoderException(sprintf('Non-ASCII characters not supported in local-part os "%s".', $address));
43-
}
44-
4537
if (preg_match('/[^\x00-\x7F]/', $domain)) {
4638
$address = sprintf('%s@%s', $local, idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46));
4739
}

src/Symfony/Component/Mime/Tests/Header/MailboxHeaderTest.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,10 @@ public function testgetBodyAsString()
5858
$this->assertEquals('Fabien =?'.$header->getCharset().'?Q?P=8Ftencier?= <fabien@symfony.com>', $header->getBodyAsString());
5959
}
6060

61-
public function testUtf8CharsInLocalPartThrows()
61+
public function testUtf8CharsInLocalPart()
6262
{
63-
$this->expectException('Symfony\Component\Mime\Exception\AddressEncoderException');
6463
$header = new MailboxHeader('Sender', new Address('fabïen@symfony.com'));
65-
$header->getBodyAsString();
64+
$this->assertSame('fabïen@symfony.com', $header->getBodyAsString());
6665
}
6766

6867
public function testToString()

src/Symfony/Component/Mime/Tests/Header/MailboxListHeaderTest.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,10 @@ public function testUtf8CharsInDomainAreIdnEncoded()
5555
$this->assertEquals(['Chris Corbyn <chris@xn--swftmailer-78a.org>'], $header->getAddressStrings());
5656
}
5757

58-
public function testUtf8CharsInLocalPartThrows()
58+
public function testUtf8CharsInLocalPart()
5959
{
60-
$this->expectException('Symfony\Component\Mime\Exception\AddressEncoderException');
6160
$header = new MailboxListHeader('From', [new Address('chrïs@swiftmailer.org', 'Chris Corbyn')]);
62-
$header->getAddressStrings();
61+
$this->assertSame(['Chris Corbyn <chrïs@swiftmailer.org>'], $header->getAddressStrings());
6362
}
6463

6564
public function testGetMailboxesReturnsNameValuePairs()

src/Symfony/Component/Mime/Tests/Header/PathHeaderTest.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,10 @@ public function testAddressIsIdnEncoded()
4949
$this->assertEquals('<chris@xn--swftmailer-78a.org>', $header->getBodyAsString());
5050
}
5151

52-
public function testAddressMustBeEncodable()
52+
public function testAddressMustBeEncodableWithUtf8CharsInLocalPart()
5353
{
54-
$this->expectException('Symfony\Component\Mime\Exception\AddressEncoderException');
5554
$header = new PathHeader('Return-Path', new Address('chrïs@swiftmailer.org'));
56-
$header->getBodyAsString();
55+
$this->assertSame('<chrïs@swiftmailer.org>', $header->getBodyAsString());
5756
}
5857

5958
public function testSetBody()

0 commit comments

Comments
 (0)
0