From c07f89df7ce799f3a53be9258a8dac17325220c4 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Wed, 8 Sep 2021 16:38:42 +0200 Subject: [PATCH] Implement Message Stream for Postmark Mailer --- .../Transport/PostmarkApiTransportTest.php | 6 ++++- .../Transport/PostmarkSmtpTransportTest.php | 7 ++++-- .../PostmarkTransportFactoryTest.php | 10 ++++++++ .../Transport/MessageStreamHeader.php | 22 +++++++++++++++++ .../Transport/PostmarkApiTransport.php | 24 ++++++++++++++++++- .../Transport/PostmarkSmtpTransport.php | 16 +++++++++++++ .../Transport/PostmarkTransportFactory.php | 15 ++++++++++-- 7 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 src/Symfony/Component/Mailer/Bridge/Postmark/Transport/MessageStreamHeader.php diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php index 760e5a016810a..d6073a65d72c0 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\Mailer\Bridge\Postmark\Transport\MessageStreamHeader; use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkApiTransport; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Exception\HttpTransportException; @@ -123,12 +124,13 @@ public function testSendThrowsForErrorResponse() $transport->send($mail); } - public function testTagAndMetadataHeaders() + public function testTagAndMetadataAndMessageStreamHeaders() { $email = new Email(); $email->getHeaders()->add(new TagHeader('password-reset')); $email->getHeaders()->add(new MetadataHeader('Color', 'blue')); $email->getHeaders()->add(new MetadataHeader('Client-ID', '12345')); + $email->getHeaders()->add(new MessageStreamHeader('broadcasts')); $envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]); $transport = new PostmarkApiTransport('ACCESS_KEY'); @@ -139,8 +141,10 @@ public function testTagAndMetadataHeaders() $this->assertArrayNotHasKey('Headers', $payload); $this->assertArrayHasKey('Tag', $payload); $this->assertArrayHasKey('Metadata', $payload); + $this->assertArrayHasKey('MessageStream', $payload); $this->assertSame('password-reset', $payload['Tag']); $this->assertSame(['Color' => 'blue', 'Client-ID' => '12345'], $payload['Metadata']); + $this->assertSame('broadcasts', $payload['MessageStream']); } } diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkSmtpTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkSmtpTransportTest.php index dff59585a6b85..62836b04fc648 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkSmtpTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkSmtpTransportTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Mailer\Bridge\Postmark\Tests\Transport; use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\Bridge\Postmark\Transport\MessageStreamHeader; use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkSmtpTransport; use Symfony\Component\Mailer\Header\MetadataHeader; use Symfony\Component\Mailer\Header\TagHeader; @@ -34,24 +35,26 @@ public function testCustomHeader() $this->assertSame('foo: bar', $email->getHeaders()->get('FOO')->toString()); } - public function testTagAndMetadataHeaders() + public function testTagAndMetadataAndMessageStreamHeaders() { $email = new Email(); $email->getHeaders()->addTextHeader('foo', 'bar'); $email->getHeaders()->add(new TagHeader('password-reset')); $email->getHeaders()->add(new MetadataHeader('Color', 'blue')); $email->getHeaders()->add(new MetadataHeader('Client-ID', '12345')); + $email->getHeaders()->add(new MessageStreamHeader('broadcasts')); $transport = new PostmarkSmtpTransport('ACCESS_KEY'); $method = new \ReflectionMethod(PostmarkSmtpTransport::class, 'addPostmarkHeaders'); $method->setAccessible(true); $method->invoke($transport, $email); - $this->assertCount(5, $email->getHeaders()->toArray()); + $this->assertCount(6, $email->getHeaders()->toArray()); $this->assertSame('foo: bar', $email->getHeaders()->get('FOO')->toString()); $this->assertSame('X-PM-KeepID: true', $email->getHeaders()->get('X-PM-KeepID')->toString()); $this->assertSame('X-PM-Tag: password-reset', $email->getHeaders()->get('X-PM-Tag')->toString()); $this->assertSame('X-PM-Metadata-Color: blue', $email->getHeaders()->get('X-PM-Metadata-Color')->toString()); $this->assertSame('X-PM-Metadata-Client-ID: 12345', $email->getHeaders()->get('X-PM-Metadata-Client-ID')->toString()); + $this->assertSame('X-PM-Message-Stream: broadcasts', $email->getHeaders()->get('X-PM-Message-Stream')->toString()); } } diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkTransportFactoryTest.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkTransportFactoryTest.php index 2959cd3a4188f..d6d3263c5c760 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkTransportFactoryTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkTransportFactoryTest.php @@ -68,6 +68,11 @@ public function createProvider(): iterable (new PostmarkApiTransport(self::USER, $this->getClient(), $dispatcher, $logger))->setHost('example.com')->setPort(8080), ]; + yield [ + new Dsn('postmark+api', 'example.com', self::USER, '', 8080, ['message_stream' => 'broadcasts']), + (new PostmarkApiTransport(self::USER, $this->getClient(), $dispatcher, $logger))->setHost('example.com')->setPort(8080)->setMessageStream('broadcasts'), + ]; + yield [ new Dsn('postmark', 'default', self::USER), new PostmarkSmtpTransport(self::USER, $dispatcher, $logger), @@ -82,6 +87,11 @@ public function createProvider(): iterable new Dsn('postmark+smtps', 'default', self::USER), new PostmarkSmtpTransport(self::USER, $dispatcher, $logger), ]; + + yield [ + new Dsn('postmark+smtps', 'default', self::USER, null, null, ['message_stream' => 'broadcasts']), + (new PostmarkSmtpTransport(self::USER, $dispatcher, $logger))->setMessageStream('broadcasts'), + ]; } public function unsupportedSchemeProvider(): iterable diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/MessageStreamHeader.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/MessageStreamHeader.php new file mode 100644 index 0000000000000..01a4d7baf3014 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/MessageStreamHeader.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Postmark\Transport; + +use Symfony\Component\Mime\Header\UnstructuredHeader; + +final class MessageStreamHeader extends UnstructuredHeader +{ + public function __construct(string $value) + { + parent::__construct('X-PM-Message-Stream', $value); + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php index 8b37241d62753..05efdc9266def 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php @@ -34,6 +34,8 @@ class PostmarkApiTransport extends AbstractApiTransport private $key; + private $messageStream; + public function __construct(string $key, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { $this->key = $key; @@ -43,7 +45,7 @@ public function __construct(string $key, HttpClientInterface $client = null, Eve public function __toString(): string { - return sprintf('postmark+api://%s', $this->getEndpoint()); + return sprintf('postmark+api://%s', $this->getEndpoint()).($this->messageStream ? '?message_stream='.$this->messageStream : ''); } protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $envelope): ResponseInterface @@ -106,12 +108,22 @@ private function getPayload(Email $email, Envelope $envelope): array continue; } + if ($header instanceof MessageStreamHeader) { + $payload['MessageStream'] = $header->getValue(); + + continue; + } + $payload['Headers'][] = [ 'Name' => $name, 'Value' => $header->getBodyAsString(), ]; } + if (null !== $this->messageStream && !isset($payload['MessageStream'])) { + $payload['MessageStream'] = $this->messageStream; + } + return $payload; } @@ -143,4 +155,14 @@ private function getEndpoint(): ?string { return ($this->host ?: self::HOST).($this->port ? ':'.$this->port : ''); } + + /** + * @return $this + */ + public function setMessageStream(string $messageStream): self + { + $this->messageStream = $messageStream; + + return $this; + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php index 0a02a86b7cad0..54e7b206bfaec 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php @@ -26,6 +26,8 @@ */ class PostmarkSmtpTransport extends EsmtpTransport { + private $messageStream; + public function __construct(string $id, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { parent::__construct('smtp.postmarkapp.com', 587, false, $dispatcher, $logger); @@ -60,5 +62,19 @@ private function addPostmarkHeaders(Message $message): void $headers->remove($name); } } + + if (null !== $this->messageStream && !$message->getHeaders()->has('X-PM-Message-Stream')) { + $headers->addTextHeader('X-PM-Message-Stream', $this->messageStream); + } + } + + /** + * @return $this + */ + public function setMessageStream(string $messageStream): self + { + $this->messageStream = $messageStream; + + return $this; } } diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkTransportFactory.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkTransportFactory.php index 983f41a4503e8..20728986c4b8d 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkTransportFactory.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkTransportFactory.php @@ -23,6 +23,7 @@ final class PostmarkTransportFactory extends AbstractTransportFactory { public function create(Dsn $dsn): TransportInterface { + $transport = null; $scheme = $dsn->getScheme(); $user = $this->getUser($dsn); @@ -30,11 +31,21 @@ public function create(Dsn $dsn): TransportInterface $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); $port = $dsn->getPort(); - return (new PostmarkApiTransport($user, $this->client, $this->dispatcher, $this->logger))->setHost($host)->setPort($port); + $transport = (new PostmarkApiTransport($user, $this->client, $this->dispatcher, $this->logger))->setHost($host)->setPort($port); } if ('postmark+smtp' === $scheme || 'postmark+smtps' === $scheme || 'postmark' === $scheme) { - return new PostmarkSmtpTransport($user, $this->dispatcher, $this->logger); + $transport = new PostmarkSmtpTransport($user, $this->dispatcher, $this->logger); + } + + if (null !== $transport) { + $messageStream = $dsn->getOption('message_stream'); + + if (null !== $messageStream) { + $transport->setMessageStream($messageStream); + } + + return $transport; } throw new UnsupportedSchemeException($dsn, 'postmark', $this->getSupportedSchemes());