Asynchronous email sending with Symfony

Asynchronous email sending with Symfony

Below article serves as a reminder for myself on how to quickly setup asynchronous email sending for Symfony.

We will use Symfony messenger with Doctrine as the queue mechanism.

The below instructions have been tested for Symfony version 6.4.

Install composer packages

Install the required composer packages to do the actual asynchronous sending:

composer require symfony/messenger;
composer require symfony/doctrine-messenger;

And for testing purposes:

composer require --dev zenstruck/messenger-test;

Configure messenger

Add the following YAML configuration file in /config/packages/messenger.yaml.

framework:
    messenger:
        # Uncomment this (and the failed transport below) to send failed messages to this transport for later handling.
        failure_transport: failed

        transports:
            # https://symfony.com/doc/current/messenger.html#transport-configuration
            async:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                retry_strategy:
                    max_retries: 10
                    delay: 10000 # milliseconds delay
                    # causes the delay to be higher before each retry
                    # e.g. 10 seconds delay, 20 seconds, 40 seconds
                    multiplier: 2
                    max_delay: 0
            failed: 'doctrine://default?queue_name=failed'
            # sync: 'sync://'

        routing:
            # Route your messages to the transports
            # 'App\Message\YourMessage': async
            'Symfony\Component\Mailer\Messenger\SendEmailMessage':  async

when@test:
    framework:
        messenger:
            transports:
                # replace with your transport name here (e.g., my_transport: 'in-memory://')
                # For more Messenger testing tools, see https://github.com/zenstruck/messenger-test
                async: 'test://'

when@dev:
    framework:
        messenger:
            transports:
                # replace with your transport name here (e.g., my_transport: 'in-memory://')
                # For more Messenger testing tools, see https://github.com/zenstruck/messenger-test
                async: 'sync://'

As you noticed, in test environment, we will be using the zenstruck/messenger-test library, and in dev environment we will send email still synchronously.

You may have also noticed that it uses an ENV variable MESSENGER_TRANSPORT_DSN. Please add a definition for it in your .env file:

MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=1

Install supervisor

Install supervisor package, e.g.:

sudo apt-get install supervisor;

Add the below configuration in /etc/supervisor/conf.d/messenger-worker.conf.

[program:messenger-consume]
command=php /path/to/symfony/bin/console messenger:consume async --limit=10 -v
user=www-data
numprocs=1
startsecs=0
autostart=true
autorestart=true
startretries=10
process_name=%(program_name)s_%(process_num)02d

Update your tests

The zenstruck/messenger-test library provides many useful methods to assert email sending.

Ensure that your test class implements the following trait:

use Zenstruck\Messenger\Test\InteractsWithMessenger;
use Symfony\Component\Mailer\Messenger\SendEmailMessage;

// Ensure one email is sent
$this->transport()->queue()->assertNotEmpty();
$this->transport()->queue()->assertCount(1);
$this->transport()->queue()->assertContains(SendEmailMessage::class);

// Ensure email contains $string
$messages = $this->transport()->queue()->messages(SendEmailMessage::class);
/** @var Email $email */
$email = $messages[0]->getMessage();
/** @var TextPart $textPart */
$textPart = $email->getBody();
$emailBody = $textPart->getBody();
$this->assertStringContainsString($string, $emailBody);
comments powered by Disqus

Related Posts

Christmas 2023

Christmas 2023

Merry Christmas! It’s our first Christmas in Finland. Most of the below photos are from December, 2023.

Read More
Khao Lak, Phuket and relocation from Ipoh to Helsinki

Khao Lak, Phuket and relocation from Ipoh to Helsinki

We relocated from Ipoh, Malaysia to Helsinki, Finland in December 2023.

Read More
Visit at the Natural History Museum

Visit at the Natural History Museum

Today we visited the Natural History Museum with the kids. It’s conveniently located just 5 min walk from Kamppi, so we decided to give it a quick visit.

Read More