A new solution to Drupal's messy mailing approach
Drupal core's mail module has been a mess for a long time and has seemingly not kept up with the modernization of the rest of the stack. Using the hook system to send emails feels archaic; therefore, a while ago, we started developing a module that:
- Allows for defining emails in code via a clean and powerful (chaining) object-oriented interface
- Supports sending HTML emails without any fuss
- Optionally allows for defining (HTML) emails as Twig templates
- Allows for translating said emails by simply adding more Twig templates in different languages (multilingual capabilities)
- Integrates with Drupal's default framework for email manipulation, which handles the transporting and formatting of outgoing emails
- Can be used as the backend for bespoke UI-driven mailing solutions
We have been using and improving Mail Composer and would love for that work to be reused and further built upon.
Let's talk code
Just sending an inline email
... is as simple as:
/** @var \Drupal\mail_composer\Manager $manager */
$manager = \Drupal::service('mail_composer.manager');
$manager
->compose()
->setFrom('foobar@foo.bar')
->setTo('foo@bar.bar')
->setSubject('Test subject')
->setBody(['This is the body of the email.'])
->send();Neat, isn't it?
Multilingual HTML emails
In order to send HTML emails, install Mail System and the replacement for the now-unsupported Swift Mailer: Symfony Mailer Lite. The only thing left to do is set Symfony Mailer Lite as the default formatter and sender in /admin/config/system/mailsystem:

That's all that is necessary to send valid HTML emails.
Now let's dive into defining emails in code.
1. Define an Email
Drupal\my_module\TestEmail
namespace Drupal\my_module;
use Drupal\mail_composer\Email;
class TestEmail extends Email {
/**
* @inheritDoc
*/
public function getSubject(): string {
return $this->t('My test email');
}
/**
* @inheritDoc
*/
public function getFrom(): string {
return 'foobar@foo.bar';
}
}Bear in mind, TestEmail::getSubject() and TestEmail::getFrom() are optional; you can set or override these values later during runtime when using the manager.
2. Define email content as Twig templates
my_module/templates/emails/test-email.html.twig
<p>This is the body of the <strong>email</strong> with variable {{ my_variable_1 }} and
{{ my_variable_2 }}.</p>3. Translate the email into (e.g.) German
To translate the email content, just create another twig template with the correct country code in its name. The translation is picked up automatically when sending the email.
my_module/templates/emails/test-email.de.html.twig
<p>Das ist der Textkörper der <strong>E-Mail</strong> mit der Variablen {{ my_variable_1 }} und
{{ my_variable_2 }}.</p>Defining email content as Twig templates is also optional (though preferred). You could alternatively set this content when using the manager via Manager::setBody() like an animal.
4. Send the email
/** @var \Drupal\mail_composer\Manager $manager */
$manager = \Drupal::service('mail_composer.manager');
$variables = ['my_variable_1' => 'foo', 'my_variable_2' => 'bar'];
$email = new \Drupal\my_module\TestEmail($variables);
$manager->compose($email)->setTo('foo@bar.bar')->send();Try it and let me know what you think
If you are interested in seeing more examples, check out the module's documentation.
This module has been in production on two of our large-scale sites and has been working very well. Please download and use it, and let me know what you think below (or create requests in the module's queue): Mail Composer.
Add new comment