From 128ab66d407561f218dbc84ce89d0a73c97b192f Mon Sep 17 00:00:00 2001 From: Christophe Deliens Date: Fri, 16 Dec 2022 12:21:00 +0100 Subject: [PATCH 1/5] :recycle: Adapt ApiTransport to allow the region or the host to be specified --- src/Transport/SparkPostApiTransport.php | 27 ++++++++++++------ tests/Transport/SparkPostApiTransportTest.php | 28 +++++++++++++++++-- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/Transport/SparkPostApiTransport.php b/src/Transport/SparkPostApiTransport.php index 30c0256..329369e 100644 --- a/src/Transport/SparkPostApiTransport.php +++ b/src/Transport/SparkPostApiTransport.php @@ -21,16 +21,21 @@ class SparkPostApiTransport extends AbstractApiTransport */ private $key; - public function __construct(string $key, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + public function __construct(string $key, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null, ?string $region = null, string $host = 'default') { $this->key = $key; + if ('default' === $host) { + $host = \sprintf('api%s.sparkpost.com', $region ? '.'.$region : ''); + } + $this->host = $host; + parent::__construct($client, $dispatcher, $logger); } public function __toString(): string { - return 'sparkpost+api://'; + return \sprintf('sparkpost+api://%s', $this->host); } protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $envelope): ResponseInterface @@ -52,13 +57,17 @@ protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $e $this->log($payload); - $response = $this->client->request('POST', 'https://api.sparkpost.com/api/v1/transmissions/', [ - 'headers' => [ - 'Authorization' => $this->key, - 'Content-Type' => 'application/json', - ], - 'json' => $payload, - ]); + $response = $this->client->request( + 'POST', + \sprintf('https://%s/api/v1/transmissions/', $this->host), + [ + 'headers' => [ + 'Authorization' => $this->key, + 'Content-Type' => 'application/json', + ], + 'json' => $payload, + ] + ); $this->handleError($response); diff --git a/tests/Transport/SparkPostApiTransportTest.php b/tests/Transport/SparkPostApiTransportTest.php index 5687aa4..be5e884 100644 --- a/tests/Transport/SparkPostApiTransportTest.php +++ b/tests/Transport/SparkPostApiTransportTest.php @@ -251,11 +251,14 @@ public function testTruncateAttachmentData(): void $transport->send($this->createDefaultMessage(), $this->createDefaultEnvelope()); } - public function testToString() + /** + * @dataProvider dataToString + */ + public function testToString(?string $region, ?string $host, string $endpoint) { $client = $this->createMock(HttpClientInterface::class); - $transport = new SparkPostApiTransport('api-key', $client); - self::assertSame('sparkpost+api://', (string) $transport); + $transport = new SparkPostApiTransport('api-key', $client, null, null, $region, $host); + self::assertSame('sparkpost+api://' . $endpoint, (string) $transport); } /** @@ -325,4 +328,23 @@ public function dataNotSuccess() '[{"message":"error 0"},{"message":"error 1"}]', ]; } + + public function dataToString(): iterable + { + yield [ + null, 'default', 'api.sparkpost.com', + ]; + + yield [ + 'eu', 'default', 'api.eu.sparkpost.com', + ]; + + yield [ + 'eu', 'example.com', 'example.com', + ]; + + yield [ + null, 'example.com', 'example.com', + ]; + } } From cc8df4ac16bb1f8d5e6d7d7f3d92dec38c9837a1 Mon Sep 17 00:00:00 2001 From: Christophe Deliens Date: Fri, 16 Dec 2022 12:37:29 +0100 Subject: [PATCH 2/5] :recycle: Adapt SmtpTransport to allow the region or the host to be specified --- src/Transport/SparkPostSmtpTransport.php | 7 +- .../Transport/SparkPostSmtpTransportTest.php | 70 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 tests/Transport/SparkPostSmtpTransportTest.php diff --git a/src/Transport/SparkPostSmtpTransport.php b/src/Transport/SparkPostSmtpTransport.php index c78fcbb..be9a92f 100644 --- a/src/Transport/SparkPostSmtpTransport.php +++ b/src/Transport/SparkPostSmtpTransport.php @@ -8,9 +8,12 @@ class SparkPostSmtpTransport extends EsmtpTransport { - public function __construct(string $username, string $password, int $port = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + public function __construct(string $username, string $password, int $port = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null, ?string $region = null, string $host = 'default') { - parent::__construct('smtp.sparkpostmail.com', $port ?: 587, false, $dispatcher, $logger); + if ('default' === $host) { + $host = \sprintf('smtp%s.sparkpostmail.com', $region ? '.'.$region : ''); + } + parent::__construct($host, $port ?: 587, false, $dispatcher, $logger); $this->setUsername($username); $this->setPassword($password); diff --git a/tests/Transport/SparkPostSmtpTransportTest.php b/tests/Transport/SparkPostSmtpTransportTest.php new file mode 100644 index 0000000..f2ecba5 --- /dev/null +++ b/tests/Transport/SparkPostSmtpTransportTest.php @@ -0,0 +1,70 @@ + Date: Fri, 16 Dec 2022 12:50:51 +0100 Subject: [PATCH 3/5] :recycle: Adapt the factory to allow the region or the host to be specified --- src/Transport/SparkPostTransportFactory.php | 16 +++--- .../SparkPostTransportFactoryTest.php | 54 ++++++++++++++++--- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/Transport/SparkPostTransportFactory.php b/src/Transport/SparkPostTransportFactory.php index 1a33045..d5f8c67 100644 --- a/src/Transport/SparkPostTransportFactory.php +++ b/src/Transport/SparkPostTransportFactory.php @@ -14,15 +14,17 @@ public function create(Dsn $dsn): TransportInterface $scheme = $dsn->getScheme(); $user = $this->getUser($dsn); $port = $dsn->getPort(); + $region = $dsn->getOption('region'); - if ('sparkpost+api' === $scheme) { - return new SparkPostApiTransport($user, $this->client, $this->dispatcher, $this->logger); - } - - if (in_array($scheme, ['sparkpost', 'sparkpost+smtp', 'sparkpost+smtps'])) { - $password = $this->getPassword($dsn); + switch (true) { + case 'sparkpost+api' === $scheme: + return new SparkPostApiTransport($user, $this->client, $this->dispatcher, $this->logger, $region, $dsn->getHost()); - return new SparkPostSmtpTransport($user, $password, $port, $this->dispatcher, $this->logger); + case 'sparkpost' === $scheme: + case 'sparkpost+smtp' === $scheme: + case 'sparkpost+smtps' === $scheme: + $password = $this->getPassword($dsn); + return new SparkPostSmtpTransport($user, $password, $port, $this->dispatcher, $this->logger, $region, $dsn->getHost()); } throw new UnsupportedSchemeException($dsn, 'sparkpost', $this->getSupportedSchemes()); diff --git a/tests/Transport/SparkPostTransportFactoryTest.php b/tests/Transport/SparkPostTransportFactoryTest.php index 28e2492..d25b2b8 100644 --- a/tests/Transport/SparkPostTransportFactoryTest.php +++ b/tests/Transport/SparkPostTransportFactoryTest.php @@ -26,16 +26,31 @@ public function supportsProvider(): iterable true, ]; + yield [ + new Dsn('sparkpost', 'example.com'), + true, + ]; + yield [ new Dsn('sparkpost+api', 'default'), true, ]; + yield [ + new Dsn('sparkpost+api', 'example.com'), + true, + ]; + yield [ new Dsn('sparkpost+https', 'default'), false, ]; + yield [ + new Dsn('sparkpost+https', 'example.com'), + false, + ]; + yield [ new Dsn('sparkpost+smtp', 'default'), true, @@ -64,19 +79,46 @@ public function createProvider(): iterable ]; yield [ - new Dsn('sparkpost', 'default', self::USER, self::PASSWORD), - new SparkPostSmtpTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger), + new Dsn('sparkpost+api', 'default', self::USER, null, null, ['region' => 'eu']), + new SparkPostApiTransport(self::USER, $client, $dispatcher, $logger, 'eu'), + ]; + + yield [ + new Dsn('sparkpost+api', 'example.com', self::USER), + new SparkPostApiTransport(self::USER, $client, $dispatcher, $logger, null, 'example.com'), ]; yield [ - new Dsn('sparkpost+smtp', 'default', self::USER, self::PASSWORD, 587), - new SparkPostSmtpTransport(self::USER, self::PASSWORD, 587, $dispatcher, $logger), + new Dsn('sparkpost+api', 'example.com', self::USER, null, null, ['region' => 'eu']), + new SparkPostApiTransport(self::USER, $client, $dispatcher, $logger, 'eu', 'example.com'), ]; yield [ - new Dsn('sparkpost+smtps', 'default', self::USER, self::PASSWORD, 2525), - new SparkPostSmtpTransport(self::USER, self::PASSWORD, 2525, $dispatcher, $logger), + new Dsn('sparkpost', 'default', self::USER, self::PASSWORD), + new SparkPostSmtpTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger), ]; + + foreach (['sparkpost', 'sparkpost+smtp', 'sparkpost+smtps'] as $scheme) { + yield [ + new Dsn($scheme, 'default', self::USER, self::PASSWORD, null, ['region' => 'eu']), + new SparkPostSmtpTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger, 'eu'), + ]; + + yield [ + new Dsn($scheme, 'example.com', self::USER, self::PASSWORD), + new SparkPostSmtpTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger, null, 'example.com'), + ]; + + yield [ + new Dsn($scheme, 'example.com', self::USER, self::PASSWORD, null, ['region' => 'eu']), + new SparkPostSmtpTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger, 'eu', 'example.com'), + ]; + + yield [ + new Dsn($scheme, 'example.com', self::USER, self::PASSWORD, 1111, ['region' => 'eu']), + new SparkPostSmtpTransport(self::USER, self::PASSWORD, 1111, $dispatcher, $logger, 'eu', 'example.com'), + ]; + } } public function unsupportedSchemeProvider(): iterable From 2289191f6f7e3148f5c27368b4f360d14c080c09 Mon Sep 17 00:00:00 2001 From: Christophe Deliens Date: Fri, 16 Dec 2022 13:00:34 +0100 Subject: [PATCH 4/5] :memo: Update README about the EU region settings --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 56b1c57..df899cc 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ composer require gam6itko/sparkpost-mailer ## configuration -services.yaml +### services.yaml ```yaml services: mailer.transport_factory.sparkpost: @@ -20,7 +20,10 @@ services: - {name: mailer.transport_factory} ``` -.env +### .env + +#### Default region + ```dotenv MAILER_DSN=sparkpost+api://api_key@default ``` @@ -28,6 +31,15 @@ MAILER_DSN=sparkpost+api://api_key@default MAILER_DSN=sparkpost+smtp://user:password@default:port ``` +#### EU region + +```dotenv +MAILER_DSN=sparkpost+api://api_key@default?region=eu +``` +```dotenv +MAILER_DSN=sparkpost+smtp://user:password@default:port?region=eu +``` + ## tests ### Using sink server From 729a17a122c8e6ddb5296d256ea65e69e065934b Mon Sep 17 00:00:00 2001 From: Christophe Deliens Date: Fri, 16 Dec 2022 13:03:19 +0100 Subject: [PATCH 5/5] :memo: Normalise titles and update "sink server" link --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index df899cc..b506dd5 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ [![Build Status](https://travis-ci.com/gam6itko/sparkpost-mailer.svg?branch=master)](https://travis-ci.com/gam6itko/sparkpost-mailer) [![Coverage Status](https://coveralls.io/repos/github/gam6itko/sparkpost-mailer/badge.svg?branch=master)](https://coveralls.io/github/gam6itko/sparkpost-mailer?branch=master) -## install +## Installation ```bash composer require gam6itko/sparkpost-mailer ``` -## configuration +## Configuration ### services.yaml ```yaml @@ -40,10 +40,10 @@ MAILER_DSN=sparkpost+api://api_key@default?region=eu MAILER_DSN=sparkpost+smtp://user:password@default:port?region=eu ``` -## tests +## Tests ### Using sink server -[About sink server](https://www.sparkpost.com/docs/faq/using-sink-server/) +[About sink server](https://support.sparkpost.com/docs/faq/using-sink-server) ```yaml services: @@ -53,4 +53,4 @@ services: ## Also -[Api transmissions](https://developers.sparkpost.com/api/transmissions/) +[Sparkpost's "transmissions" API reference](https://developers.sparkpost.com/api/transmissions/)