In October CMS and Laravel, you can use the MAIL_ENCRYPTION
environment variable to set the type of encryption for your email connections to use. This configuration is used to set the encryption option on the SMTP mail transport type.
You can also set the encryption and other configuration using the Mail Configuration screen in the Settings area using the SMTP encryption protocol field (MAIL_ENCRYPTION
), which can be set to either No encryption (null
) or TLS (tls
). You may also set the port number using the SMTP port field (MAIL_PORT
) as a number. Commonly this is set to port 465
or port 587
, otherwise it can be left empty.
Research
In previous versions, October CMS v1 and v2, this encryption
option is given verbatim to the Swift Mailer library used for SMTP emails, with $transport
as a Swift_SmtpTransport
instance. This works as expected and also included an ssl
option for SSL encryption, which is now removed.
if (! empty($config['encryption'])) {
$transport->setEncryption($config['encryption']);
}
Since Swift Mailer is no longer maintained, Laravel 9 and October CMS v3, switched to use the Symfony Mailer instead. As a result the use of the encryption
setting behaves differently. See the code below for how the value is handled.
$transport = $factory->create(new Dsn(
! empty($config['encryption']) && $config['encryption'] === 'tls'
? (($config['port'] == 465) ? 'smtps' : 'smtp')
: '',
// ...
));
With $factory
as an EsmtpTransportFactory
instance, the encryption
setting is no longer passed verbatim and instead used to set the scheme to one of three possible values. The logic makes a decision based on the port number and the encryption value. We should look at how the factory uses this scheme.
$tls = 'smtps' === $dsn->getScheme() ? true : null;
// ...
$transport = new EsmtpTransport(
$host,
$port,
$tls,
$this->dispatcher,
$this->logger
);
With this information we can determine that the $tls
variable is true
when the port setting is 465
and the encrpytion is est to tls
; otherwise $tls
variable is set to null
. However, before this value is used, it is modified further inside the EsmtpTransport
constructor.
if (null === $tls) {
if (465 === $port) {
$tls = true;
} else {
$tls = \defined('OPENSSL_VERSION_NUMBER') &&
0 === $port &&
'localhost' !== $host;
}
}
Now we see if the port setting is 465
but this $tls
variable is set to null
, it will be set to true
anyway regardless of the encryption setting. Let’s look at how this $tls
is used.
if (!$tls) {
$stream->disableTls();
}
When $tls
is true
, implicit TLS remains enabled, and when $tls
is null
, implicit TLS is disabled instead. There is one final detail to cover: STARTTLS.
if (
!$stream->isTLS() &&
\defined('OPENSSL_VERSION_NUMBER') &&
\array_key_exists('STARTTLS', $this->capabilities)
) {
$this->executeCommand("STARTTLS\r\n", [220]);
// ...
}
According to this code, when implicit TLS is not enabled and the server advertises STARTTLS, Symfony Mailer always tries to enable it. There is no possibility to enforce or disable this.
Conclusion
In summary, the port is used to determine if STARTTLS is used. When configuring your mail server to use SMTP:
-
When the
MAIL_PORT
environment variable is set to465
then Symfony Mailer will end up using implicit TLS. Otherwise, Symfony Mailer will try to use STARTTLS if the server supports it. -
When your
MAIL_PORT
is undefined or set to0
, Laravel will guess the port to use. WhenMAIL_HOST
is set tolocalhost
with port25
STARTTLS is used, otherwise port465
with implicit TLS is used.
There is no way for a developer to change this behaviour. The MAIL_ENCRYPTION
environment variable ends up not affecting this process. This leads to the following problems.
-
You cannot enable implicit TLS for any non-standard port, nor can you disable it on the standard port.
-
You cannot disable STARTTLS even when it is optional. This prevents you from connecting to your mailserver through localhost.
-
You cannot enforce STARTTLS when you know a server supports it. This makes Symfony Mailer vulnerable to even trivial downgrade attacks.
Source: Wilco de Boer · Why you can't configure email encryption in Laravel 9