[Mailer] Use AsyncAws to handle SES requests

This commit is contained in:
Jérémy Derussé 2020-03-15 23:41:30 +01:00 committed by Fabien Potencier
parent c6cf433589
commit 21243874bc
15 changed files with 504 additions and 26 deletions

View File

@ -72,6 +72,8 @@ Mailer
------
* Deprecated passing Mailgun headers without their "h:" prefix.
* Deprecated the `SesApiTransport` class. It has been replaced by SesApiAsyncAwsTransport Run `composer require async-aws/ses` to use the new classes.
* Deprecated the `SesHttpTransport` class. It has been replaced by SesHttpAsyncAwsTransport Run `composer require async-aws/ses` to use the new classes.
Messenger
---------

View File

@ -64,6 +64,13 @@ HttpKernel
* Made `WarmableInterface::warmUp()` return a list of classes or files to preload on PHP 7.4+
* Removed support for `service:action` syntax to reference controllers. Use `serviceOrFqcn::method` instead.
Mailer
------
* Removed the `SesApiTransport` class. Use `SesApiAsyncAwsTransport` instead.
* Removed the `SesHttpTransport` class. Use `SesHttpAsyncAwsTransport` instead.
Messenger
---------

View File

@ -104,6 +104,7 @@
"require-dev": {
"amphp/http-client": "^4.2",
"amphp/http-tunnel": "^1.0",
"async-aws/ses": "^1.0",
"cache/integration-tests": "dev-master",
"doctrine/annotations": "~1.0",
"doctrine/cache": "~1.6",

View File

@ -1,6 +1,11 @@
CHANGELOG
=========
5.1.0
-----
* Added `async-aws/ses` to communicate with AWS API.
4.4.0
-----

View File

@ -0,0 +1,120 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Amazon\Tests\Transport;
use AsyncAws\Core\Configuration;
use AsyncAws\Core\Credentials\NullProvider;
use AsyncAws\Ses\SesClient;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesApiAsyncAwsTransport;
use Symfony\Component\Mailer\Exception\HttpTransportException;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Contracts\HttpClient\ResponseInterface;
class SesApiAsyncAwsTransportTest extends TestCase
{
/**
* @dataProvider getTransportData
*/
public function testToString(SesApiAsyncAwsTransport $transport, string $expected)
{
$this->assertSame($expected, (string) $transport);
}
public function getTransportData()
{
return [
[
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY']))),
'ses+api://ACCESS_KEY@us-east-1',
],
[
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1']))),
'ses+api://ACCESS_KEY@us-west-1',
],
[
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com']))),
'ses+api://ACCESS_KEY@example.com',
],
[
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99']))),
'ses+api://ACCESS_KEY@example.com:99',
],
];
}
public function testSend()
{
$client = new MockHttpClient(function (string $method, string $url, array $options): ResponseInterface {
$this->assertSame('POST', $method);
$this->assertSame('https://email.us-east-1.amazonaws.com/v2/email/outbound-emails', $url);
$content = json_decode($options['body'], true);
$this->assertSame('Hello!', $content['Content']['Simple']['Subject']['Data']);
$this->assertSame('Saif Eddin <saif.gmati@symfony.com>', $content['Destination']['ToAddresses'][0]);
$this->assertSame('Fabien <fabpot@symfony.com>', $content['FromEmailAddress']);
$this->assertSame('Hello There!', $content['Content']['Simple']['Body']['Text']['Data']);
$this->assertSame('<b>Hello There!</b>', $content['Content']['Simple']['Body']['Html']['Data']);
$json = '{"MessageId": "foobar"}';
return new MockResponse($json, [
'http_code' => 200,
]);
});
$transport = new SesApiAsyncAwsTransport(new SesClient(Configuration::create([]), new NullProvider(), $client));
$mail = new Email();
$mail->subject('Hello!')
->to(new Address('saif.gmati@symfony.com', 'Saif Eddin'))
->from(new Address('fabpot@symfony.com', 'Fabien'))
->text('Hello There!')
->html('<b>Hello There!</b>');
$message = $transport->send($mail);
$this->assertSame('foobar', $message->getMessageId());
}
public function testSendThrowsForErrorResponse()
{
$client = new MockHttpClient(function (string $method, string $url, array $options): ResponseInterface {
$xml = "<SendEmailResponse xmlns=\"https://email.amazonaws.com/doc/2010-03-31/\">
<Error>
<Message>i'm a teapot</Message>
<Code>418</Code>
</Error>
</SendEmailResponse>";
return new MockResponse($xml, [
'http_code' => 418,
]);
});
$transport = new SesApiAsyncAwsTransport(new SesClient(Configuration::create([]), new NullProvider(), $client));
$mail = new Email();
$mail->subject('Hello!')
->to(new Address('saif.gmati@symfony.com', 'Saif Eddin'))
->from(new Address('fabpot@symfony.com', 'Fabien'))
->text('Hello There!');
$this->expectException(HttpTransportException::class);
$this->expectExceptionMessage('Unable to send an email: i\'m a teapot (code 418).');
$transport->send($mail);
}
}

View File

@ -20,6 +20,9 @@ use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* @group legacy
*/
class SesApiTransportTest extends TestCase
{
/**

View File

@ -0,0 +1,119 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Amazon\Tests\Transport;
use AsyncAws\Core\Configuration;
use AsyncAws\Core\Credentials\NullProvider;
use AsyncAws\Ses\SesClient;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesHttpAsyncAwsTransport;
use Symfony\Component\Mailer\Exception\HttpTransportException;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Contracts\HttpClient\ResponseInterface;
class SesHttpAsyncAwsTransportTest extends TestCase
{
/**
* @dataProvider getTransportData
*/
public function testToString(SesHttpAsyncAwsTransport $transport, string $expected)
{
$this->assertSame($expected, (string) $transport);
}
public function getTransportData()
{
return [
[
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY']))),
'ses+https://ACCESS_KEY@us-east-1',
],
[
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1']))),
'ses+https://ACCESS_KEY@us-west-1',
],
[
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com']))),
'ses+https://ACCESS_KEY@example.com',
],
[
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99']))),
'ses+https://ACCESS_KEY@example.com:99',
],
];
}
public function testSend()
{
$client = new MockHttpClient(function (string $method, string $url, array $options): ResponseInterface {
$this->assertSame('POST', $method);
$this->assertSame('https://email.us-east-1.amazonaws.com/v2/email/outbound-emails', $url);
$body = json_decode($options['body'], true);
$content = base64_decode($body['Content']['Raw']['Data']);
$this->assertStringContainsString('Hello!', $content);
$this->assertStringContainsString('Saif Eddin <saif.gmati@symfony.com>', $content);
$this->assertStringContainsString('Fabien <fabpot@symfony.com>', $content);
$this->assertStringContainsString('Hello There!', $content);
$json = '{"MessageId": "foobar"}';
return new MockResponse($json, [
'http_code' => 200,
]);
});
$transport = new SesHttpAsyncAwsTransport(new SesClient(Configuration::create([]), new NullProvider(), $client));
$mail = new Email();
$mail->subject('Hello!')
->to(new Address('saif.gmati@symfony.com', 'Saif Eddin'))
->from(new Address('fabpot@symfony.com', 'Fabien'))
->text('Hello There!');
$message = $transport->send($mail);
$this->assertSame('foobar', $message->getMessageId());
}
public function testSendThrowsForErrorResponse()
{
$client = new MockHttpClient(function (string $method, string $url, array $options): ResponseInterface {
$xml = "<SendEmailResponse xmlns=\"https://email.amazonaws.com/doc/2010-03-31/\">
<Error>
<Message>i'm a teapot</Message>
<Code>418</Code>
</Error>
</SendEmailResponse>";
return new MockResponse($xml, [
'http_code' => 418,
]);
});
$transport = new SesHttpAsyncAwsTransport(new SesClient(Configuration::create([]), new NullProvider(), $client));
$mail = new Email();
$mail->subject('Hello!')
->to(new Address('saif.gmati@symfony.com', 'Saif Eddin'))
->from(new Address('fabpot@symfony.com', 'Fabien'))
->text('Hello There!');
$this->expectException(HttpTransportException::class);
$this->expectExceptionMessage('Unable to send an email: i\'m a teapot (code 418).');
$transport->send($mail);
}
}

View File

@ -20,6 +20,9 @@ use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* @group legacy
*/
class SesHttpTransportTest extends TestCase
{
/**

View File

@ -11,8 +11,10 @@
namespace Symfony\Component\Mailer\Bridge\Amazon\Tests\Transport;
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesApiTransport;
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesHttpTransport;
use AsyncAws\Core\Configuration;
use AsyncAws\Ses\SesClient;
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesApiAsyncAwsTransport;
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesHttpAsyncAwsTransport;
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesSmtpTransport;
use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesTransportFactory;
use Symfony\Component\Mailer\Test\TransportFactoryTestCase;
@ -67,37 +69,37 @@ class SesTransportFactoryTest extends TransportFactoryTestCase
yield [
new Dsn('ses+api', 'default', self::USER, self::PASSWORD),
new SesApiTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-1']), null, $client, $logger), $dispatcher, $logger),
];
yield [
new Dsn('ses+api', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
new SesApiTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
new Dsn('ses+api', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-2']),
new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-2']), null, $client, $logger), $dispatcher, $logger),
];
yield [
new Dsn('ses+api', 'example.com', self::USER, self::PASSWORD, 8080),
(new SesApiTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger))->setHost('example.com')->setPort(8080),
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),
];
yield [
new Dsn('ses+https', 'default', self::USER, self::PASSWORD),
new SesHttpTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-1']), null, $client, $logger), $dispatcher, $logger),
];
yield [
new Dsn('ses', 'default', self::USER, self::PASSWORD),
new SesHttpTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger),
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-1']), null, $client, $logger), $dispatcher, $logger),
];
yield [
new Dsn('ses+https', 'example.com', self::USER, self::PASSWORD, 8080),
(new SesHttpTransport(self::USER, self::PASSWORD, null, $client, $dispatcher, $logger))->setHost('example.com')->setPort(8080),
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),
];
yield [
new Dsn('ses+https', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
new SesHttpTransport(self::USER, self::PASSWORD, 'eu-west-1', $client, $dispatcher, $logger),
new Dsn('ses+https', 'default', self::USER, self::PASSWORD, null, ['region' => 'eu-west-2']),
new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => self::USER, 'accessKeySecret' => self::PASSWORD, 'region' => 'eu-west-2']), null, $client, $logger), $dispatcher, $logger),
];
yield [
@ -127,7 +129,5 @@ class SesTransportFactoryTest extends TransportFactoryTestCase
public function incompleteDsnProvider(): iterable
{
yield [new Dsn('ses+smtp', 'default', self::USER)];
yield [new Dsn('ses+smtp', 'default', null, self::PASSWORD)];
}
}

View File

@ -0,0 +1,101 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Amazon\Transport;
use AsyncAws\Ses\Input\SendEmailRequest;
use AsyncAws\Ses\ValueObject\Content;
use Symfony\Component\Mailer\Envelope;
use Symfony\Component\Mailer\Exception\RuntimeException;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\MessageConverter;
/**
* @author Jérémy Derussé <jeremy@derusse.com>
*/
class SesApiAsyncAwsTransport extends SesHttpAsyncAwsTransport
{
public function __toString(): string
{
$configuration = $this->sesClient->getConfiguration();
if (!$configuration->isDefault('endpoint')) {
$endpoint = parse_url($configuration->get('endpoint'));
$host = $endpoint['host'].($endpoint['port'] ?? null ? ':'.$endpoint['port'] : '');
} else {
$host = $configuration->get('region');
}
return sprintf('ses+api://%s@%s', $configuration->get('accessKeyId'), $host);
}
protected function getRequest(SentMessage $message): SendEmailRequest
{
try {
$email = MessageConverter::toEmail($message->getOriginalMessage());
} catch (\Exception $e) {
throw new RuntimeException(sprintf('Unable to send message with the "%s" transport: "%s".', __CLASS__, $e->getMessage()), 0, $e);
}
if ($email->getAttachments()) {
return parent::getRequest($message);
}
$envelope = $message->getEnvelope();
$request = [
'FromEmailAddress' => $envelope->getSender()->toString(),
'Destination' => [
'ToAddresses' => $this->stringifyAddresses($this->getRecipients($email, $envelope)),
],
'Content' => [
'Simple' => [
'Subject' => [
'Data' => $email->getSubject(),
'Charset' => 'utf-8',
],
'Body' => [],
],
],
];
if ($emails = $email->getCc()) {
$request['Destination']['CcAddresses'] = $this->stringifyAddresses($emails);
}
if ($emails = $email->getBcc()) {
$request['Destination']['BccAddresses'] = $this->stringifyAddresses($emails);
}
if ($email->getTextBody()) {
$request['Content']['Simple']['Body']['Text'] = new Content([
'Data' => $email->getTextBody(),
'Charset' => $email->getTextCharset(),
]);
}
if ($email->getHtmlBody()) {
$request['Content']['Simple']['Body']['Html'] = new Content([
'Data' => $email->getHtmlBody(),
'Charset' => $email->getHtmlCharset(),
]);
}
return new SendEmailRequest($request);
}
private function getRecipients(Email $email, Envelope $envelope): array
{
$emailRecipients = array_merge($email->getCc(), $email->getBcc());
return array_filter($envelope->getRecipients(), function (Address $address) use ($emailRecipients) {
return !\in_array($address, $emailRecipients, true);
});
}
}

View File

@ -21,6 +21,8 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
trigger_deprecation('symfony/amazon-mailer', '5.1', 'The "%s" class is deprecated, use "%s" instead. The Amazon transport now requires "AsyncAws". Run "composer require async-aws/ses".', SesApiTransport::class, SesApiAsyncAwsTransport::class);
/**
* @author Kevin Verschaeve
*/

View File

@ -0,0 +1,81 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Mailer\Bridge\Amazon\Transport;
use AsyncAws\Core\Exception\Http\HttpException;
use AsyncAws\Ses\Input\SendEmailRequest;
use AsyncAws\Ses\SesClient;
use AsyncAws\Ses\ValueObject\Destination;
use Psr\Log\LoggerInterface;
use Symfony\Component\Mailer\Exception\HttpTransportException;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Transport\AbstractTransport;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
/**
* @author Jérémy Derussé <jeremy@derusse.com>
*/
class SesHttpAsyncAwsTransport extends AbstractTransport
{
/** @var SesClient */
protected $sesClient;
public function __construct(SesClient $sesClient, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null)
{
$this->sesClient = $sesClient;
parent::__construct($dispatcher, $logger);
}
public function __toString(): string
{
$configuration = $this->sesClient->getConfiguration();
if (!$configuration->isDefault('endpoint')) {
$endpoint = parse_url($configuration->get('endpoint'));
$host = $endpoint['host'].($endpoint['port'] ?? null ? ':'.$endpoint['port'] : '');
} else {
$host = $configuration->get('region');
}
return sprintf('ses+https://%s@%s', $configuration->get('accessKeyId'), $host);
}
protected function doSend(SentMessage $message): void
{
$result = $this->sesClient->sendEmail($this->getRequest($message));
$response = $result->info()['response'];
try {
$message->setMessageId($result->getMessageId());
$message->appendDebug($response->getInfo('debug') ?? '');
} catch (HttpException $e) {
$exception = new HttpTransportException(sprintf('Unable to send an email: %s (code %s).', $e->getAwsMessage() ?: $e->getMessage(), $e->getAwsCode() ?: $e->getCode()), $e->getResponse(), $e->getCode(), $e);
$exception->appendDebug($e->getResponse()->getInfo('debug') ?? '');
throw $exception;
}
}
protected function getRequest(SentMessage $message): SendEmailRequest
{
return new SendEmailRequest([
'Destination' => $destination = new Destination([
'ToAddresses' => $this->stringifyAddresses($message->getEnvelope()->getRecipients()),
]),
'Content' => [
'Raw' => [
'Data' => $message->toString(),
],
],
]);
}
}

View File

@ -19,6 +19,8 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\Contracts\HttpClient\ResponseInterface;
trigger_deprecation('symfony/amazon-mailer', '5.1', 'The "%s" class is deprecated, use "%s" instead. The Amazon transport now requires "AsyncAws". Run "composer require async-aws/ses".', SesHttpTransport::class, SesHttpAsyncAwsTransport::class);
/**
* @author Kevin Verschaeve
*/

View File

@ -11,6 +11,9 @@
namespace Symfony\Component\Mailer\Bridge\Amazon\Transport;
use AsyncAws\Core\Configuration;
use AsyncAws\Ses\SesClient;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
use Symfony\Component\Mailer\Transport\AbstractTransportFactory;
use Symfony\Component\Mailer\Transport\Dsn;
@ -18,28 +21,55 @@ use Symfony\Component\Mailer\Transport\TransportInterface;
/**
* @author Konstantin Myakshin <molodchick@gmail.com>
* @author Jérémy Derussé <jeremy@derusse.com>
*/
final class SesTransportFactory extends AbstractTransportFactory
{
public function create(Dsn $dsn): TransportInterface
{
$scheme = $dsn->getScheme();
$user = $this->getUser($dsn);
$password = $this->getPassword($dsn);
$region = $dsn->getOption('region');
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort();
if ('ses+api' === $scheme) {
return (new SesApiTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger))->setHost($host)->setPort($port);
}
if ('ses+https' === $scheme || 'ses' === $scheme) {
return (new SesHttpTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger))->setHost($host)->setPort($port);
}
if ('ses+smtp' === $scheme || 'ses+smtps' === $scheme) {
return new SesSmtpTransport($user, $password, $region, $this->dispatcher, $this->logger);
return new SesSmtpTransport($this->getUser($dsn), $this->getPassword($dsn), $region, $this->dispatcher, $this->logger);
}
if (!class_exists(SesClient::class)) {
if (!class_exists(HttpClient::class)) {
throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component or AsyncAws package is not installed. Try running "composer require async-aws/ses".', __CLASS__));
}
trigger_deprecation('symfony/amazon-mailer', '5.1', 'Using the "%s" transport without AsyncAws is deprecated. Try running "composer require async-aws/ses".', $scheme, \get_called_class());
$user = $this->getUser($dsn);
$password = $this->getPassword($dsn);
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
$port = $dsn->getPort();
if ('ses+api' === $scheme) {
return (new SesApiTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger))->setHost($host)->setPort($port);
}
if ('ses+https' === $scheme || 'ses' === $scheme) {
return (new SesHttpTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger))->setHost($host)->setPort($port);
}
} else {
switch ($scheme) {
case 'ses+api':
$class = SesApiAsyncAwsTransport::class;
// no break
case 'ses':
case 'ses+https':
$class = $class ?? SesHttpAsyncAwsTransport::class;
$options = [
'region' => $dsn->getOption('region') ?: 'eu-west-1',
'accessKeyId' => $dsn->getUser(),
'accessKeySecret' => $dsn->getPassword(),
] + (
'default' === $dsn->getHost() ? [] : ['endpoint' => 'https://'.$dsn->getHost().($dsn->getPort() ? ':'.$dsn->getPort() : '')]
);
return new $class(new SesClient(Configuration::create($options), null, $this->client, $this->logger), $this->dispatcher, $this->logger);
}
}
throw new UnsupportedSchemeException($dsn, 'ses', $this->getSupportedSchemes());

View File

@ -17,9 +17,11 @@
],
"require": {
"php": "^7.2.5",
"symfony/deprecation-contracts": "^2.1",
"symfony/mailer": "^4.4|^5.0"
},
"require-dev": {
"async-aws/ses": "^1.0",
"symfony/http-client": "^4.4|^5.0"
},
"autoload": {