winter icon indicating copy to clipboard operation
winter copied to clipboard

Improve mailer

Open mjauvin opened this issue 1 year ago • 7 comments

Fix username / password fields not showing up when "SMTP authorization required" was being triggered in create context.

Drop port 25 in favor of 587 as it is rarely used nowadays.

Add default configs for the different mail drivers in services config.

mjauvin avatar Mar 21 '24 16:03 mjauvin

@mjauvin I'm not sure I agree with the port changes. Port 25 is still the default port for unencrypted SMTP - even if most people are using other ports these days. While we obviously want to "encourage" people to use encryption, it's still up to the developer and their environment.

The other changes look fine to me though.

bennothommo avatar Mar 22 '24 06:03 bennothommo

@mjauvin I'm not sure I agree with the port changes. Port 25 is still the default port for unencrypted SMTP - even if most people are using other ports these days. While we obviously want to "encourage" people to use encryption, it's still up to the developer and their environment.

The other changes look fine to me though.

The submission port is 587 (look in /etc/services). Port 25 is used by mail servers, not by mail clients.

mjauvin avatar Mar 22 '24 10:03 mjauvin

Read this for a very good explanation: https://www.mailgun.com/blog/email/which-smtp-port-understanding-ports-25-465-587/#chapter-3

mjauvin avatar Mar 22 '24 10:03 mjauvin

Outlook, Thunderbird and most other clients that I've seen default to port 25 for unencrypted connections although most servers have 587 open for both these days.

josephcrowell avatar Mar 22 '24 11:03 josephcrowell

Also, it looks like we're using 'tls' & 'ssl' for the encryption but Laravel only ever use 'tls':

ref. https://github.com/laravel/framework/blob/11.x/src/Illuminate/Mail/MailManager.php#L177-L199

I think I'll change the encryption field to a checkbox, and leave the port number untouched.

For BC, I'll convert the encryption option to 'tls' if it was 'ssl'/'tls' and leave it unset otherwise.

Thoughts?

mjauvin avatar Mar 22 '24 13:03 mjauvin

Ok, so I removed ssl encryption as this is irrelevant (it gets converted to tls if it was previously set).

Port if left untouched, allowing full configurability.

Note: if port is 587, whether encryption is set or not, the Mail client (symfony here) will use STARTTLS automatically if it's listed in the mail server's capabilities.

below is what symfony does in Transport/Smtp/EsmtpTransport.php:

if (!$stream->isTLS() && \defined('OPENSSL_VERSION_NUMBER') && \array_key_exists('STARTTLS', $this->capabilities)) {
   $this->executeCommand("STARTTLS\r\n", [220]);
   ...
}

Arguably, we COULD force Encryption when port 465 is used as this is usually mandatory.

mjauvin avatar Mar 22 '24 14:03 mjauvin

465 is usually SSL only, not starttls. So if you wanted a reason to assume/turn on SSL, that would be a good one.

josephcrowell avatar Mar 22 '24 17:03 josephcrowell

@josephcrowell is correct - port 465 is explicitly an SSL port for SMTP servers, and requires an SSL connection, although some servers do allow TLS to be used (hence the check for the capabilities).

Nonetheless, I think it's reasonable to assume that if 465 is used, it will be encrypted, so I'm fine with it being forced through the form.

bennothommo avatar Mar 28 '24 01:03 bennothommo

Nonetheless, I think it's reasonable to assume that if 465 is used, it will be encrypted, so I'm fine with it being forced through the form.

What are you saying, this PR removes any forced rules, giving more flexibility for any possible setup.

mjauvin avatar Mar 28 '24 16:03 mjauvin

What's the status of this?

LukeTowers avatar Apr 23 '24 16:04 LukeTowers

Notes: Laravel Mailer/Transport/EsmtpTransport does the following:

if (null === $tls) {
    if (465 === $port) {
        $tls = true;
    } else {
        $tls = \defined('OPENSSL_VERSION_NUMBER') && 0 === $port && 'localhost' !== $host;
    }
}

Also, no matter what encryption we set, Laravel does this for smtp transport:

        if (! $scheme) {
            $scheme = ! empty($config['encryption']) && $config['encryption'] === 'tls'
                ? (($config['port'] == 465) ? 'smtps' : 'smtp')
                : '';
        }   

And symfony does this in the EsmtpTransportFactory:

final class EsmtpTransportFactory extends AbstractTransportFactory
{
    public function create(Dsn $dsn): TransportInterface
    {   
        $tls = 'smtps' === $dsn->getScheme() ? true : null;
        $port = $dsn->getPort(0);
        $host = $dsn->getHost();
        
        $transport = new EsmtpTransport($host, $port, $tls, $this->dispatcher, $this->logger);
    ...
}

So encryption is only forced for port 465. Encryption will be automatically enabled using STARTTLS for other ports (e.g. 25 and 587) if available from the mail server CAPABILITIES.

Here

if (!$stream->isTLS() && \defined('OPENSSL_VERSION_NUMBER') && \array_key_exists('STARTTLS', $this->capabilities)) {
    $this->executeCommand("STARTTLS\r\n", [220]);
    ...
}

mjauvin avatar Apr 23 '24 18:04 mjauvin

@bennothommo @LukeTowers All the above mean we should drop the encryption config for SMTP transport.

mjauvin avatar Apr 23 '24 18:04 mjauvin