Using MJML email templates with Symfony

Sylvain Fabre
AssoConnect
Published in
4 min readJun 5, 2019

In this article we will learn how to use MJML with Symfony and Twig to make beautiful responsive emails that work with every client.

What is MJML?

Emails are the only development related matter that has stayed in the past for the last decade: you have to use old HTML structure like <table> with inline CSS style in order to get your email correctly displayed in any email client.

Nobody knows how to work with this today and testing a template with the email clients out there is a real pain.

Here comes MJML! It stands for MailJet Markup Language, is written in ReactJS and helps you use HTML-like markup to make beautiful and responsive email templates.
You can try it here https://mjml.io/try-it-live

It comes with a compiler: you write MJML and you get ready-to-use HTML.

Ok, so what’s wrong?

You write Twig templates with MJML code. Every time you want to send an email you have to:
- render the Twig template with your custom variables (like a customer’s firstname as greetings)
- compile the MJML code to HTML

The first issue comes from the compilation speed: it takes several seconds so it would slow down your processes.
An alternative solution is to first compile all your templates and render with Twig but you need to do it every time you work on them.

The second issue is standardization. For instance, if you always want big red button with rounded corners then you have to repeat this MJML code everywhere:

<mj-button background-color="red" font-size="40px" border-radius="5px" font-weight="bold">
Click me!
</mj-button>

MJML can be easily extended with custom tags to reuse your styling rules across multiple templates but it is done with ReactJS and you don’t want to mix ReactJS and PHP in your files.

Our solution at AssoConnect

We have created this bundle: https://github.com/assoconnect/mjml-bundle

It has two key features:
- custom tags are created with PHP classes
- MJML compilation happens during the cache warmup

Let’s see how to create our big red button with rounded corners with two possible heights : large (default) and small

Custom tags

We spend a lot of time thinking about standardization at AssoConnect:
- we want to respect our style guide across our features and content
- we don’t want to copy paste similar code in our code base

Compilation

MJML compilation happens during the cache warmup and any change made to the source files will invalidate the cache so you don’t worry about compilation. This is another key feature for the developer experience at AssoConnect: working on a codebase must require as few steps as possible to be pain-free.

You can use whatever Twig expressions you want in the MJML code as they are kept during MJML to HTML compilation.

Installation

First you need to install MJML:

npm install — global mjml

Then install the bundle with composer:

composer require assoconnect/mjml-bundle

Red button custom tag

Custom tags are created with PHP classes:

<?php# /MJMLTag/RedButtonTag.phpnamespace App\MJMLTag;use Assoconnect\MJMLBundle\Tag\TagInterface;class RedButtonTag implements TagInterface
{
public function getName(): string
{
// Write here the name of the custom tag you are creating
return 'acme-button';
}
public function getAttributes() : iterable{
// List here the default attributes of your tag
return [
'size' => 'big'
];
}

public function getMJML(string $body, iterable $attributes): string
{
if($attributes['size'] === 'big') {
$height = 200;
} else {
$height = 100;
}
return <<<EOT
<mj-button
background-color="red"
font-size="40px"
border-radius="5px"
font-weight="bold"
height="{$height}px"
>{$body}</mj-button>
EOT;
}
}

Let’s use our red button

We just have to create a template in templates/mjml/my_template.mjml.twig. It follows the naming guideline of Symfony:
- content is MJML
- template engine is Twig

# templates/mjml/my_template.mjml.twig<mjml>
<mj-body>
<mj-section>
<mj-column>
<mj-text>Hello {{ firstname }}</mj-text> <acme-button size="small">
Click me!
</mj-button>

</mj-column>
</mj-section>
</mj-body>
</mjml>

MJML contains a lot of tags for common use-case, check out their documentation to know more.
I also recommend to use their online editor to design your emails.

Then you use it with Twig like this:

<?php
# src/Service/EmailerService.php
namespace App\Service;
use Twig\Environment;class EmailerService
{
protected $twig;

public function __construct(Environment $twig)
{
$this->twig = $twig;
}

public function sendEmail()
{
$templateFile = 'mjml/my_template.html.twig';

$template = $this->twig->load($templateFile);

$html = $template->render([
// place here the variables to resolve in your template
'firstname' => 'John',
]);

// implement here your email sending logic
}
}

When you run this code:
- Symfony will warmup the cache (or you can call the compiler) which will create templates/mjml/my_template.html.twig
- Twig will render templates/mjml/my_template.html.twig
- our ready-to-use HTML will be stored in the $html variable

You can now make beautiful and responsive emails templates with Twig right from Symfony, happy emailing!

--

--

Sylvain Fabre
AssoConnect

Happy CTO at https://www.assoconnect.com a SaaS product to help non-profits focus on their missions. We’re hiring!