Sending html mails in Drupal 8/9 programmatically. An example Drupal module including Twig template

Aug 18, 2020

(Available as freelancer)
Joris Snoek
Business Consultant
/ Drupal Developer

Last month we implemented a user story for our Drupal distro OpenLucius: we needed to send clean html from Drupal 9 modules. This should also be scalable, as in: different modules should be able to mail different content in a consistent template. After some time of coding and trying different modules and options within those modules, we finally got it together in a nice, clean and scalable way.

So I thought more people would like to send nice html mails from Drupal 8/9 programmatically: I extracted the code and produced an isolated example module, even installable.

Copy and run off

I published it here on Github, so you can copy it and run off with it to do whatever you need. At the moment it's not a published project with all kinds of configurable stuff.

Install instructions

Clone this repo and install it like a custom module in Drupal; I haven't set it up with Composer / Packagist. The drupal module has a dependency on Swiftmailer module, which has a dependency on the Mailsystem Drupal module. After you installed it, these three modules should be enabled:

Config instructions

Configure Mailsystem
Head to /admin/config/system/mailsystem and copy this config:

  1. Formatter: choose 'Swiftmailer'
  2. Sender: choose 'Default PHP Mailer', somehow it didn't work when I choose 'Swiftmailer' here. That took a loooong time to figure out.
  3. Choose your active theme (custom or contrib), this is needed so Swiftmailer will detect your clean html Twig override for the emails:

Copy Twig template override

Copy the file 'swiftmailer--lucius-html-mail.html.twig' to your custom theme's '/templates' folder. This is the clean html email template override which Swiftmailer will use later on and you can tune anyway you like.

Swiftmailer config
FYI, all 'Transport settings' in Swiftmailer config can be left to default (see /config/swiftmailer/transport).

Explaining the Drupal code

1. hook_mail() in .module file

First of all, to make use of the Drupal's mailing system: you need to implement hook_mail in the .module file:

  1. Get global site name -and email.
  2. This took a loooooooooooooooooooong time to figure out, but you need to define these headers to make Drupal html mails work.
  3. Additional parameters to fill Twig html email template.

2. Custom Drupal Mail Service 'lucius_html_mail.mail'.

I implemented a custom Drupal Service 'lucius_html_mail.mail', for among other things scalability: this service handles all generic stuff for email sending, while other modules can use this service via Dependency injection and send mails with different parameters: message content in this case.

  1. Define our custom Mail Service and inject 2 external Services.
  2. Constructor to facilitate the 2 external Services.
  3. Build the mailing variables, loop through users, get name and email, finally send mails.

3. Drupal Route and Controller to test and send example emails

I defined a route '/send_test_mail'. If you head over to that url in your browser, the code in sendTestMail() will execute.

If all is ok: all users will receive the example mail.

!) So make sure you're testing this in an environment where mails can't go to the outside world, we use local Docker with Mailhog for example. (!

  1. Drupal's Dependency Injection in action: inject our custom Service 'lucius_html_mail.mail'.
  2. Prepare all paramaters for the mail with static example texts. Then send the mails via our Service method 'sendMail()'.
  3. Simple helper function to get all users.

So, if you head over to '/send_test_mail', all users should receive an email that looks like this:

4. Custom Twig override file 'swiftmailer--lucius-html-mail.html.twig'

As mentioned earlier, swiftmailer--lucius-html-mail.html.twig should be copied somewhere to your custom theme's /templates folder. I found this html code in this open source repo. It's even responsive and uses a lot of inline styles, needed to make it compatible to all major email clients.

As you can see, there are Twig variables, mostly I use the values in the $message array. These variables match the parameters we build earlier. Function Lucius_html_mail_mail() (hook_mail) turned our parameters into one $message array, which can be used in the Twig template as shown in above image.

So tune this template anyway you like, or implement a complete new one with other variables. It's all in your hands now, make it the way you want in a clean, responsive and scalable way!

Handy: Twig template file override suggestions

If you turn on Development mode in Drupal, you can see all template suggestions to go even further down/up the road:

Wrap up

Ok, that's it for now. Hopefully you're now able to implement nice clean emails for your Drupal 8/9 system. If you need more explanation, or you can't get it to work: please let me know.


Need even
more knowlegde?