From 5b8c4676d05987ce5346fdbf44fcac6654bc39c1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 19 Aug 2019 09:22:00 +0200 Subject: [PATCH] [Mailer] simplified the way TLS/SSL/StartTls work --- .../Transport/SesTransportFactoryTest.php | 12 +++++- .../Amazon/Transport/SesSmtpTransport.php | 2 +- .../Amazon/Transport/SesTransportFactory.php | 4 +- .../Transport/GmailTransportFactoryTest.php | 12 +++++- .../Google/Transport/GmailSmtpTransport.php | 2 +- .../Transport/GmailTransportFactory.php | 4 +- .../MandrillTransportFactoryTest.php | 12 +++++- .../Transport/MandrillSmtpTransport.php | 2 +- .../Transport/MandrillTransportFactory.php | 4 +- .../Transport/MailgunTransportFactoryTest.php | 12 +++++- .../Transport/MailgunSmtpTransport.php | 2 +- .../Transport/MailgunTransportFactory.php | 4 +- .../PostmarkTransportFactoryTest.php | 12 +++++- .../Transport/PostmarkSmtpTransport.php | 2 +- .../Transport/PostmarkTransportFactory.php | 4 +- .../SendgridTransportFactoryTest.php | 12 +++++- .../Transport/SendgridSmtpTransport.php | 2 +- .../Transport/SendgridTransportFactory.php | 4 +- src/Symfony/Component/Mailer/CHANGELOG.md | 3 ++ .../Mailer/Test/TransportFactoryTestCase.php | 2 +- .../Smtp/EsmtpTransportFactoryTest.php | 27 ++++++++++-- .../Transport/Smtp/EsmtpTransportTest.php | 43 +++++++++++++++++++ .../Transport/Smtp/SmtpTransportTest.php | 4 +- .../Smtp/Stream/SocketStreamTest.php | 1 - .../Mailer/Transport/Smtp/EsmtpTransport.php | 27 +++++++++--- .../Transport/Smtp/EsmtpTransportFactory.php | 8 ++-- .../Mailer/Transport/Smtp/SmtpTransport.php | 8 +++- .../Transport/Smtp/Stream/SocketStream.php | 29 +++++-------- 28 files changed, 197 insertions(+), 63 deletions(-) create mode 100644 src/Symfony/Component/Mailer/Tests/Transport/Smtp/EsmtpTransportTest.php diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesTransportFactoryTest.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesTransportFactoryTest.php index 6d24447d063f9..8e21f56f50441 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesTransportFactoryTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesTransportFactoryTest.php @@ -43,6 +43,11 @@ public function supportsProvider(): iterable true, ]; + yield [ + new Dsn('smtps', 'ses'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -84,13 +89,18 @@ public function createProvider(): iterable new Dsn('smtp', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']), new SesSmtpTransport(self::USER, self::PASSWORD, 'eu-west-1', $dispatcher, $logger), ]; + + yield [ + new Dsn('smtps', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']), + new SesSmtpTransport(self::USER, self::PASSWORD, 'eu-west-1', $dispatcher, $logger), + ]; } public function unsupportedSchemeProvider(): iterable { yield [ new Dsn('foo', 'ses', self::USER, self::PASSWORD), - 'The "foo" scheme is not supported for mailer "ses". Supported schemes are: "api", "http", "smtp".', + 'The "foo" scheme is not supported for mailer "ses". Supported schemes are: "api", "http", "smtp", "smtps".', ]; } diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesSmtpTransport.php index c1eb245212c76..08146ab0d9b34 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesSmtpTransport.php @@ -25,7 +25,7 @@ class SesSmtpTransport extends EsmtpTransport */ public function __construct(string $username, string $password, string $region = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { - parent::__construct(sprintf('email-smtp.%s.amazonaws.com', $region ?: 'eu-west-1'), 587, 'tls', null, $dispatcher, $logger); + parent::__construct(sprintf('email-smtp.%s.amazonaws.com', $region ?: 'eu-west-1'), 587, true, null, $dispatcher, $logger); $this->setUsername($username); $this->setPassword($password); diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesTransportFactory.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesTransportFactory.php index 80f6326a69e89..0dba1d998b465 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesTransportFactory.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Transport/SesTransportFactory.php @@ -36,11 +36,11 @@ public function create(Dsn $dsn): TransportInterface return new SesHttpTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger); } - if ('smtp' === $scheme) { + if ('smtp' === $scheme || 'smtps' === $scheme) { return new SesSmtpTransport($user, $password, $region, $this->dispatcher, $this->logger); } - throw new UnsupportedSchemeException($dsn, ['api', 'http', 'smtp']); + throw new UnsupportedSchemeException($dsn, ['api', 'http', 'smtp', 'smtps']); } public function supports(Dsn $dsn): bool diff --git a/src/Symfony/Component/Mailer/Bridge/Google/Tests/Transport/GmailTransportFactoryTest.php b/src/Symfony/Component/Mailer/Bridge/Google/Tests/Transport/GmailTransportFactoryTest.php index ef351d759275e..803b3b4e2473a 100644 --- a/src/Symfony/Component/Mailer/Bridge/Google/Tests/Transport/GmailTransportFactoryTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Google/Tests/Transport/GmailTransportFactoryTest.php @@ -22,6 +22,11 @@ public function supportsProvider(): iterable true, ]; + yield [ + new Dsn('smtps', 'gmail'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -34,13 +39,18 @@ public function createProvider(): iterable new Dsn('smtp', 'gmail', self::USER, self::PASSWORD), new GmailSmtpTransport(self::USER, self::PASSWORD, $this->getDispatcher(), $this->getLogger()), ]; + + yield [ + new Dsn('smtps', 'gmail', self::USER, self::PASSWORD), + new GmailSmtpTransport(self::USER, self::PASSWORD, $this->getDispatcher(), $this->getLogger()), + ]; } public function unsupportedSchemeProvider(): iterable { yield [ new Dsn('foo', 'gmail', self::USER, self::PASSWORD), - 'The "foo" scheme is not supported for mailer "gmail". Supported schemes are: "smtp".', + 'The "foo" scheme is not supported for mailer "gmail". Supported schemes are: "smtp", "smtps".', ]; } diff --git a/src/Symfony/Component/Mailer/Bridge/Google/Transport/GmailSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Google/Transport/GmailSmtpTransport.php index 4f51b4ff60bdb..371877e535f10 100644 --- a/src/Symfony/Component/Mailer/Bridge/Google/Transport/GmailSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Google/Transport/GmailSmtpTransport.php @@ -22,7 +22,7 @@ class GmailSmtpTransport extends EsmtpTransport { public function __construct(string $username, string $password, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { - parent::__construct('smtp.gmail.com', 465, 'ssl', null, $dispatcher, $logger); + parent::__construct('smtp.gmail.com', 465, true, null, $dispatcher, $logger); $this->setUsername($username); $this->setPassword($password); diff --git a/src/Symfony/Component/Mailer/Bridge/Google/Transport/GmailTransportFactory.php b/src/Symfony/Component/Mailer/Bridge/Google/Transport/GmailTransportFactory.php index ad32e18843725..346a2a7e93a48 100644 --- a/src/Symfony/Component/Mailer/Bridge/Google/Transport/GmailTransportFactory.php +++ b/src/Symfony/Component/Mailer/Bridge/Google/Transport/GmailTransportFactory.php @@ -23,11 +23,11 @@ final class GmailTransportFactory extends AbstractTransportFactory { public function create(Dsn $dsn): TransportInterface { - if ('smtp' === $dsn->getScheme()) { + if ('smtp' === $dsn->getScheme() || 'smtps' === $dsn->getScheme()) { return new GmailSmtpTransport($this->getUser($dsn), $this->getPassword($dsn), $this->dispatcher, $this->logger); } - throw new UnsupportedSchemeException($dsn, ['smtp']); + throw new UnsupportedSchemeException($dsn, ['smtp', 'smtps']); } public function supports(Dsn $dsn): bool diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillTransportFactoryTest.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillTransportFactoryTest.php index f4b0c2a38477c..2e8e2c0c0cc76 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillTransportFactoryTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillTransportFactoryTest.php @@ -43,6 +43,11 @@ public function supportsProvider(): iterable true, ]; + yield [ + new Dsn('smtps', 'mandrill'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -69,13 +74,18 @@ public function createProvider(): iterable new Dsn('smtp', 'mandrill', self::USER, self::PASSWORD), new MandrillSmtpTransport(self::USER, self::PASSWORD, $dispatcher, $logger), ]; + + yield [ + new Dsn('smtps', 'mandrill', self::USER, self::PASSWORD), + new MandrillSmtpTransport(self::USER, self::PASSWORD, $dispatcher, $logger), + ]; } public function unsupportedSchemeProvider(): iterable { yield [ new Dsn('foo', 'mandrill', self::USER), - 'The "foo" scheme is not supported for mailer "mandrill". Supported schemes are: "api", "http", "smtp".', + 'The "foo" scheme is not supported for mailer "mandrill". Supported schemes are: "api", "http", "smtp", "smtps".', ]; } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillSmtpTransport.php index 13be53717b043..bdcb4f055c333 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillSmtpTransport.php @@ -22,7 +22,7 @@ class MandrillSmtpTransport extends EsmtpTransport { public function __construct(string $username, string $password, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { - parent::__construct('smtp.mandrillapp.com', 587, 'tls', null, $dispatcher, $logger); + parent::__construct('smtp.mandrillapp.com', 587, true, null, $dispatcher, $logger); $this->setUsername($username); $this->setPassword($password); diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillTransportFactory.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillTransportFactory.php index 0b42bae1dcad8..b00b2bee748e8 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillTransportFactory.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillTransportFactory.php @@ -34,13 +34,13 @@ public function create(Dsn $dsn): TransportInterface return new MandrillHttpTransport($user, $this->client, $this->dispatcher, $this->logger); } - if ('smtp' === $scheme) { + if ('smtp' === $scheme || 'smtps' === $scheme) { $password = $this->getPassword($dsn); return new MandrillSmtpTransport($user, $password, $this->dispatcher, $this->logger); } - throw new UnsupportedSchemeException($dsn, ['api', 'http', 'smtp']); + throw new UnsupportedSchemeException($dsn, ['api', 'http', 'smtp', 'smtps']); } public function supports(Dsn $dsn): bool diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunTransportFactoryTest.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunTransportFactoryTest.php index 674a4d8b47f02..829d880fca624 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunTransportFactoryTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunTransportFactoryTest.php @@ -43,6 +43,11 @@ public function supportsProvider(): iterable true, ]; + yield [ + new Dsn('smtps', 'mailgun'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -74,13 +79,18 @@ public function createProvider(): iterable new Dsn('smtp', 'mailgun', self::USER, self::PASSWORD), new MailgunSmtpTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger), ]; + + yield [ + new Dsn('smtps', 'mailgun', self::USER, self::PASSWORD), + new MailgunSmtpTransport(self::USER, self::PASSWORD, null, $dispatcher, $logger), + ]; } public function unsupportedSchemeProvider(): iterable { yield [ new Dsn('foo', 'mailgun', self::USER, self::PASSWORD), - 'The "foo" scheme is not supported for mailer "mailgun". Supported schemes are: "api", "http", "smtp".', + 'The "foo" scheme is not supported for mailer "mailgun". Supported schemes are: "api", "http", "smtp", "smtps".', ]; } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunSmtpTransport.php index cd4530c120924..b2e15b594b08c 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunSmtpTransport.php @@ -22,7 +22,7 @@ class MailgunSmtpTransport extends EsmtpTransport { 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, 'ssl', null, $dispatcher, $logger); + parent::__construct('us' !== ($region ?: 'us') ? sprintf('smtp.%s.mailgun.org', $region) : 'smtp.mailgun.org', 465, true, null, $dispatcher, $logger); $this->setUsername($username); $this->setPassword($password); diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunTransportFactory.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunTransportFactory.php index 33ecf88fc628e..486dd6661935f 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunTransportFactory.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunTransportFactory.php @@ -36,11 +36,11 @@ public function create(Dsn $dsn): TransportInterface return new MailgunHttpTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger); } - if ('smtp' === $scheme) { + if ('smtp' === $scheme || 'smtps' === $scheme) { return new MailgunSmtpTransport($user, $password, $region, $this->dispatcher, $this->logger); } - throw new UnsupportedSchemeException($dsn, ['api', 'http', 'smtp']); + throw new UnsupportedSchemeException($dsn, ['api', 'http', 'smtp', 'smtps']); } public function supports(Dsn $dsn): bool 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 caca8a5197b58..721af087a74db 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkTransportFactoryTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkTransportFactoryTest.php @@ -37,6 +37,11 @@ public function supportsProvider(): iterable true, ]; + yield [ + new Dsn('smtps', 'postmark'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -57,13 +62,18 @@ public function createProvider(): iterable new Dsn('smtp', 'postmark', self::USER), new PostmarkSmtpTransport(self::USER, $dispatcher, $logger), ]; + + yield [ + new Dsn('smtps', 'postmark', self::USER), + new PostmarkSmtpTransport(self::USER, $dispatcher, $logger), + ]; } public function unsupportedSchemeProvider(): iterable { yield [ new Dsn('foo', 'postmark', self::USER), - 'The "foo" scheme is not supported for mailer "postmark". Supported schemes are: "api", "smtp".', + 'The "foo" scheme is not supported for mailer "postmark". Supported schemes are: "api", "smtp", "smtps".', ]; } diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php index 29b5bd53ac41b..f9f32ed7e4946 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkSmtpTransport.php @@ -22,7 +22,7 @@ class PostmarkSmtpTransport extends EsmtpTransport { public function __construct(string $id, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { - parent::__construct('smtp.postmarkapp.com', 587, 'tls', null, $dispatcher, $logger); + parent::__construct('smtp.postmarkapp.com', 587, true, null, $dispatcher, $logger); $this->setUsername($id); $this->setPassword($id); diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkTransportFactory.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkTransportFactory.php index 16d491091a1fe..fbe6add0c2871 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkTransportFactory.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkTransportFactory.php @@ -30,11 +30,11 @@ public function create(Dsn $dsn): TransportInterface return new PostmarkApiTransport($user, $this->client, $this->dispatcher, $this->logger); } - if ('smtp' === $scheme) { + if ('smtp' === $scheme || 'smtps' === $scheme) { return new PostmarkSmtpTransport($user, $this->dispatcher, $this->logger); } - throw new UnsupportedSchemeException($dsn, ['api', 'smtp']); + throw new UnsupportedSchemeException($dsn, ['api', 'smtp', 'smtps']); } public function supports(Dsn $dsn): bool diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridTransportFactoryTest.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridTransportFactoryTest.php index e271b88930789..efbd41eff5504 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridTransportFactoryTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridTransportFactoryTest.php @@ -37,6 +37,11 @@ public function supportsProvider(): iterable true, ]; + yield [ + new Dsn('smtps', 'sendgrid'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -57,13 +62,18 @@ public function createProvider(): iterable new Dsn('smtp', 'sendgrid', self::USER), new SendgridSmtpTransport(self::USER, $dispatcher, $logger), ]; + + yield [ + new Dsn('smtps', 'sendgrid', self::USER), + new SendgridSmtpTransport(self::USER, $dispatcher, $logger), + ]; } public function unsupportedSchemeProvider(): iterable { yield [ new Dsn('foo', 'sendgrid', self::USER), - 'The "foo" scheme is not supported for mailer "sendgrid". Supported schemes are: "api", "smtp".', + 'The "foo" scheme is not supported for mailer "sendgrid". Supported schemes are: "api", "smtp", "smtps".', ]; } } diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridSmtpTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridSmtpTransport.php index ff448c591a7b7..d61eca3c1c90c 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridSmtpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridSmtpTransport.php @@ -22,7 +22,7 @@ class SendgridSmtpTransport extends EsmtpTransport { public function __construct(string $key, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { - parent::__construct('smtp.sendgrid.net', 465, 'ssl', null, $dispatcher, $logger); + parent::__construct('smtp.sendgrid.net', 465, true, null, $dispatcher, $logger); $this->setUsername('apikey'); $this->setPassword($key); diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridTransportFactory.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridTransportFactory.php index dbd2b5ae9c123..70d87a08dabff 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridTransportFactory.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridTransportFactory.php @@ -29,11 +29,11 @@ public function create(Dsn $dsn): TransportInterface return new SendgridApiTransport($key, $this->client, $this->dispatcher, $this->logger); } - if ('smtp' === $dsn->getScheme()) { + if ('smtp' === $dsn->getScheme() || 'smtps' === $dsn->getScheme()) { return new SendgridSmtpTransport($key, $this->dispatcher, $this->logger); } - throw new UnsupportedSchemeException($dsn, ['api', 'smtp']); + throw new UnsupportedSchemeException($dsn, ['api', 'smtp', 'smtps']); } public function supports(Dsn $dsn): bool diff --git a/src/Symfony/Component/Mailer/CHANGELOG.md b/src/Symfony/Component/Mailer/CHANGELOG.md index 0c464ab5c0d14..fc642f576d94b 100644 --- a/src/Symfony/Component/Mailer/CHANGELOG.md +++ b/src/Symfony/Component/Mailer/CHANGELOG.md @@ -4,6 +4,9 @@ CHANGELOG 4.4.0 ----- + * STARTTLS cannot be enabled anymore (it is used automatically if TLS is disabled and the server supports STARTTLS) + * [BC BREAK] Removed the `encryption` DSN option (use `smtps` instead) + * Added support for the `smtps` protocol (does the same as using `smtp` and port `465`) * Added PHPUnit constraints * Added `MessageDataCollector` * Added `MessageEvents` and `MessageLoggerListener` to allow collecting sent emails diff --git a/src/Symfony/Component/Mailer/Test/TransportFactoryTestCase.php b/src/Symfony/Component/Mailer/Test/TransportFactoryTestCase.php index 0fee7d3b9a744..9b7dda632f611 100644 --- a/src/Symfony/Component/Mailer/Test/TransportFactoryTestCase.php +++ b/src/Symfony/Component/Mailer/Test/TransportFactoryTestCase.php @@ -69,7 +69,7 @@ public function testCreate(Dsn $dsn, TransportInterface $transport): void $factory = $this->getFactory(); $this->assertEquals($transport, $factory->create($dsn)); - if ('smtp' !== $dsn->getScheme()) { + if ('smtp' !== $dsn->getScheme() && 'smtps' !== $dsn->getScheme()) { $this->assertStringMatchesFormat($dsn->getScheme().'://%S'.$dsn->getHost().'%S', $transport->getName()); } } diff --git a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/EsmtpTransportFactoryTest.php b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/EsmtpTransportFactoryTest.php index 4413f8a148792..c64854239c08e 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/EsmtpTransportFactoryTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/EsmtpTransportFactoryTest.php @@ -22,6 +22,11 @@ public function supportsProvider(): iterable true, ]; + yield [ + new Dsn('smtps', 'example.com'), + true, + ]; + yield [ new Dsn('api', 'example.com'), false, @@ -33,19 +38,33 @@ public function createProvider(): iterable $eventDispatcher = $this->getDispatcher(); $logger = $this->getLogger(); - $transport = new EsmtpTransport('example.com', 25, null, null, $eventDispatcher, $logger); + $transport = new EsmtpTransport('localhost', 25, false, null, $eventDispatcher, $logger); yield [ - new Dsn('smtp', 'example.com'), + new Dsn('smtp', 'localhost'), $transport, ]; - $transport = new EsmtpTransport('example.com', 99, 'ssl', 'login', $eventDispatcher, $logger); + $transport = new EsmtpTransport('example.com', 99, true, 'login', $eventDispatcher, $logger); $transport->setUsername(self::USER); $transport->setPassword(self::PASSWORD); yield [ - new Dsn('smtp', 'example.com', self::USER, self::PASSWORD, 99, ['encryption' => 'ssl', 'auth_mode' => 'login']), + new Dsn('smtps', 'example.com', self::USER, self::PASSWORD, 99, ['auth_mode' => 'login']), + $transport, + ]; + + $transport = new EsmtpTransport('example.com', 465, true, null, $eventDispatcher, $logger); + + yield [ + new Dsn('smtps', 'example.com'), + $transport, + ]; + + $transport = new EsmtpTransport('example.com', 465, true, null, $eventDispatcher, $logger); + + yield [ + new Dsn('smtp', 'example.com', '', '', 465), $transport, ]; } diff --git a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/EsmtpTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/EsmtpTransportTest.php new file mode 100644 index 0000000000000..83c4ac51d96f9 --- /dev/null +++ b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/EsmtpTransportTest.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\Tests\Transport\Smtp; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +class EsmtpTransportTest extends TestCase +{ + public function testName() + { + $t = new EsmtpTransport(); + $this->assertEquals('smtp://localhost', $t->getName()); + + $t = new EsmtpTransport('example.com'); + if (\defined('OPENSSL_VERSION_NUMBER')) { + $this->assertEquals('smtps://example.com', $t->getName()); + } else { + $this->assertEquals('smtp://example.com', $t->getName()); + } + + $t = new EsmtpTransport('example.com', 2525); + $this->assertEquals('smtp://example.com:2525', $t->getName()); + + $t = new EsmtpTransport('example.com', 0, true); + $this->assertEquals('smtps://example.com', $t->getName()); + + $t = new EsmtpTransport('example.com', 0, false); + $this->assertEquals('smtp://example.com', $t->getName()); + + $t = new EsmtpTransport('example.com', 466, true); + $this->assertEquals('smtps://example.com:466', $t->getName()); + } +} diff --git a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php index 27494e150648a..1ad8a8235b2df 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php @@ -20,9 +20,9 @@ class SmtpTransportTest extends TestCase public function testName() { $t = new SmtpTransport(); - $this->assertEquals('smtp://localhost:25', $t->getName()); + $this->assertEquals('smtps://localhost', $t->getName()); - $t = new SmtpTransport((new SocketStream())->setHost('127.0.0.1')->setPort(2525)); + $t = new SmtpTransport((new SocketStream())->setHost('127.0.0.1')->setPort(2525)->disableTls()); $this->assertEquals('smtp://127.0.0.1:2525', $t->getName()); } } diff --git a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/SocketStreamTest.php b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/SocketStreamTest.php index ead0d7b73a60a..d7912f9ccba2d 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/SocketStreamTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/SocketStreamTest.php @@ -37,7 +37,6 @@ public function testSocketErrorBeforeConnectError() 'cafile' => __FILE__, ], ]); - $s->setEncryption('ssl'); $s->setHost('smtp.gmail.com'); $s->setPort(465); $s->initialize(); diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php index 37011f07c85ff..ef4d7f71ccea1 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php @@ -31,7 +31,7 @@ class EsmtpTransport extends SmtpTransport private $password = ''; private $authMode; - public function __construct(string $host = 'localhost', int $port = 25, string $encryption = null, string $authMode = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + public function __construct(string $host = 'localhost', int $port = 0, bool $tls = null, string $authMode = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { parent::__construct(null, $dispatcher, $logger); @@ -44,11 +44,23 @@ public function __construct(string $host = 'localhost', int $port = 25, string $ /** @var SocketStream $stream */ $stream = $this->getStream(); + + if (null === $tls) { + if (465 === $port) { + $tls = true; + } else { + $tls = \defined('OPENSSL_VERSION_NUMBER') && 0 === $port && 'localhost' !== $host; + } + } + if (!$tls) { + $stream->disableTls(); + } + if (0 === $port) { + $port = $tls ? 465 : 25; + } + $stream->setHost($host); $stream->setPort($port); - if (null !== $encryption) { - $stream->setEncryption($encryption); - } if (null !== $authMode) { $this->setAuthMode($authMode); } @@ -105,13 +117,15 @@ protected function doHeloCommand(): void return; } + $capabilities = $this->getCapabilities($response); + /** @var SocketStream $stream */ $stream = $this->getStream(); - if ($stream->isTLS()) { + if (!$stream->isTLS() && \defined('OPENSSL_VERSION_NUMBER') && \array_key_exists('STARTTLS', $capabilities)) { $this->executeCommand("STARTTLS\r\n", [220]); if (!$stream->startTLS()) { - throw new TransportException('Unable to connect with TLS encryption.'); + throw new TransportException('Unable to connect with STARTTLS.'); } try { @@ -123,7 +137,6 @@ protected function doHeloCommand(): void } } - $capabilities = $this->getCapabilities($response); if (\array_key_exists('AUTH', $capabilities)) { $this->handleAuth($capabilities['AUTH']); } diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransportFactory.php b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransportFactory.php index d1a5c60c5fb32..377a36e3ef94a 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransportFactory.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransportFactory.php @@ -22,12 +22,12 @@ final class EsmtpTransportFactory extends AbstractTransportFactory { public function create(Dsn $dsn): TransportInterface { - $encryption = $dsn->getOption('encryption'); + $tls = 'smtps' === $dsn->getScheme() ? true : null; $authMode = $dsn->getOption('auth_mode'); - $port = $dsn->getPort(25); + $port = $dsn->getPort(0); $host = $dsn->getHost(); - $transport = new EsmtpTransport($host, $port, $encryption, $authMode, $this->dispatcher, $this->logger); + $transport = new EsmtpTransport($host, $port, $tls, $authMode, $this->dispatcher, $this->logger); if ($user = $dsn->getUser()) { $transport->setUsername($user); @@ -42,6 +42,6 @@ public function create(Dsn $dsn): TransportInterface public function supports(Dsn $dsn): bool { - return 'smtp' === $dsn->getScheme(); + return 'smtp' === $dsn->getScheme() || 'smtps' === $dsn->getScheme(); } } diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php index f50e670848a1b..61990a9350397 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php @@ -129,7 +129,13 @@ public function send(RawMessage $message, SmtpEnvelope $envelope = null): ?SentM public function getName(): string { if ($this->stream instanceof SocketStream) { - return sprintf('smtp://%s:%d', $this->stream->getHost(), $this->stream->getPort()); + $name = sprintf('smtp%s://%s', ($tls = $this->stream->isTLS()) ? 's' : '', $this->stream->getHost()); + $port = $this->stream->getPort(); + if (!(25 === $port || ($tls && 465 === $port))) { + $name .= ':'.$port; + } + + return $name; } return sprintf('smtp://sendmail'); diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php b/src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php index eadfb759e6985..09c03660c30b1 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php @@ -25,10 +25,9 @@ final class SocketStream extends AbstractStream { private $url; private $host = 'localhost'; - private $protocol = 'tcp'; - private $port = 25; + private $port = 465; private $timeout = 15; - private $tls = false; + private $tls = true; private $sourceIp; private $streamContextOptions = []; @@ -72,18 +71,11 @@ public function getPort(): int } /** - * Sets the encryption type (tls or ssl). + * Sets the TLS/SSL on the socket (disables STARTTLS). */ - public function setEncryption(string $encryption): self - { - $encryption = strtolower($encryption); - if ('tls' === $encryption) { - $this->protocol = 'tcp'; - $this->tls = true; - } else { - $this->protocol = $encryption; - $this->tls = false; - } + public function disableTls(): self + { + $this->tls = false; return $this; } @@ -128,8 +120,8 @@ public function getSourceIp(): ?string public function initialize(): void { $this->url = $this->host.':'.$this->port; - if ($this->protocol) { - $this->url = $this->protocol.'://'.$this->url; + if ($this->tls) { + $this->url = 'ssl://'.$this->url; } $options = []; if ($this->sourceIp) { @@ -138,9 +130,8 @@ public function initialize(): void if ($this->streamContextOptions) { $options = array_merge($options, $this->streamContextOptions); } - if ($this->isTLS()) { - $options['ssl']['crypto_method'] = $options['ssl']['crypto_method'] ?? STREAM_CRYPTO_METHOD_TLS_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; - } + // do it unconditionnally as it will be used by STARTTLS as well if supported + $options['ssl']['crypto_method'] = $options['ssl']['crypto_method'] ?? STREAM_CRYPTO_METHOD_TLS_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; $streamContext = stream_context_create($options); set_error_handler(function ($type, $msg) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy