Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 378abfa

Browse files
committed
feature #33424 [Mailer] Change the DSN semantics (fabpot)
This PR was merged into the 4.4 branch. Discussion ---------- [Mailer] Change the DSN semantics | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | no | New feature? | yes | BC breaks? | yes | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tests pass? | yes <!-- please add some, will be required by reviewers --> | Fixed tickets | n/a | License | MIT | Doc PR | symfony/symfony-docs#12258 I'm not very satisfied with the current DSNs for the Mailer. First, the scheme/protocol should use the provider name, then, there is no way to change the host, which would be nice to debug more easily (using a requestb.in service for instance). Before: ``` smtp://USERNAME:PASSWORD@mailgun http://KEY:DOMAIN@mailgun ``` After: ``` mailgun+smtp://USERNAME:PASSWORD@default mailgun+http://KEY:DOMAIN@default # New mailgun+http://KEY:[email protected]:99 ``` SMTP DSNs did not change, but the special sendmail one did: Before: ``` smtp://sendmail ``` After: ``` sendmail+smtp://default ``` And for the `null` transport: Before: ``` smtp://null ``` After: ``` null://null ``` Commits ------- 469c989 [Mailer] Change the DSN semantics
2 parents ef2b65a + 469c989 commit 378abfa

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+704
-187
lines changed

src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Mailer/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ imports:
44

55
framework:
66
mailer:
7-
dsn: 'smtp://null'
7+
dsn: 'null://null'
88
envelope:
99
1010
recipients:
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mailer\Bridge\Amazon\Tests\Transport;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesApiTransport;
16+
17+
class SesApiTransportTest extends TestCase
18+
{
19+
/**
20+
* @dataProvider getTransportData
21+
*/
22+
public function testToString(SesApiTransport $transport, string $expected)
23+
{
24+
$this->assertSame($expected, (string) $transport);
25+
}
26+
27+
public function getTransportData()
28+
{
29+
return [
30+
[
31+
new SesApiTransport('ACCESS_KEY', 'SECRET_KEY'),
32+
'ses+api://[email protected]',
33+
],
34+
[
35+
new SesApiTransport('ACCESS_KEY', 'SECRET_KEY', 'us-east-1'),
36+
'ses+api://[email protected]',
37+
],
38+
[
39+
(new SesApiTransport('ACCESS_KEY', 'SECRET_KEY'))->setHost('example.com'),
40+
'ses+api://[email protected]',
41+
],
42+
[
43+
(new SesApiTransport('ACCESS_KEY', 'SECRET_KEY'))->setHost('example.com')->setPort(99),
44+
'ses+api://[email protected]:99',
45+
],
46+
];
47+
}
48+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mailer\Bridge\Amazon\Tests\Transport;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesHttpTransport;
16+
17+
class SesHttpTransportTest extends TestCase
18+
{
19+
/**
20+
* @dataProvider getTransportData
21+
*/
22+
public function testToString(SesHttpTransport $transport, string $expected)
23+
{
24+
$this->assertSame($expected, (string) $transport);
25+
}
26+
27+
public function getTransportData()
28+
{
29+
return [
30+
[
31+
new SesHttpTransport('ACCESS_KEY', 'SECRET_KEY'),
32+
'ses+https://[email protected]',
33+
],
34+
[
35+
new SesHttpTransport('ACCESS_KEY', 'SECRET_KEY', 'us-east-1'),
36+
'ses+https://[email protected]',
37+
],
38+
[
39+
(new SesHttpTransport('ACCESS_KEY', 'SECRET_KEY'))->setHost('example.com'),
40+
'ses+https://[email protected]',
41+
],
42+
[
43+
(new SesHttpTransport('ACCESS_KEY', 'SECRET_KEY'))->setHost('example.com')->setPort(99),
44+
'ses+https://[email protected]:99',
45+
],
46+
];
47+
}
48+
}

src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesTransportFactoryTest.php

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,33 @@ public function getFactory(): TransportFactoryInterface
2929
public function supportsProvider(): iterable
3030
{
3131
yield [
32-
new Dsn('api', 'ses'),
32+
new Dsn('ses+api', 'default'),
3333
true,
3434
];
3535

3636
yield [
37-
new Dsn('http', 'ses'),
37+
new Dsn('ses+https', 'default'),
3838
true,
3939
];
4040

4141
yield [
42-
new Dsn('smtp', 'ses'),
42+
new Dsn('ses', 'default'),
4343
true,
4444
];
4545

4646
yield [
47-
new Dsn('smtps', 'ses'),
47+
new Dsn('ses+smtp', 'default'),
4848
true,
4949
];
5050

5151
yield [
52-
new Dsn('smtp', 'example.com'),
53-
false,
52+
new Dsn('ses+smtps', 'default'),
53+
true,
54+
];
55+
56+
yield [
57+
new Dsn('ses+smtp', 'example.com'),
58+
true,
5459
];
5560
}
5661

@@ -61,53 +66,68 @@ public function createProvider(): iterable
6166
$logger = $this->getLogger();
6267

6368
yield [
64-
new Dsn('api', 'ses', self::USER, self::PASSWORD),
69+
new Dsn('ses+api', 'default', self::USER, self::PASSWORD),
6570
new SesApiTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
6671
];
6772

6873
yield [
69-
new Dsn('api', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
74+
new Dsn('ses+api', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
7075
new SesApiTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
7176
];
7277

7378
yield [
74-
new Dsn('http', 'ses', self::USER, self::PASSWORD),
79+
new Dsn('ses+api', 'example.com', self::USER, self::PASSWORD, 8080),
80+
(new SesApiTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger))->setHost('example.com')->setPort(8080),
81+
];
82+
83+
yield [
84+
new Dsn('ses+https', 'default', self::USER, self::PASSWORD),
7585
new SesHttpTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
7686
];
7787

7888
yield [
79-
new Dsn('http', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
89+
new Dsn('ses', 'default', self::USER, self::PASSWORD),
90+
new SesHttpTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
91+
];
92+
93+
yield [
94+
new Dsn('ses+https', 'example.com', self::USER, self::PASSWORD, 8080),
95+
(new SesHttpTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger))->setHost('example.com')->setPort(8080),
96+
];
97+
98+
yield [
99+
new Dsn('ses+https', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
80100
new SesHttpTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
81101
];
82102

83103
yield [
84-
new Dsn('smtp', 'ses', self::USER, self::PASSWORD),
104+
new Dsn('ses+smtp', 'default', self::USER, self::PASSWORD),
85105
new SesSmtpTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger),
86106
];
87107

88108
yield [
89-
new Dsn('smtp', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
109+
new Dsn('ses+smtp', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
90110
new SesSmtpTransport(self::USER, self::PASSWORD, 'eu-west-1', $dispatcher, $logger),
91111
];
92112

93113
yield [
94-
new Dsn('smtps', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
114+
new Dsn('ses+smtps', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
95115
new SesSmtpTransport(self::USER, self::PASSWORD, 'eu-west-1', $dispatcher, $logger),
96116
];
97117
}
98118

99119
public function unsupportedSchemeProvider(): iterable
100120
{
101121
yield [
102-
new Dsn('foo', 'ses', self::USER, self::PASSWORD),
103-
'The "foo" scheme is not supported for mailer "ses". Supported schemes are: "api", "http", "smtp", "smtps".',
122+
new Dsn('ses+foo', 'default', self::USER, self::PASSWORD),
123+
'The "ses+foo" scheme is not supported. Supported schemes for mailer "ses" are: "ses", "ses+api", "ses+https", "ses+smtp", "ses+smtps".',
104124
];
105125
}
106126

107127
public function incompleteDsnProvider(): iterable
108128
{
109-
yield [new Dsn('smtp', 'ses', self::USER)];
129+
yield [new Dsn('ses+smtp', 'default', self::USER)];
110130

111-
yield [new Dsn('smtp', 'ses', null, self::PASSWORD)];
131+
yield [new Dsn('ses+smtp', 'default', null, self::PASSWORD)];
112132
}
113133
}

src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesApiTransport.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
*/
2626
class SesApiTransport extends AbstractApiTransport
2727
{
28-
private const ENDPOINT = 'https://email.%region%.amazonaws.com';
28+
private const HOST = 'email.%region%.amazonaws.com';
2929

3030
private $accessKey;
3131
private $secretKey;
@@ -45,16 +45,15 @@ public function __construct(string $accessKey, string $secretKey, string $region
4545

4646
public function __toString(): string
4747
{
48-
return sprintf('api://%s@ses?region=%s', $this->accessKey, $this->region);
48+
return sprintf('ses+api://%s@%s', $this->accessKey, $this->getEndpoint());
4949
}
5050

5151
protected function doSendApi(Email $email, SmtpEnvelope $envelope): ResponseInterface
5252
{
5353
$date = gmdate('D, d M Y H:i:s e');
5454
$auth = sprintf('AWS3-HTTPS AWSAccessKeyId=%s,Algorithm=HmacSHA256,Signature=%s', $this->accessKey, $this->getSignature($date));
5555

56-
$endpoint = str_replace('%region%', $this->region, self::ENDPOINT);
57-
$response = $this->client->request('POST', $endpoint, [
56+
$response = $this->client->request('POST', 'https://'.$this->getEndpoint(), [
5857
'headers' => [
5958
'X-Amzn-Authorization' => $auth,
6059
'Date' => $date,
@@ -72,6 +71,11 @@ protected function doSendApi(Email $email, SmtpEnvelope $envelope): ResponseInte
7271
return $response;
7372
}
7473

74+
private function getEndpoint(): ?string
75+
{
76+
return ($this->host ?: str_replace('%region%', $this->region, self::HOST)).($this->port ? ':'.$this->port : '');
77+
}
78+
7579
private function getSignature(string $string): string
7680
{
7781
return base64_encode(hash_hmac('sha256', $string, $this->secretKey, true));

src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesHttpTransport.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*/
2525
class SesHttpTransport extends AbstractHttpTransport
2626
{
27-
private const ENDPOINT = 'https://email.%region%.amazonaws.com';
27+
private const HOST = 'email.%region%.amazonaws.com';
2828

2929
private $accessKey;
3030
private $secretKey;
@@ -44,16 +44,15 @@ public function __construct(string $accessKey, string $secretKey, string $region
4444

4545
public function __toString(): string
4646
{
47-
return sprintf('http://%s@ses?region=%s', $this->accessKey, $this->region);
47+
return sprintf('ses+https://%s@%s', $this->accessKey, $this->getEndpoint());
4848
}
4949

5050
protected function doSendHttp(SentMessage $message): ResponseInterface
5151
{
5252
$date = gmdate('D, d M Y H:i:s e');
5353
$auth = sprintf('AWS3-HTTPS AWSAccessKeyId=%s,Algorithm=HmacSHA256,Signature=%s', $this->accessKey, $this->getSignature($date));
5454

55-
$endpoint = str_replace('%region%', $this->region, self::ENDPOINT);
56-
$response = $this->client->request('POST', $endpoint, [
55+
$response = $this->client->request('POST', 'https://'.$this->getEndpoint(), [
5756
'headers' => [
5857
'X-Amzn-Authorization' => $auth,
5958
'Date' => $date,
@@ -73,6 +72,11 @@ protected function doSendHttp(SentMessage $message): ResponseInterface
7372
return $response;
7473
}
7574

75+
private function getEndpoint(): ?string
76+
{
77+
return ($this->host ?: str_replace('%region%', $this->region, self::HOST)).($this->port ? ':'.$this->port : '');
78+
}
79+
7680
private function getSignature(string $string): string
7781
{
7882
return base64_encode(hash_hmac('sha256', $string, $this->secretKey, true));

src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesTransportFactory.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,26 @@ public function create(Dsn $dsn): TransportInterface
2727
$user = $this->getUser($dsn);
2828
$password = $this->getPassword($dsn);
2929
$region = $dsn->getOption('region');
30+
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
31+
$port = $dsn->getPort();
3032

31-
if ('api' === $scheme) {
32-
return new SesApiTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
33+
if ('ses+api' === $scheme) {
34+
return (new SesApiTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger))->setHost($host)->setPort($port);
3335
}
3436

35-
if ('http' === $scheme) {
36-
return new SesHttpTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
37+
if ('ses+https' === $scheme || 'ses' === $scheme) {
38+
return (new SesHttpTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger))->setHost($host)->setPort($port);
3739
}
3840

39-
if ('smtp' === $scheme || 'smtps' === $scheme) {
41+
if ('ses+smtp' === $scheme || 'ses+smtps' === $scheme) {
4042
return new SesSmtpTransport($user, $password, $region, $this->dispatcher, $this->logger);
4143
}
4244

43-
throw new UnsupportedSchemeException($dsn, ['api', 'http', 'smtp', 'smtps']);
45+
throw new UnsupportedSchemeException($dsn, 'ses', $this->getSupportedSchemes());
4446
}
4547

46-
public function supports(Dsn $dsn): bool
48+
protected function getSupportedSchemes(): array
4749
{
48-
return 'ses' === $dsn->getHost();
50+
return ['ses', 'ses+api', 'ses+https', 'ses+smtp', 'ses+smtps'];
4951
}
5052
}

0 commit comments

Comments
 (0)