Using MJML with Twig

Quentin Ferrer
3 min readApr 3, 2020

MJML is an email templating language created by Mailjet. It provides features easy to use for reduce the pain of coding responsive emails.

Twig is a template engine powered by Symfony. It is an awesome option for rendering HTML. It got some nice features like blocks and inheritance.

Why use MJML and Twig together ?

Using MJML and Twig together allows you to use Twig features with MJML. It’s like adding an extension to MJML. Let me show you below the Twig features I use with MJML.

Layout

Don’t repeat yourself and create a layout that you can extend for all your emails.

layout.mjml.twig

<mjml>
<mj-body>
<mj-section>
<mj-column>
<mj-text>Header</mj-text>
</mj-column>
</mj-section>
{% block body %}{% endblock %}
<mj-section>
<mj-column>
<mj-text>Footer</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>

newsletter.mjml.twig

{% extends 'layout.mjml.twig' %}

{% block body %}
<mj-section>
<mj-column>
<mj-text>Hello</mj-text>
</mj-column>
</mj-section>
{% endblock %}

Partial Templates

Reduce your code size and create partial email templates.

header.mjml.twig

<mj-section>
<mj-column>
<mj-text>Header</mj-text>
</mj-column>
</mj-section>

footer.mjml.twig

<mj-section>
<mj-column>
<mj-text>Footer</mj-text>
</mj-column>
</mj-section>

layout.mjml.twig

<mjml>
<mj-body>
{% include 'header.mjml.twig' %}
{% block body %}{% endblock %}
{% include 'footer.mjml.twig' %}
</mj-body>
</mjml>

Variables

All emails templates need to be personalized. The most commonly used variables are personalization variables, which allow you to dynamically include information about your recipients.

newsletter.mjml.twig

{% extends 'layout.mjml.twig' %}

{% block body %}
<mj-section>
<mj-column>
<mj-text>Hello {{ username }}</mj-text>
</mj-column>
</mj-section>
{% endblock %}

Translations

The Translator component allows you to create emails in multi-languages by using a specialized Twig tag trans.

newsletter.mjml.twig

{% extends 'layout.mjml.twig' %}

{% block body %}
<mj-section>
<mj-column>
<mj-text>{{ "Hello"|trans }} {{ username }}</mj-text>
</mj-column>
</mj-section>
{% endblock %}

And many others

You have as many possibilities as Twig has features.

The MJML Extension

Twig extensions are packages that add new features to Twig. I created a library that provides integration with MJML via the MjmlExtension.

The MJML extension add a mjml_to_html filter, which can be used to convert the entire email contents from MJML to HTML:

{% apply mjml_to_html %}
<mjml>
<mj-body>
<mj-section>
<mj-column>
<mj-text>Hello {{ username }}</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>
{% endapply %}

Because we have two ways for rendering MJML to HML, the extension depends on a renderer:

  • BinaryRenderer: using the MJML library. You will have to provide the location of the MJML binary. Don’t forget to install it with the Node package manager.
  • ApiRenderer: using the MJML API. Nothing to install. You will have to provide the credentials to access of the API.

Thanks to the library MJML in PHP for make easier the integration of MJML in PHP. Read the article Rendering MJML in PHP for more informations.

Installation

composer require qferr/mjml-twig

Basics

<?php
require_once 'vendor/autoload.php';
use \Qferrer\Mjml\Renderer\ApiRenderer;
use \Qferrer\Mjml\Renderer\BinaryRenderer;
use \Qferrer\Mjml\Twig\MjmlExtension;
$loader = new \Twig\Loader\FilesystemLoader(__DIR__ . '/templates');
$twig = new \Twig\Environment($loader);
$renderer = new BinaryRenderer(__DIR__ . '/node_modules/.bin/mjml');
$renderer = new ApiRenderer('my-app-id','my-secret-key');
$twig->addExtension(new MjmlExtension($renderer));
$html = $twig->render('newsletter.mjml.twig', [
'username' => 'Quentin'
])

You can now start using MJML in any Twig template.

Note: Remove the renderer you don’t want to use.

Bonus: Integrating in Symfony

Register the MJML extension as a service and tag it with twig.extension.

# config/services.yaml
services:

mjml_renderer:
class: Qferrer\Mjml\Renderer\BinaryRenderer
arguments:
- '%kernel.project_dir%/node_modules/.bin/mjml'

mjml_renderer:
class: Qferrer\Mjml\Renderer\ApiRenderer
arguments:
- '%env(MJML_APP_ID)%'
- '%env(MJML_SECRET_KEY)%'

Qferrer\Mjml\Twig\MjmlExtension:
arguments: ['@mjml_renderer']
tags: ['twig.extension']

Note: Remove the renderer you don’t want to use.

--

--

Quentin Ferrer

I’m a french web developer. I develop in PHP with the popular Symfony framework.