Skip to content

Commit 5396dbf

Browse files
committed
[Mailer] Change the DSN semantics
1 parent ef2b65a commit 5396dbf

33 files changed

+352
-185
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
sender: sender@example.org
1010
recipients:

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+http://%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
}

src/Symfony/Component/Mailer/Bridge/Google/Tests/Transport/GmailTransportFactoryTest.php

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,46 +18,56 @@ public function getFactory(): TransportFactoryInterface
1818
public function supportsProvider(): iterable
1919
{
2020
yield [
21-
new Dsn('smtp', 'gmail'),
21+
new Dsn('gmail', 'default'),
2222
true,
2323
];
2424

2525
yield [
26-
new Dsn('smtps', 'gmail'),
26+
new Dsn('gmail+smtp', 'default'),
2727
true,
2828
];
2929

3030
yield [
31-
new Dsn('smtp', 'example.com'),
32-
false,
31+
new Dsn('gmail+smtps', 'default'),
32+
true,
33+
];
34+
35+
yield [
36+
new Dsn('gmail+smtp', 'example.com'),
37+
true,
3338
];
3439
}
3540

3641
public function createProvider(): iterable
3742
{
3843
yield [
39-
new Dsn('smtp', 'gmail', self::USER, self::PASSWORD),
44+
new Dsn('gmail', 'default', self::USER, self::PASSWORD),
45+
new GmailSmtpTransport(self::USER, self::PASSWORD, $this->getDispatcher(), $this->getLogger()),
46+
];
47+
48+
yield [
49+
new Dsn('gmail+smtp', 'default', self::USER, self::PASSWORD),
4050
new GmailSmtpTransport(self::USER, self::PASSWORD, $this->getDispatcher(), $this->getLogger()),
4151
];
4252

4353
yield [
44-
new Dsn('smtps', 'gmail', self::USER, self::PASSWORD),
54+
new Dsn('gmail+smtps', 'default', self::USER, self::PASSWORD),
4555
new GmailSmtpTransport(self::USER, self::PASSWORD, $this->getDispatcher(), $this->getLogger()),
4656
];
4757
}
4858

4959
public function unsupportedSchemeProvider(): iterable
5060
{
5161
yield [
52-
new Dsn('foo', 'gmail', self::USER, self::PASSWORD),
53-
'The "foo" scheme is not supported for mailer "gmail". Supported schemes are: "smtp", "smtps".',
62+
new Dsn('gmail+foo', 'default', self::USER, self::PASSWORD),
63+
'The "gmail+foo" scheme is not supported. Supported schemes for mailer "gmail" are: "gmail", "gmail+smtp", "gmail+smtps".',
5464
];
5565
}
5666

5767
public function incompleteDsnProvider(): iterable
5868
{
59-
yield [new Dsn('smtp', 'gmail', self::USER)];
69+
yield [new Dsn('gmail+smtp', 'default', self::USER)];
6070

61-
yield [new Dsn('smtp', 'gmail', null, self::PASSWORD)];
71+
yield [new Dsn('gmail+smtp', 'default', null, self::PASSWORD)];
6272
}
6373
}

src/Symfony/Component/Mailer/Bridge/Google/Transport/GmailTransportFactory.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ final class GmailTransportFactory extends AbstractTransportFactory
2323
{
2424
public function create(Dsn $dsn): TransportInterface
2525
{
26-
if ('smtp' === $dsn->getScheme() || 'smtps' === $dsn->getScheme()) {
26+
if (in_array($dsn->getScheme(), $this->getSupportedSchemes())) {
2727
return new GmailSmtpTransport($this->getUser($dsn), $this->getPassword($dsn), $this->dispatcher, $this->logger);
2828
}
2929

30-
throw new UnsupportedSchemeException($dsn, ['smtp', 'smtps']);
30+
throw new UnsupportedSchemeException($dsn, 'gmail', $this->getSupportedSchemes());
3131
}
3232

33-
public function supports(Dsn $dsn): bool
33+
protected function getSupportedSchemes(): array
3434
{
35-
return 'gmail' === $dsn->getHost();
35+
return ['gmail', 'gmail+smtp', 'gmail+smtps'];
3636
}
3737
}

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