diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillApiTransportTest.php index af4cdbeebe..cc84e53f30 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillApiTransportTest.php @@ -14,6 +14,8 @@ namespace Symfony\Component\Mailer\Bridge\Mailchimp\Tests\Transport; use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Bridge\Mailchimp\Transport\MandrillApiTransport; use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Email; @@ -61,4 +63,42 @@ class MandrillApiTransportTest extends TestCase $this->assertCount(1, $payload['message']['headers']); $this->assertEquals('foo: bar', $payload['message']['headers'][0]); } + + public function testTagAndMetadataHeaders() + { + $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')); + $envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]); + + $transport = new MandrillApiTransport('ACCESS_KEY'); + $method = new \ReflectionMethod(MandrillApiTransport::class, 'getPayload'); + $method->setAccessible(true); + $payload = $method->invoke($transport, $email, $envelope); + + $this->assertArrayHasKey('message', $payload); + $this->assertArrayNotHasKey('headers', $payload['message']); + $this->assertArrayHasKey('tags', $payload['message']); + $this->assertSame(['password-reset'], $payload['message']['tags']); + $this->assertArrayHasKey('metadata', $payload['message']); + $this->assertSame(['Color' => 'blue', 'Client-ID' => '12345'], $payload['message']['metadata']); + } + + public function testCanHaveMultipleTags() + { + $email = new Email(); + $email->getHeaders()->add(new TagHeader('password-reset,user')); + $envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]); + + $transport = new MandrillApiTransport('ACCESS_KEY'); + $method = new \ReflectionMethod(MandrillApiTransport::class, 'getPayload'); + $method->setAccessible(true); + $payload = $method->invoke($transport, $email, $envelope); + + $this->assertArrayHasKey('message', $payload); + $this->assertArrayNotHasKey('headers', $payload['message']); + $this->assertArrayHasKey('tags', $payload['message']); + $this->assertSame(['password-reset', 'user'], $payload['message']['tags']); + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php index dd72c848f1..6220054471 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillHttpTransportTest.php @@ -13,6 +13,9 @@ namespace Symfony\Component\Mailer\Bridge\Mailchimp\Tests\Transport; use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Bridge\Mailchimp\Transport\MandrillHttpTransport; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; +use Symfony\Component\Mime\Email; class MandrillHttpTransportTest extends TestCase { @@ -41,4 +44,23 @@ class MandrillHttpTransportTest extends TestCase ], ]; } + + public function testTagAndMetadataHeaders() + { + $email = new Email(); + $email->getHeaders()->addTextHeader('foo', 'bar'); + $email->getHeaders()->add(new TagHeader('password-reset,user')); + $email->getHeaders()->add(new MetadataHeader('Color', 'blue')); + $email->getHeaders()->add(new MetadataHeader('Client-ID', '12345')); + + $transport = new MandrillHttpTransport('key'); + $method = new \ReflectionMethod(MandrillHttpTransport::class, 'addMandrillHeaders'); + $method->setAccessible(true); + $method->invoke($transport, $email); + + $this->assertCount(3, $email->getHeaders()->toArray()); + $this->assertSame('foo: bar', $email->getHeaders()->get('FOO')->toString()); + $this->assertSame('X-MC-Tags: password-reset,user', $email->getHeaders()->get('X-MC-Tags')->toString()); + $this->assertSame('X-MC-Metadata: '.json_encode(['Color' => 'blue', 'Client-ID' => '12345']), $email->getHeaders()->get('X-MC-Metadata')->toString()); + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillSmtpTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillSmtpTransportTest.php new file mode 100644 index 0000000000..c6ed7cd988 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillSmtpTransportTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Mailchimp\Tests\Transport; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\Bridge\Mailchimp\Transport\MandrillSmtpTransport; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; +use Symfony\Component\Mime\Email; + +class MandrillSmtpTransportTest extends TestCase +{ + public function testTagAndMetadataHeaders() + { + $email = new Email(); + $email->getHeaders()->addTextHeader('foo', 'bar'); + $email->getHeaders()->add(new TagHeader('password-reset,user')); + $email->getHeaders()->add(new MetadataHeader('Color', 'blue')); + $email->getHeaders()->add(new MetadataHeader('Client-ID', '12345')); + + $transport = new MandrillSmtpTransport('user', 'password'); + $method = new \ReflectionMethod(MandrillSmtpTransport::class, 'addMandrillHeaders'); + $method->setAccessible(true); + $method->invoke($transport, $email); + + $this->assertCount(3, $email->getHeaders()->toArray()); + $this->assertSame('foo: bar', $email->getHeaders()->get('FOO')->toString()); + $this->assertSame('X-MC-Tags: password-reset,user', $email->getHeaders()->get('X-MC-Tags')->toString()); + $this->assertSame('X-MC-Metadata: '.json_encode(['Color' => 'blue', 'Client-ID' => '12345']), $email->getHeaders()->get('X-MC-Metadata')->toString()); + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php index af221ca66e..067d124a86 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php @@ -14,6 +14,8 @@ namespace Symfony\Component\Mailer\Bridge\Mailchimp\Transport; use Psr\Log\LoggerInterface; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Exception\HttpTransportException; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\AbstractApiTransport; use Symfony\Component\Mime\Email; @@ -111,6 +113,18 @@ class MandrillApiTransport extends AbstractApiTransport continue; } + if ($header instanceof TagHeader) { + $payload['message']['tags'] = explode(',', $header->getValue()); + + continue; + } + + if ($header instanceof MetadataHeader) { + $payload['message']['metadata'][$header->getKey()] = $header->getValue(); + + continue; + } + $payload['message']['headers'][] = $name.': '.$header->getBodyAsString(); } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHeadersTrait.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHeadersTrait.php new file mode 100644 index 0000000000..2ca440560a --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHeadersTrait.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Mailchimp\Transport; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Kevin Bond + */ +trait MandrillHeadersTrait +{ + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage + { + if ($message instanceof Message) { + $this->addMandrillHeaders($message); + } + + return parent::send($message, $envelope); + } + + private function addMandrillHeaders(Message $message): void + { + $headers = $message->getHeaders(); + $metadata = []; + + foreach ($headers->all() as $name => $header) { + if ($header instanceof TagHeader) { + $headers->addTextHeader('X-MC-Tags', $header->getValue()); + $headers->remove($name); + } elseif ($header instanceof MetadataHeader) { + $metadata[$header->getKey()] = $header->getValue(); + $headers->remove($name); + } + } + + if ($metadata) { + $headers->addTextHeader('X-MC-Metadata', json_encode($metadata)); + } + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php index 17f7a7fcf3..01282f897f 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillHttpTransport.php @@ -24,6 +24,8 @@ use Symfony\Contracts\HttpClient\ResponseInterface; */ class MandrillHttpTransport extends AbstractHttpTransport { + use MandrillHeadersTrait; + private const HOST = 'mandrillapp.com'; private $key; diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillSmtpTransport.php index 72d2e8a51a..c1e1ae3b0e 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillSmtpTransport.php @@ -20,6 +20,8 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; */ class MandrillSmtpTransport extends EsmtpTransport { + use MandrillHeadersTrait; + public function __construct(string $username, string $password, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { parent::__construct('smtp.mandrillapp.com', 587, true, $dispatcher, $logger); diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/composer.json b/src/Symfony/Component/Mailer/Bridge/Mailchimp/composer.json index 4ed93da850..97aa19aabf 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/composer.json +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.2.5", - "symfony/mailer": "^4.4|^5.0" + "symfony/mailer": "^5.1" }, "require-dev": { "symfony/http-client": "^4.4|^5.0" diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php index f30fa0285c..6de53b9ccb 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php @@ -14,6 +14,8 @@ namespace Symfony\Component\Mailer\Bridge\Mailgun\Tests\Transport; use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunApiTransport; use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Email; @@ -64,4 +66,29 @@ class MailgunApiTransportTest extends TestCase $this->assertArrayHasKey('h:x-mailgun-variables', $payload); $this->assertEquals($json, $payload['h:x-mailgun-variables']); } + + public function testTagAndMetadataHeaders() + { + $json = json_encode(['foo' => 'bar']); + $email = new Email(); + $email->getHeaders()->addTextHeader('X-Mailgun-Variables', $json); + $email->getHeaders()->add(new TagHeader('password-reset')); + $email->getHeaders()->add(new MetadataHeader('Color', 'blue')); + $email->getHeaders()->add(new MetadataHeader('Client-ID', '12345')); + $envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]); + + $transport = new MailgunApiTransport('ACCESS_KEY', 'DOMAIN'); + $method = new \ReflectionMethod(MailgunApiTransport::class, 'getPayload'); + $method->setAccessible(true); + $payload = $method->invoke($transport, $email, $envelope); + + $this->assertArrayHasKey('h:x-mailgun-variables', $payload); + $this->assertEquals($json, $payload['h:x-mailgun-variables']); + $this->assertArrayHasKey('o:tag', $payload); + $this->assertSame('password-reset', $payload['o:tag']); + $this->assertArrayHasKey('v:Color', $payload); + $this->assertSame('blue', $payload['v:Color']); + $this->assertArrayHasKey('v:Client-ID', $payload); + $this->assertSame('12345', $payload['v:Client-ID']); + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunHttpTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunHttpTransportTest.php index 9b57b2b35e..14130b0df2 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunHttpTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunHttpTransportTest.php @@ -13,6 +13,9 @@ namespace Symfony\Component\Mailer\Bridge\Mailgun\Tests\Transport; use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunHttpTransport; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; +use Symfony\Component\Mime\Email; class MailgunHttpTransportTest extends TestCase { @@ -45,4 +48,23 @@ class MailgunHttpTransportTest extends TestCase ], ]; } + + public function testTagAndMetadataHeaders() + { + $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')); + + $transport = new MailgunHttpTransport('key', 'domain'); + $method = new \ReflectionMethod(MailgunHttpTransport::class, 'addMailgunHeaders'); + $method->setAccessible(true); + $method->invoke($transport, $email); + + $this->assertCount(3, $email->getHeaders()->toArray()); + $this->assertSame('foo: bar', $email->getHeaders()->get('foo')->toString()); + $this->assertSame('X-Mailgun-Tag: password-reset', $email->getHeaders()->get('X-Mailgun-Tag')->toString()); + $this->assertSame('X-Mailgun-Variables: '.json_encode(['Color' => 'blue', 'Client-ID' => '12345']), $email->getHeaders()->get('X-Mailgun-Variables')->toString()); + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunSmtpTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunSmtpTransportTest.php new file mode 100644 index 0000000000..89712064b3 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunSmtpTransportTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Mailgun\Tests\Transport; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunSmtpTransport; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; +use Symfony\Component\Mime\Email; + +/** + * @author Kevin Bond + */ +class MailgunSmtpTransportTest extends TestCase +{ + public function testTagAndMetadataHeaders() + { + $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')); + + $transport = new MailgunSmtpTransport('user', 'password'); + $method = new \ReflectionMethod(MailgunSmtpTransport::class, 'addMailgunHeaders'); + $method->setAccessible(true); + $method->invoke($transport, $email); + + $this->assertCount(3, $email->getHeaders()->toArray()); + $this->assertSame('foo: bar', $email->getHeaders()->get('foo')->toString()); + $this->assertSame('X-Mailgun-Tag: password-reset', $email->getHeaders()->get('X-Mailgun-Tag')->toString()); + $this->assertSame('X-Mailgun-Variables: '.json_encode(['Color' => 'blue', 'Client-ID' => '12345']), $email->getHeaders()->get('X-Mailgun-Variables')->toString()); + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php index cf40a8cf1e..105a155e57 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php @@ -14,6 +14,8 @@ namespace Symfony\Component\Mailer\Bridge\Mailgun\Transport; use Psr\Log\LoggerInterface; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Exception\HttpTransportException; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\AbstractApiTransport; use Symfony\Component\Mime\Email; @@ -114,6 +116,18 @@ class MailgunApiTransport extends AbstractApiTransport continue; } + if ($header instanceof TagHeader) { + $payload['o:tag'] = $header->getValue(); + + continue; + } + + if ($header instanceof MetadataHeader) { + $payload['v:'.$header->getKey()] = $header->getValue(); + + continue; + } + $payload['h:'.$name] = $header->getBodyAsString(); } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHeadersTrait.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHeadersTrait.php new file mode 100644 index 0000000000..9d1603960e --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHeadersTrait.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Mailgun\Transport; + +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Kevin Bond + */ +trait MailgunHeadersTrait +{ + public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage + { + if ($message instanceof Message) { + $this->addMailgunHeaders($message); + } + + return parent::send($message, $envelope); + } + + private function addMailgunHeaders(Message $message): void + { + $headers = $message->getHeaders(); + $metadata = []; + + foreach ($headers->all() as $name => $header) { + if ($header instanceof TagHeader) { + $headers->addTextHeader('X-Mailgun-Tag', $header->getValue()); + $headers->remove($name); + } elseif ($header instanceof MetadataHeader) { + $metadata[$header->getKey()] = $header->getValue(); + $headers->remove($name); + } + } + + if ($metadata) { + $headers->addTextHeader('X-Mailgun-Variables', json_encode($metadata)); + } + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php index a42598a0b5..0c314ba0ad 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php @@ -26,6 +26,8 @@ use Symfony\Contracts\HttpClient\ResponseInterface; */ class MailgunHttpTransport extends AbstractHttpTransport { + use MailgunHeadersTrait; + private const HOST = 'api.%region_dot%mailgun.net'; private $key; diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunSmtpTransport.php index 824cd48b03..f48156c3f8 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunSmtpTransport.php @@ -20,6 +20,8 @@ use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; */ class MailgunSmtpTransport extends EsmtpTransport { + use MailgunHeadersTrait; + public function __construct(string $username, string $password, string $region = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { parent::__construct('us' !== ($region ?: 'us') ? sprintf('smtp.%s.mailgun.org', $region) : 'smtp.mailgun.org', 465, true, $dispatcher, $logger); diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json b/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json index c3a2608563..35e6a433af 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.2.5", - "symfony/mailer": "^4.4|^5.0" + "symfony/mailer": "^5.1" }, "require-dev": { "symfony/http-client": "^4.4|^5.0" 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 6996997b65..6af12ac911 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,8 @@ namespace Symfony\Component\Mailer\Bridge\Postmark\Tests\Transport; use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkApiTransport; use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Email; @@ -61,4 +63,25 @@ class PostmarkApiTransportTest extends TestCase $this->assertEquals(['Name' => 'foo', 'Value' => 'bar'], $payload['Headers'][0]); } + + public function testTagAndMetadataHeaders() + { + $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')); + $envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]); + + $transport = new PostmarkApiTransport('ACCESS_KEY'); + $method = new \ReflectionMethod(PostmarkApiTransport::class, 'getPayload'); + $method->setAccessible(true); + $payload = $method->invoke($transport, $email, $envelope); + + $this->assertArrayNotHasKey('Headers', $payload); + $this->assertArrayHasKey('Tag', $payload); + $this->assertArrayHasKey('Metadata', $payload); + + $this->assertSame('password-reset', $payload['Tag']); + $this->assertSame(['Color' => 'blue', 'Client-ID' => '12345'], $payload['Metadata']); + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkSmtpTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkSmtpTransportTest.php new file mode 100644 index 0000000000..dff59585a6 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkSmtpTransportTest.php @@ -0,0 +1,57 @@ + + * + * 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\Tests\Transport; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkSmtpTransport; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; +use Symfony\Component\Mime\Email; + +class PostmarkSmtpTransportTest extends TestCase +{ + public function testCustomHeader() + { + $email = new Email(); + $email->getHeaders()->addTextHeader('foo', 'bar'); + + $transport = new PostmarkSmtpTransport('ACCESS_KEY'); + $method = new \ReflectionMethod(PostmarkSmtpTransport::class, 'addPostmarkHeaders'); + $method->setAccessible(true); + $method->invoke($transport, $email); + + $this->assertCount(2, $email->getHeaders()->toArray()); + $this->assertSame('X-PM-KeepID: true', $email->getHeaders()->get('X-PM-KeepID')->toString()); + $this->assertSame('foo: bar', $email->getHeaders()->get('FOO')->toString()); + } + + public function testTagAndMetadataHeaders() + { + $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')); + + $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->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()); + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php index 610f858260..7a9b47bc56 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php @@ -14,6 +14,8 @@ namespace Symfony\Component\Mailer\Bridge\Postmark\Transport; use Psr\Log\LoggerInterface; use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mailer\Exception\HttpTransportException; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\AbstractApiTransport; use Symfony\Component\Mime\Email; @@ -82,6 +84,18 @@ class PostmarkApiTransport extends AbstractApiTransport continue; } + if ($header instanceof TagHeader) { + $payload['Tag'] = $header->getValue(); + + continue; + } + + if ($header instanceof MetadataHeader) { + $payload['Metadata'][$header->getKey()] = $header->getValue(); + + continue; + } + $payload['Headers'][] = [ 'Name' => $name, 'Value' => $header->getBodyAsString(), diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php index b6d9ba2827..5017bea7a0 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php @@ -13,6 +13,8 @@ namespace Symfony\Component\Mailer\Bridge\Postmark\Transport; use Psr\Log\LoggerInterface; use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Header\MetadataHeader; +use Symfony\Component\Mailer\Header\TagHeader; use Symfony\Component\Mailer\SentMessage; use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; use Symfony\Component\Mime\Message; @@ -35,9 +37,28 @@ class PostmarkSmtpTransport extends EsmtpTransport public function send(RawMessage $message, Envelope $envelope = null): ?SentMessage { if ($message instanceof Message) { - $message->getHeaders()->addTextHeader('X-PM-KeepID', 'true'); + $this->addPostmarkHeaders($message); } return parent::send($message, $envelope); } + + private function addPostmarkHeaders(Message $message): void + { + $message->getHeaders()->addTextHeader('X-PM-KeepID', 'true'); + + $headers = $message->getHeaders(); + + foreach ($headers->all() as $name => $header) { + if ($header instanceof TagHeader) { + $headers->addTextHeader('X-PM-Tag', $header->getValue()); + $headers->remove($name); + } + + if ($header instanceof MetadataHeader) { + $headers->addTextHeader('X-PM-Metadata-'.$header->getKey(), $header->getValue()); + $headers->remove($name); + } + } + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/composer.json b/src/Symfony/Component/Mailer/Bridge/Postmark/composer.json index cf0219083b..1681f86210 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/composer.json +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.2.5", - "symfony/mailer": "^4.4|^5.0" + "symfony/mailer": "^5.1" }, "require-dev": { "symfony/http-client": "^4.4|^5.0" diff --git a/src/Symfony/Component/Mailer/Header/MetadataHeader.php b/src/Symfony/Component/Mailer/Header/MetadataHeader.php new file mode 100644 index 0000000000..d56acb16b0 --- /dev/null +++ b/src/Symfony/Component/Mailer/Header/MetadataHeader.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Header; + +use Symfony\Component\Mime\Header\UnstructuredHeader; + +/** + * @author Kevin Bond + */ +final class MetadataHeader extends UnstructuredHeader +{ + private $key; + + public function __construct(string $key, string $value) + { + $this->key = $key; + + parent::__construct('X-Metadata-'.$key, $value); + } + + public function getKey(): string + { + return $this->key; + } +} diff --git a/src/Symfony/Component/Mailer/Header/TagHeader.php b/src/Symfony/Component/Mailer/Header/TagHeader.php new file mode 100644 index 0000000000..7115caebeb --- /dev/null +++ b/src/Symfony/Component/Mailer/Header/TagHeader.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Header; + +use Symfony\Component\Mime\Header\UnstructuredHeader; + +/** + * @author Kevin Bond + */ +final class TagHeader extends UnstructuredHeader +{ + public function __construct(string $value) + { + parent::__construct('X-Tag', $value); + } +}