This post is part 6 in a series about Symfony Messenger.
- Introducing Symfony Messenger integrations with Drupal
- Symfony Messenger’ message and message handlers, and comparison with @QueueWorker
- Real-time: Symfony Messenger’ Consume command and prioritised messages
- Automatic message scheduling and replacing hook_cron
- Adding real-time processing to QueueWorker plugins
- Making Symfony Mailer asynchronous: integration with Symfony Messenger
- Displaying notifications when Symfony Messenger messages are processed
- Future of Symfony Messenger in Drupal
Since Swift Mailer and its Drupal contrib integration were recently deprecated, many projects have naturally switched to its replacement: Symfony Mailer, either via Drupal Symfony Mailer or Drupal Symfony Mailer Lite.
This post outlines how you can take advantage of Symfony Mailer’s first class integration with Symfony Messenger brought to Drupal via the SM project. This integration allows for dispatching emails off-thread, potentially improving performance of the dispatching (usually web-) thread by offloading email-related tasks to dedicated Symfony Messenger workers. This setup can be considered an alternative to using Queue Mail.
As of writing, of the two Symfony Mailer implementations in contrib, Drupal Symfony Mailer Lite has built in support for Symfony Messenger. Drupal Symfony Mailer does not yet support it, an issue and merge request exist to add it. Apply a patch until the changes are merged.
Symfony Messenger itself does not require any special configuration, other than installing SM.
To run asynchronously, the
\Symfony\Component\Mailer\Messenger\SendEmailMessage message must have routing configuration to a transport. Or at least the fallback transport must be configured. Without transport configuration, Emails will still be dispatched through Messenger, however they will be executed synchronously in the same thread they were dispatched.
If you happen to have both Symfony Mailer and Symfony Messenger installed but do not want emails to be sent asynchronously, you can configure routing for the
\Symfony\Component\Mailer\Messenger\SendEmailMessage message to instead use the
If you’re using the SM Config submodule:
Sending emails and dispatching emails
Emails may be dispatched using the usual Drupal mechanism, or you can dispatch using Symfony Mailer directly by constructing an email object:
$email = (new \Symfony\Component\Mime\Email())
->text('Some sample text.')
->html('<p>some <strong>sample</strong> text.</p>');
/** @var \Symfony\Component\Mailer\MailerInterface $mailer */
$mailer = \Drupal::service(\Symfony\Component\Mailer\MailerInterface::class);
send method is executed, Mailer checks Messenger is available, creates a new
SendEmailMessage message to wrap the
\Symfony\Component\Mime\Email object. Then dispatches
SendEmailMessage to the messenger bus.
As is typical with Symfony Messenger, email messages must be serialisable. Avoid including any Drupal entities or service references in an email object, and render email contents before sending it.
To process email messages, run the worker with
sm messenger:consume. This command will either listen or poll for messages and execute them in a dedicated thread, ensuring quick processing after they are dispatched. For more information on the worker, please refer to post 3 of this series.
In the next post, we’ll explore how to add a user interface to notify users when relevant tasks have been processed.
Projects no longer need to rely on unpredictable processing time frames. The SM project can intercept legacy Drupal
@QueueWorker items and insert them into the Symfony Messenger message bus, effectively giving existing core and contrib queue workers jobs real-time processing capabilities.
Symfony Scheduler provides a viable replacement to
hook_cron wherein messages can be scheduled for dispatch at a predefined interval. Messages are dispatched the moment they are scheduled, and there is no message duplication, making tasks more reliable and efficient.
The greatest advantage of Symfony Messenger is arguably the ability to send and process messages in a different thread almost immediately. This post covers the worker that powers this functionality.