Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b9a1428

Browse filesBrowse files
committed
[AmazonMailer] Add adapter for AsyncAws and deprecate HttpClient impl
1 parent 7c90c8b commit b9a1428
Copy full SHA for b9a1428

13 files changed

+500
-25
lines changed

‎UPGRADE-5.1.md

Copy file name to clipboardExpand all lines: UPGRADE-5.1.md
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ HttpFoundation
3838
`__construct()` instead)
3939
* Made the Mime component an optional dependency
4040

41+
Mailer
42+
------
43+
44+
* Deprecated the `SesApiTransport` class. It has been replaced by SesApiAsyncAwsTransport Run `composer require async-aws/ses` to use the new classes.
45+
* Deprecated the `SesHttpTransport` class. It has been replaced by SesHttpAsyncAwsTransport Run `composer require async-aws/ses` to use the new classes.
46+
4147
Messenger
4248
---------
4349

‎UPGRADE-6.0.md

Copy file name to clipboardExpand all lines: UPGRADE-6.0.md
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ HttpFoundation
3535
`RedirectResponse::create()`, and `StreamedResponse::create()` methods (use
3636
`__construct()` instead)
3737

38+
Mailer
39+
------
40+
41+
* Removed the `SesApiTransport` class. Run `composer require async-aws/ses` to keep the transport in your application.
42+
* Removed the `SesHttpTransport` class. Run `composer require async-aws/ses` to keep the transport in your application.
43+
3844
Messenger
3945
---------
4046

‎composer.json

Copy file name to clipboardExpand all lines: composer.json
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@
126126
"phpdocumentor/reflection-docblock": "^3.0|^4.0",
127127
"twig/cssinliner-extra": "^2.12",
128128
"twig/inky-extra": "^2.12",
129-
"twig/markdown-extra": "^2.12"
129+
"twig/markdown-extra": "^2.12",
130+
"async-aws/ses": "^0.3"
130131
},
131132
"conflict": {
132133
"masterminds/html5": "<2.6",

‎src/Symfony/Component/Mailer/Bridge/Amazon/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Mailer/Bridge/Amazon/CHANGELOG.md
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
5.1.0
5+
-----
6+
7+
* Added `async-aws/ses` to communicate with AWS API.
8+
49
4.4.0
510
-----
611

+117Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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 AsyncAws\Core\Configuration;
15+
use AsyncAws\Ses\SesClient;
16+
use PHPUnit\Framework\TestCase;
17+
use Symfony\Component\HttpClient\MockHttpClient;
18+
use Symfony\Component\HttpClient\Response\MockResponse;
19+
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesApiAsyncAwsTransport;
20+
use Symfony\Component\Mailer\Exception\HttpTransportException;
21+
use Symfony\Component\Mime\Address;
22+
use Symfony\Component\Mime\Email;
23+
use Symfony\Contracts\HttpClient\ResponseInterface;
24+
25+
class SesApiAsyncAwsTransportTest extends TestCase
26+
{
27+
/**
28+
* @dataProvider getTransportData
29+
*/
30+
public function testToString(SesApiAsyncAwsTransport $transport, string $expected)
31+
{
32+
$this->assertSame($expected, (string) $transport);
33+
}
34+
35+
public function getTransportData()
36+
{
37+
return [
38+
[
39+
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY']))),
40+
'ses+api://ACCESS_KEY@us-east-1',
41+
],
42+
[
43+
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1']))),
44+
'ses+api://ACCESS_KEY@us-west-1',
45+
],
46+
[
47+
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com']))),
48+
'ses+api://ACCESS_KEY@example.com',
49+
],
50+
[
51+
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99']))),
52+
'ses+api://ACCESS_KEY@example.com:99',
53+
],
54+
];
55+
}
56+
57+
public function testSend()
58+
{
59+
$client = new MockHttpClient(function (string $method, string $url, array $options): ResponseInterface {
60+
$this->assertSame('POST', $method);
61+
$this->assertSame('https://email.us-east-1.amazonaws.com/v2/email/outbound-emails', $url);
62+
63+
$content = json_decode($options['body'](), true);
64+
65+
$this->assertSame('Hello!', $content['Content']['Simple']['Subject']['Data']);
66+
$this->assertSame('Saif Eddin <saif.gmati@symfony.com>', $content['Destination']['ToAddresses'][0]);
67+
$this->assertSame('Fabien <fabpot@symfony.com>', $content['FromEmailAddress']);
68+
$this->assertSame('Hello There!', $content['Content']['Simple']['Body']['Text']['Data']);
69+
70+
$json = '{"MessageId": "foobar"}';
71+
72+
return new MockResponse($json, [
73+
'http_code' => 200,
74+
]);
75+
});
76+
77+
$transport = new SesApiAsyncAwsTransport(new SesClient(Configuration::create([]), null, $client));
78+
79+
$mail = new Email();
80+
$mail->subject('Hello!')
81+
->to(new Address('saif.gmati@symfony.com', 'Saif Eddin'))
82+
->from(new Address('fabpot@symfony.com', 'Fabien'))
83+
->text('Hello There!');
84+
85+
$message = $transport->send($mail);
86+
87+
$this->assertSame('foobar', $message->getMessageId());
88+
}
89+
90+
public function testSendThrowsForErrorResponse()
91+
{
92+
$client = new MockHttpClient(function (string $method, string $url, array $options): ResponseInterface {
93+
$xml = "<SendEmailResponse xmlns=\"https://email.amazonaws.com/doc/2010-03-31/\">
94+
<Error>
95+
<Message>i'm a teapot</Message>
96+
<Code>418</Code>
97+
</Error>
98+
</SendEmailResponse>";
99+
100+
return new MockResponse($xml, [
101+
'http_code' => 418,
102+
]);
103+
});
104+
105+
$transport = new SesApiAsyncAwsTransport(new SesClient(Configuration::create([]), null, $client));
106+
107+
$mail = new Email();
108+
$mail->subject('Hello!')
109+
->to(new Address('saif.gmati@symfony.com', 'Saif Eddin'))
110+
->from(new Address('fabpot@symfony.com', 'Fabien'))
111+
->text('Hello There!');
112+
113+
$this->expectException(HttpTransportException::class);
114+
$this->expectExceptionMessage('Unable to send an email: i\'m a teapot (code 418).');
115+
$transport->send($mail);
116+
}
117+
}
+118Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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 AsyncAws\Core\Configuration;
15+
use AsyncAws\Ses\SesClient;
16+
use PHPUnit\Framework\TestCase;
17+
use Symfony\Component\HttpClient\MockHttpClient;
18+
use Symfony\Component\HttpClient\Response\MockResponse;
19+
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesHttpAsyncAwsTransport;
20+
use Symfony\Component\Mailer\Exception\HttpTransportException;
21+
use Symfony\Component\Mime\Address;
22+
use Symfony\Component\Mime\Email;
23+
use Symfony\Contracts\HttpClient\ResponseInterface;
24+
25+
class SesHttpAsyncAwsTransportTest extends TestCase
26+
{
27+
/**
28+
* @dataProvider getTransportData
29+
*/
30+
public function testToString(SesHttpAsyncAwsTransport $transport, string $expected)
31+
{
32+
$this->assertSame($expected, (string) $transport);
33+
}
34+
35+
public function getTransportData()
36+
{
37+
return [
38+
[
39+
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY']))),
40+
'ses+https://ACCESS_KEY@us-east-1',
41+
],
42+
[
43+
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1']))),
44+
'ses+https://ACCESS_KEY@us-west-1',
45+
],
46+
[
47+
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com']))),
48+
'ses+https://ACCESS_KEY@example.com',
49+
],
50+
[
51+
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99']))),
52+
'ses+https://ACCESS_KEY@example.com:99',
53+
],
54+
];
55+
}
56+
57+
public function testSend()
58+
{
59+
$client = new MockHttpClient(function (string $method, string $url, array $options): ResponseInterface {
60+
$this->assertSame('POST', $method);
61+
$this->assertSame('https://email.us-east-1.amazonaws.com/v2/email/outbound-emails', $url);
62+
63+
$body = json_decode($options['body'](), true);
64+
$content = base64_decode($body['Content']['Raw']['Data']);
65+
66+
$this->assertStringContainsString('Hello!', $content);
67+
$this->assertStringContainsString('Saif Eddin <saif.gmati@symfony.com>', $content);
68+
$this->assertStringContainsString('Fabien <fabpot@symfony.com>', $content);
69+
$this->assertStringContainsString('Hello There!', $content);
70+
71+
$json = '{"MessageId": "foobar"}';
72+
73+
return new MockResponse($json, [
74+
'http_code' => 200,
75+
]);
76+
});
77+
78+
$transport = new SesHttpAsyncAwsTransport(new SesClient(Configuration::create([]), null, $client));
79+
80+
$mail = new Email();
81+
$mail->subject('Hello!')
82+
->to(new Address('saif.gmati@symfony.com', 'Saif Eddin'))
83+
->from(new Address('fabpot@symfony.com', 'Fabien'))
84+
->text('Hello There!');
85+
86+
$message = $transport->send($mail);
87+
88+
$this->assertSame('foobar', $message->getMessageId());
89+
}
90+
91+
public function testSendThrowsForErrorResponse()
92+
{
93+
$client = new MockHttpClient(function (string $method, string $url, array $options): ResponseInterface {
94+
$xml = "<SendEmailResponse xmlns=\"https://email.amazonaws.com/doc/2010-03-31/\">
95+
<Error>
96+
<Message>i'm a teapot</Message>
97+
<Code>418</Code>
98+
</Error>
99+
</SendEmailResponse>";
100+
101+
return new MockResponse($xml, [
102+
'http_code' => 418,
103+
]);
104+
});
105+
106+
$transport = new SesHttpAsyncAwsTransport(new SesClient(Configuration::create([]), null, $client));
107+
108+
$mail = new Email();
109+
$mail->subject('Hello!')
110+
->to(new Address('saif.gmati@symfony.com', 'Saif Eddin'))
111+
->from(new Address('fabpot@symfony.com', 'Fabien'))
112+
->text('Hello There!');
113+
114+
$this->expectException(HttpTransportException::class);
115+
$this->expectExceptionMessage('Unable to send an email: i\'m a teapot (code 418).');
116+
$transport->send($mail);
117+
}
118+
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesTransportFactoryTest.php
+13-13Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
namespace Symfony\Component\Mailer\Bridge\Amazon\Tests\Transport;
1313

14-
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesApiTransport;
15-
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesHttpTransport;
14+
use AsyncAws\Core\Configuration;
15+
use AsyncAws\Ses\SesClient;
16+
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesApiAsyncAwsTransport;
17+
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesHttpAsyncAwsTransport;
1618
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesSmtpTransport;
1719
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesTransportFactory;
1820
use Symfony\Component\Mailer\Test\TransportFactoryTestCase;
@@ -67,37 +69,37 @@ public function createProvider(): iterable
6769

6870
yield [
6971
new Dsn('ses+api', 'default', self::USER, self::PASSWORD),
70-
new SesApiTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
72+
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-1']), null, $client, $logger), $dispatcher, $logger),
7173
];
7274

7375
yield [
74-
new Dsn('ses+api', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
75-
new SesApiTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
76+
new Dsn('ses+api', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-2']),
77+
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-2']), null, $client, $logger), $dispatcher, $logger),
7678
];
7779

7880
yield [
7981
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),
82+
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-1', 'endpoint' => 'https://example.com:8080']), null, $client, $logger), $dispatcher, $logger),
8183
];
8284

8385
yield [
8486
new Dsn('ses+https', 'default', self::USER, self::PASSWORD),
85-
new SesHttpTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
87+
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-1']), null, $client, $logger), $dispatcher, $logger),
8688
];
8789

8890
yield [
8991
new Dsn('ses', 'default', self::USER, self::PASSWORD),
90-
new SesHttpTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
92+
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-1']), null, $client, $logger), $dispatcher, $logger),
9193
];
9294

9395
yield [
9496
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),
97+
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-1', 'endpoint' => 'https://example.com:8080']), null, $client, $logger), $dispatcher, $logger),
9698
];
9799

98100
yield [
99-
new Dsn('ses+https', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
100-
new SesHttpTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
101+
new Dsn('ses+https', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-2']),
102+
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-2']), null, $client, $logger), $dispatcher, $logger),
101103
];
102104

103105
yield [
@@ -127,7 +129,5 @@ public function unsupportedSchemeProvider(): iterable
127129
public function incompleteDsnProvider(): iterable
128130
{
129131
yield [new Dsn('ses+smtp', 'default', self::USER)];
130-
131-
yield [new Dsn('ses+smtp', 'default', null, self::PASSWORD)];
132132
}
133133
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.