Skip to content

Commit 63f8827

Browse files
committed
feature symfony#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 | symfony#34932 | License | MIT | Doc PR | - This fixes symfony#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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy