The Symfony Mailer component provides many security-related features like signing and encrypting email messages. In Symfony 7.3 we're pushing those features even further to give you greater control and stronger protection when sending email messages.

Require TLS in SMTP

Dan Brown
Contributed by Dan Brown in #59479

When sending emails via SMTP, the Mailer component uses TLS automatically if your server supports it and the remote server reports that has STARTTLS support. In Symfony 7.3, we're improving this feature so your server can ensure TLS will be used.

To enforce TLS, call setRequireTls(true) on your EsmtpTransport instance, or set the require_tls option to true in the mailer DSN:

1
2
# .env
MAILER_DSN='smtp://user:pass@10.0.0.25?require_tls=true'

If the remote server doesn't support TLS and you've set it as required, Symfony will throw a TransportException to stop the message from being sent without encryption. This gives you a simple way to guarantee secure delivery, especially when dealing with sensitive data or compliance requirements.

Signing and Encrypting Messages Globally

Elías Fernández Florent Morselli
Contributed by Elías Fernández and Florent Morselli in #58501 and #59831

Until now, signing or encrypting messages with DKIM or S/MIME required you to manually create a signer or encrypter for each email.

Symfony 7.3 introduces global DKIM and S/MIME signing as well as global S/MIME encryption. This means you can now configure everything in one place, and all your emails will be signed and/or encrypted automatically.

Here's an example of what that looks like with YAML configuration (though it also works with XML and PHP):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# config/packages/mailer.yaml
framework:
    mailer:
        # ...
        dkim_signer:
            key: 'file://%kernel.project_dir%/var/certificates/dkim.pem'
            domain: 'symfony.com'
            select: 's1'

        smime_signer:
            key: '%kernel.project_dir%/var/certificates/smime.key'
            certificate: '%kernel.project_dir%/var/certificates/smime.crt'
            passphrase: ''

        # ...

        smime_encrypter:
            repository: App\Security\LocalFileCertificateRepository

For encryption, the repository option is the ID of a service that implements Symfony\Component\Mailer\EventListener\SmimeCertificateRepositoryInterface. This service returns the file path of the certificate associated with each recipient's email address:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace App\Security;

use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Mailer\EventListener\SmimeCertificateRepositoryInterface;

class LocalFileCertificateRepository implements SmimeCertificateRepositoryInterface
{
    public function __construct(
        #[Autowire(param: 'kernel.project_dir')] private readonly string $projectDir
    ) {
    }

    public function findCertificatePathFor(string $email): ?string
    {
        $hash = hash('xxh128', strtolower(trim($email)));
        $path = sprintf('%s/storage/%s.crt', $this->projectDir, $hash);

        return file_exists($path) ? $path : null;
    }
}

That's all! Every message you send is now automatically signed and/or encrypted, with no extra effort from you.

Published in #Living on the edge