8000 [Mailer] [Smtp] Add DSN param to enforce TLS/STARTTLS · symfony/symfony@bd5e626 · GitHub
[go: up one dir, main page]

Skip to content

Commit bd5e626

Browse files
committed
[Mailer] [Smtp] Add DSN param to enforce TLS/STARTTLS
Adds 'require_tls' param which can be set to true to enforce the use of TLS/STARTTLS within the ESMTP transport.
1 parent b684e7e commit bd5e626

File tree

5 files changed

+58
-0
lines changed

5 files changed

+58
-0
lines changed

src/Symfony/Component/Mailer/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* Add DSN param `retry_period` to override default email transport retry period
88
* Add `Dsn::getBooleanOption()`
99
* Add DSN param `source_ip` to allow binding to a (specific) IPv4 or IPv6 address.
10+
* Add DSN param `require_tls` to enforce use of TLS/STARTTLS
1011

1112
7.2
1213
---

src/Symfony/Component/Mailer/Tests/Transport/Smtp/EsmtpTransportFactoryTest.php

Lines changed: 12 additions & 0 deletions
< 8000 /tr>
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,18 @@ public static function createProvider(): iterable
194194
Dsn::fromString('smtps://:@example.com:465?source_ip=[2606:4700:20::681a:5fb]'),
195195
$transport,
196196
];
197+
198+
$transport = new EsmtpTransport('example.com', 465, true, null, $logger);
199+
$transport->setRequireTls(true);
200+
201+
yield [
202+
new Dsn('smtps', 'example.com', '', '', 465, ['require_tls' => true]),
203+
$transport,
204+
];
205+
yield [
206+
Dsn::fromString('smtps://:@example.com?require_tls=true'),
207+
$transport,
208+
];
197209
}
198210

199211
public static function unsupportedSchemeProvider(): iterable

src/Symfony/Component/Mailer/Tests/Transport/Smtp/EsmtpTransportTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,25 @@ public function testSocketTimeout()
297297
$stream->getCommands()
298298
);
299299
}
300+
301+
public function testRequireTls()
302+
{
303+
$stream = new DummyStream();
304+
$transport = new EsmtpTransport(stream: $stream);
305+
$transport->setRequireTls(true);
306+
307+
$message = new Email();
308+
$message->from('sender@example.org');
309+
$message->addTo('recipient@example.org');
310+
$message->text('.');
311+
312+
try {
313+
$transport->send($message);
314+
$this->fail('Symfony\Component\Mailer\Exception\TransportException to be thrown');
315+
} catch (TransportException $e) {
316+
$this->assertStringStartsWith('TLS required but neither TLS or STARTTLS are in use.', $e->getMessage());
317+
}
318+
}
300319
}
301320

302321
class CustomEsmtpTransport extends EsmtpTransport

src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php

Lin 8000 es changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class EsmtpTransport extends SmtpTransport
3333
private string $password = '';
3434
private array $capabilities;
3535
private bool $autoTls = true;
36+
private bool $requireTls = false;
3637

3738
public function __construct(string $host = 'localhost', int $port = 0, ?bool $tls = null, ?EventDispatcherInterface $dispatcher = null, ?LoggerInterface $logger = null, ?AbstractStream $stream = null, ?array $authenticators = null)
3839
{
@@ -116,6 +117,21 @@ public function isAutoTls(): bool
116117
return $this->autoTls;
117118
}
118119

120+
/**
121+
* @return $this
122+
*/
123+
public function setRequireTls(bool $requireTls): static
124+
{
125+
$this->requireTls = $requireTls;
126+
127+
return $this;
128+
}
129+
130+
public function isTlsRequired(): bool
131+
{
132+
return $this->requireTls;
133+
}
134+
119135
public function setAuthenticators(array $authenticators): void
120136
{
121137
$this->authenticators = [];
@@ -159,6 +175,7 @@ private function doEhloCommand(): string
159175

160176
/** @var SocketStream $stream */
161177
$stream = $this->getStream();
178+
$tlsStarted = $stream->isTls();
162179
// WARNING: !$stream->isTLS() is right, 100% sure :)
163180
// if you think that the ! should be removed, read the code again
164181
// if doing so "fixes" your issue then it probably means your SMTP server behaves incorrectly or is wrongly configured
@@ -169,10 +186,15 @@ private function doEhloCommand(): string
169186
throw new TransportException('Unable to connect with STARTTLS.');
170187
}
171188

189+
$tlsStarted = true;
172190
$response = $this->executeCommand(\sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]);
173191
$this->capabilities = $this->parseCapabilities($response);
174192
}
175193

194+
if (!$tlsStarted && $this->isTlsRequired()) {
195+
throw new TransportException('TLS required but neither TLS or STARTTLS are in use.');
196+
}
197+
176198
if (\array_key_exists('AUTH', $this->capabilities)) {
177199
$this->handleAuth($this->capabilities['AUTH']);
178200
}

src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransportFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ public function create(Dsn $dsn): TransportInterface
7878
$transport->setPingThreshold((int) $pingThreshold);
7979
}
8080

81+
if (null !== ($tlsRequired = $dsn->getOption('require_tls'))) {
82+
$transport->setRequireTls((bool) $tlsRequired);
83+
}
84+
8185
return $transport;
8286
}
8387

0 commit comments

Comments
 (0)
0