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 6d24447d06..8e21f56f50 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 @@ class SesTransportFactoryTest extends TransportFactoryTestCase true, ]; + yield [ + new Dsn('smtps', 'ses'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -84,13 +89,18 @@ class SesTransportFactoryTest extends TransportFactoryTestCase 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 c1eb245212..08146ab0d9 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 80f6326a69..0dba1d998b 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 @@ final class SesTransportFactory extends AbstractTransportFactory 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 ef351d7592..803b3b4e24 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 @@ class GmailTransportFactoryTest extends TransportFactoryTestCase true, ]; + yield [ + new Dsn('smtps', 'gmail'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -34,13 +39,18 @@ class GmailTransportFactoryTest extends TransportFactoryTestCase 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 4f51b4ff60..371877e535 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 ad32e18843..346a2a7e93 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 f4b0c2a384..2e8e2c0c0c 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 @@ class MandrillTransportFactoryTest extends TransportFactoryTestCase true, ]; + yield [ + new Dsn('smtps', 'mandrill'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -69,13 +74,18 @@ class MandrillTransportFactoryTest extends TransportFactoryTestCase 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 13be53717b..bdcb4f055c 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 0b42bae1dc..b00b2bee74 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 @@ final class MandrillTransportFactory extends AbstractTransportFactory 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 674a4d8b47..829d880fca 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 @@ class MailgunTransportFactoryTest extends TransportFactoryTestCase true, ]; + yield [ + new Dsn('smtps', 'mailgun'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -74,13 +79,18 @@ class MailgunTransportFactoryTest extends TransportFactoryTestCase 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 cd4530c120..b2e15b594b 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 33ecf88fc6..486dd66619 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 @@ final class MailgunTransportFactory extends AbstractTransportFactory 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 caca8a5197..721af087a7 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 @@ class PostmarkTransportFactoryTest extends TransportFactoryTestCase true, ]; + yield [ + new Dsn('smtps', 'postmark'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -57,13 +62,18 @@ class PostmarkTransportFactoryTest extends TransportFactoryTestCase 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 29b5bd53ac..f9f32ed7e4 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 16d491091a..fbe6add0c2 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 @@ final class PostmarkTransportFactory extends AbstractTransportFactory 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 e271b88930..efbd41eff5 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 @@ class SendgridTransportFactoryTest extends TransportFactoryTestCase true, ]; + yield [ + new Dsn('smtps', 'sendgrid'), + true, + ]; + yield [ new Dsn('smtp', 'example.com'), false, @@ -57,13 +62,18 @@ class SendgridTransportFactoryTest extends TransportFactoryTestCase 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 ff448c591a..d61eca3c1c 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 dbd2b5ae9c..70d87a08da 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 @@ final class SendgridTransportFactory extends AbstractTransportFactory 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 0c464ab5c0..fc642f576d 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 0fee7d3b9a..9b7dda632f 100644 --- a/src/Symfony/Component/Mailer/Test/TransportFactoryTestCase.php +++ b/src/Symfony/Component/Mailer/Test/TransportFactoryTestCase.php @@ -69,7 +69,7 @@ abstract class TransportFactoryTestCase extends TestCase $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 4413f8a148..c64854239c 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 @@ class EsmtpTransportFactoryTest extends TransportFactoryTestCase true, ]; + yield [ + new Dsn('smtps', 'example.com'), + true, + ]; + yield [ new Dsn('api', 'example.com'), false, @@ -33,19 +38,33 @@ class EsmtpTransportFactoryTest extends TransportFactoryTestCase $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 0000000000..83c4ac51d9 --- /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 27494e1506..1ad8a8235b 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 ead0d7b73a..d7912f9ccb 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 @@ class SocketStreamTest extends TestCase '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 37011f07c8..ef4d7f71cc 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 @@ class EsmtpTransport extends SmtpTransport /** @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 @@ class EsmtpTransport extends SmtpTransport 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 @@ class EsmtpTransport extends SmtpTransport } } - $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 d1a5c60c5f..377a36e3ef 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 @@ final class EsmtpTransportFactory extends AbstractTransportFactory 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 f50e670848..61990a9350 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php @@ -129,7 +129,13 @@ class SmtpTransport extends AbstractTransport 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 eadfb759e6..09c03660c3 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 @@ final class SocketStream extends AbstractStream } /** - * Sets the encryption type (tls or ssl). + * Sets the TLS/SSL on the socket (disables STARTTLS). */ - public function setEncryption(string $encryption): self + public function disableTls(): self { - $encryption = strtolower($encryption); - if ('tls' === $encryption) { - $this->protocol = 'tcp'; - $this->tls = true; - } else { - $this->protocol = $encryption; - $this->tls = false; - } + $this->tls = false; return $this; } @@ -128,8 +120,8 @@ final class SocketStream extends AbstractStream 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 @@ final class SocketStream extends AbstractStream 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) {