Skip to content

Commit 7d60857

Browse files
committed
[Mailer] simplified the way TLS/SSL/StartTls work
1 parent f7a49a0 commit 7d60857

File tree

60 files changed

+442
-176
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+442
-176
lines changed

Amazon/Tests/Transport/SesTransportFactoryTest.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ public function supportsProvider(): iterable
4343
true,
4444
];
4545

46+
yield [
47+
new Dsn('smtps', 'ses'),
48+
true,
49+
];
50+
4651
yield [
4752
new Dsn('smtp', 'example.com'),
4853
false,
@@ -84,13 +89,18 @@ public function createProvider(): iterable
8489
new Dsn('smtp', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
8590
new SesSmtpTransport(self::USER, self::PASSWORD, 'eu-west-1', $dispatcher, $logger),
8691
];
92+
93+
yield [
94+
new Dsn('smtps', 'ses', self::USER, self::PASSWORD, null, ['region' => 'eu-west-1']),
95+
new SesSmtpTransport(self::USER, self::PASSWORD, 'eu-west-1', $dispatcher, $logger),
96+
];
8797
}
8898

8999
public function unsupportedSchemeProvider(): iterable
90100
{
91101
yield [
92102
new Dsn('foo', 'ses', self::USER, self::PASSWORD),
93-
'The "foo" scheme is not supported for mailer "ses". Supported schemes are: "api", "http", "smtp".',
103+
'The "foo" scheme is not supported for mailer "ses". Supported schemes are: "api", "http", "smtp", "smtps".',
94104
];
95105
}
96106

Amazon/Transport/SesSmtpTransport.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class SesSmtpTransport extends EsmtpTransport
2525
*/
2626
public function __construct(string $username, string $password, string $region = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null)
2727
{
28-
parent::__construct(sprintf('email-smtp.%s.amazonaws.com', $region ?: 'eu-west-1'), 587, 'tls', null, $dispatcher, $logger);
28+
parent::__construct(sprintf('email-smtp.%s.amazonaws.com', $region ?: 'eu-west-1'), 587, true, null, $dispatcher, $logger);
2929

3030
$this->setUsername($username);
3131
$this->setPassword($password);

Amazon/Transport/SesTransportFactory.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ public function create(Dsn $dsn): TransportInterface
3636
return new SesHttpTransport($user, $password, $region, $this->client, $this->dispatcher, $this->logger);
3737
}
3838

39-
if ('smtp' === $scheme) {
39+
if ('smtp' === $scheme || 'smtps' === $scheme) {
4040
return new SesSmtpTransport($user, $password, $region, $this->dispatcher, $this->logger);
4141
}
4242

43-
throw new UnsupportedSchemeException($dsn, ['api', 'http', 'smtp']);
43+
throw new UnsupportedSchemeException($dsn, ['api', 'http', 'smtp', 'smtps']);
4444
}
4545

4646
public function supports(Dsn $dsn): bool

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ CHANGELOG
44
4.4.0
55
-----
66

7+
* STARTTLS cannot be enabled anymore (it is used automatically if TLS is disabled and the server supports STARTTLS)
8+
* [BC BREAK] Removed the `encryption` DSN option (use `smtps` instead)
9+
* Added support for the `smtps` protocol (does the same as using `smtp` and port `465`)
710
* Added PHPUnit constraints
811
* Added `MessageDataCollector`
912
* Added `MessageEvents` and `MessageLoggerListener` to allow collecting sent emails

EsmtpTransport.php

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class EsmtpTransport extends SmtpTransport
3131
private $password = '';
3232
private $authMode;
3333

34-
public function __construct(string $host = 'localhost', int $port = 25, string $encryption = null, string $authMode = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null)
34+
public function __construct(string $host = 'localhost', int $port = 0, bool $tls = null, string $authMode = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null)
3535
{
3636
parent::__construct(null, $dispatcher, $logger);
3737

@@ -44,11 +44,23 @@ public function __construct(string $host = 'localhost', int $port = 25, string $
4444

4545
/** @var SocketStream $stream */
4646
$stream = $this->getStream();
47+
48+
if (null === $tls) {
49+
if (465 === $port) {
50+
$tls = true;
51+
} else {
52+
$tls = \defined('OPENSSL_VERSION_NUMBER') && 0 === $port && 'localhost' !== $host;
53+
}
54+
}
55+
if (!$tls) {
56+
$stream->disableTls();
57+
}
58+
if (0 === $port) {
59+
$port = $tls ? 465 : 25;
60+
}
61+
4762
$stream->setHost($host);
4863
$stream->setPort($port);
49-
if (null !== $encryption) {
50-
$stream->setEncryption($encryption);
51-
}
5264
if (null !== $authMode) {
5365
$this->setAuthMode($authMode);
5466
}
@@ -105,13 +117,15 @@ protected function doHeloCommand(): void
105117
return;
106118
}
107119

120+
$capabilities = $this->getCapabilities($response);
121+
108122
/** @var SocketStream $stream */
109123
$stream = $this->getStream();
110-
if ($stream->isTLS()) {
124+
if (!$stream->isTLS() && \defined('OPENSSL_VERSION_NUMBER') && \array_key_exists('STARTTLS', $capabilities)) {
111125
$this->executeCommand("STARTTLS\r\n", [220]);
112126

113127
if (!$stream->startTLS()) {
114-
throw new TransportException('Unable to connect with TLS encryption.');
128+
throw new TransportException('Unable to connect with STARTTLS.');
115129
}
116130

117131
try {
@@ -123,7 +137,6 @@ protected function doHeloCommand(): void
123137
}
124138
}
125139

126-
$capabilities = $this->getCapabilities($response);
127140
if (\array_key_exists('AUTH', $capabilities)) {
128141
$this->handleAuth($capabilities['AUTH']);
129142
}

EsmtpTransportFactory.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ final class EsmtpTransportFactory extends AbstractTransportFactory
2222
{
2323
public function create(Dsn $dsn): TransportInterface
2424
{
25-
$encryption = $dsn->getOption('encryption');
25+
$tls = 'smtps' === $dsn->getScheme() ? true : null;
2626
$authMode = $dsn->getOption('auth_mode');
27-
$port = $dsn->getPort(25);
27+
$port = $dsn->getPort(0);
2828
$host = $dsn->getHost();
2929

30-
$transport = new EsmtpTransport($host, $port, $encryption, $authMode, $this->dispatcher, $this->logger);
30+
$transport = new EsmtpTransport($host, $port, $tls, $authMode, $this->dispatcher, $this->logger);
3131

3232
if ($user = $dsn->getUser()) {
3333
$transport->setUsername($user);
@@ -42,6 +42,6 @@ public function create(Dsn $dsn): TransportInterface
4242

4343
public function supports(Dsn $dsn): bool
4444
{
45-
return 'smtp' === $dsn->getScheme();
45+
return 'smtp' === $dsn->getScheme() || 'smtps' === $dsn->getScheme();
4646
}
4747
}

EsmtpTransportFactoryTest.php

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ public function supportsProvider(): iterable
2222
true,
2323
];
2424

25+
yield [
26+
new Dsn('smtps', 'example.com'),
27+
true,
28+
];
29+
2530
yield [
2631
new Dsn('api', 'example.com'),
2732
false,
@@ -33,19 +38,33 @@ public function createProvider(): iterable
3338
$eventDispatcher = $this->getDispatcher();
3439
$logger = $this->getLogger();
3540

36-
$transport = new EsmtpTransport('example.com', 25, null, null, $eventDispatcher, $logger);
41+
$transport = new EsmtpTransport('localhost', 25, false, null, $eventDispatcher, $logger);
3742

3843
yield [
39-
new Dsn('smtp', 'example.com'),
44+
new Dsn('smtp', 'localhost'),
4045
$transport,
4146
];
4247

43-
$transport = new EsmtpTransport('example.com', 99, 'ssl', 'login', $eventDispatcher, $logger);
48+
$transport = new EsmtpTransport('example.com', 99, true, 'login', $eventDispatcher, $logger);
4449
$transport->setUsername(self::USER);
4550
$transport->setPassword(self::PASSWORD);
4651

4752
yield [
48-
new Dsn('smtp', 'example.com', self::USER, self::PASSWORD, 99, ['encryption' => 'ssl', 'auth_mode' => 'login']),
53+
new Dsn('smtps', 'example.com', self::USER, self::PASSWORD, 99, ['auth_mode' => 'login']),
54+
$transport,
55+
];
56+
57+
$transport = new EsmtpTransport('example.com', 465, true, null, $eventDispatcher, $logger);
58+
59+
yield [
60+
new Dsn('smtps', 'example.com'),
61+
$transport,
62+
];
63+
64+
$transport = new EsmtpTransport('example.com', 465, true, null, $eventDispatcher, $logger);
65+
66+
yield [
67+
new Dsn('smtp', 'example.com', '', '', 465),
4968
$transport,
5069
];
5170
}

EsmtpTransportTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Mailer\Tests\Transport\Smtp;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
16+
17+
class EsmtpTransportTest extends TestCase
18+
{
19+
public function testName()
20+
{
21+
$t = new EsmtpTransport();
22+
$this->assertEquals('smtp://localhost', $t->getName());
23+
24+
$t = new EsmtpTransport('example.com');
25+
if (\defined('OPENSSL_VERSION_NUMBER')) {
26+
$this->assertEquals('smtps://example.com', $t->getName());
27+
} else {
28+
$this->assertEquals('smtp://example.com', $t->getName());
29+
}
30+
31+
$t = new EsmtpTransport('example.com', 2525);
32+
$this->assertEquals('smtp://example.com:2525', $t->getName());
33+
34+
$t = new EsmtpTransport('example.com', 0, true);
35+
$this->assertEquals('smtps://example.com', $t->getName());
36+
37+
$t = new EsmtpTransport('example.com', 0, false);
38+
$this->assertEquals('smtp://example.com', $t->getName());
39+
40+
$t = new EsmtpTransport('example.com', 466, true);
41+
$this->assertEquals('smtps://example.com:466', $t->getName());
42+
}
43+
}

GmailSmtpTransport.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class GmailSmtpTransport extends EsmtpTransport
2222
{
2323
public function __construct(string $username, string $password, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null)
2424
{
25-
parent::__construct('smtp.gmail.com', 465, 'ssl', null, $dispatcher, $logger);
25+
parent::__construct('smtp.gmail.com', 465, true, null, $dispatcher, $logger);
2626

2727
$this->setUsername($username);
2828
$this->setPassword($password);

GmailTransportFactory.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ final class GmailTransportFactory extends AbstractTransportFactory
2323
{
2424
public function create(Dsn $dsn): TransportInterface
2525
{
26-
if ('smtp' === $dsn->getScheme()) {
26+
if ('smtp' === $dsn->getScheme() || 'smtps' === $dsn->getScheme()) {
2727
return new GmailSmtpTransport($this->getUser($dsn), $this->getPassword($dsn), $this->dispatcher, $this->logger);
2828
}
2929

30-
throw new UnsupportedSchemeException($dsn, ['smtp']);
30+
throw new UnsupportedSchemeException($dsn, ['smtp', 'smtps']);
3131
}
3232

3333
public function supports(Dsn $dsn): bool

0 commit comments

Comments
 (0)