Diving Deeper Into MJML
This was originally posted on Edenspiekermanm's Developer's Blog.
Last year, our colleague Hugo Giraudel wrote a blog post about integrating MJML into Rails. After working with it for a while in some of our other projects and with the recent upgrade of the language to version 3, we thought that it's time for an update!
Use MJML in a Rails Email Layout Setup
If you have different kinds of emails in your project, you might want to extract some of the shared logic into something you could reuse ("Don't Repeat Yourself!"). In Rails this is done through the Action Mailer Layouts. To do this you have to create a layout file and use yield
to render your partial inside the layout:
<!-- ./app/views/layouts/mjml_email.mjml -->
<mjml>
<mj-body>
<mj-container>
<%= yield %>
</mj-container>
</mj-body>
</mjml>
Now you can add this layout to your mailer class:
# ./app/mailers/user_mailer.rb
class UserMailer < ApplcationMailer::Base
layout: 'mjml_email' # <- add this
def welcome_email(user)
@name = user.name
mail(to: user.email) do |format|
format.mjml
end
end
end
All you have to do now is to remove the shared markups from your partial:
<!-- ./app/views/user_mailer/welcome_email.mjml.erb -->
<mj-section>
<mj-column>
<mj-text> Hello <%= @name %></mj-text>
</mj-column>
</mj-section>
Pay attention to the different file formats (when and where to use .mjml
or .mjml.erb
), otherwise it won't work!
Style Your MJML Templates
Creating email templates for the same project also means applying similar stylings to each of the templates. With the recent upgrade of MJML to version 3 it became a lot easier to reuse some of the stylings.
Within the mj-attributes
tag you can now define global stylings with mj-all
; create styling classes with mj-class
; or set the styling for a specific tag by just mentioning it:
<!-- ./app/views/layouts/mjml_email.mjml -->
<mjml>
<mj-head>
<mj-attributes>
<mj-all font-family="Arial" align="center"/>
<mj-class name="big" font-size="42px" />
<mj-section background-color="#ffff00"/>
<mj-attributes>
</mj-head>
<mj-body>
<mj-container>
<mj-section>
<mj-text mj-class="big">
<!-- This text will appear
* centered
* in Arial
* with a font-size of 42px
* on a bright yellow background
* 😎
-->
Hello World!
</mj-text>
</mj-section>
</mj-container>
</mj-body>
</mjml>
Another way to apply styling is to use mj-style
and write plain CSS in it. You can then use mj-raw
to write plain html and apply the CSS class:
<!-- ./app/views/layouts/mjml_email.mjml -->
<mjml>
<mj-head>
<mj-style>
.card-shadow {
margin-top: 1.6em;
-webkit-box-shadow: 0px 0px 15px 5px rgba(220,220,220,0.5);
-moz-box-shadow: 0px 0px 15px 5px rgba(220,220,220,0.5);
box-shadow: 0px 0px 15px 5px rgba(220,220,220,0.5);
}
</mj-style>
</mj-head>
<mj-body>
<mj-container>
<mj-section>
<mj-raw>
<!-- This adds some box-shadow to the image -->
<img class="card-shadow" src="http://example.com/image.jpg"/>
</mj-raw>
</mj-section>
</mj-container>
</mj-body>
</mjml>
Use Web Fonts
There are several ways of integrating web fonts into your emails. Campaign Monitor has a good introduction on that. MJML introduced the mj-font
tag to allow customized fonts, which should be sufficient in most of the cases:
<mjml>
<mj-head>
<mj-font name="Oswald" href="https://fonts.googleapis.com/css?family=Oswald" />
</mj-head>
<mj-body>
<mj-container>
<mj-section>
<mj-column>
<mj-text font-family="Oswald, Arial">
Hello World!
</mj-text>
</mj-column>
</mj-section>
</mj-container>
</mj-body>
</mjml>
But in one of our projects, we are loading fonts which are nested in the Rails assets folder structure ./app/assets/fonts/*
and we used to load it with @font-face
into our email templates.
To allow this again we had to hack MJML a bit, since we weren't able to find anything else to replace this.
<mjml>
<mj-head>
<!-- mj-font gets converted into @import -->
<mj-font name="Oswald" href="https://fonts.googleapis.com/css?family=Oswald" />
<mj-attributes>
<!-- This sets the global font of the template to FSBlakeLight and adds fallbacks. -->
<mj-all font-family="FSBlakeLight, Oswald, Arial"/>
</mj-attributes>
</mj-head>
<mj-body>
<mj-container>
<mj-raw>
<!--
This is a bit of a hack!
mj-raw only works within the mj-container tag.
-->
<style>
@font-face {
font-family: 'FSBlakeLight';
src: url("<%= asset_path('blake_light/fs_blake_web-light.eot') %>");
src: url("<%= asset_path('blake_light/fs_blake_web-light.woff') %>") format('woff'),
url("<%= asset_path('blake_light/fs_blake_web-light.ttf') %>") format('truetype'),
url("<%= asset_path('blake_light/fs_blake_web-light.svg#FSBlake-Light') %>") format('svg');
font-weight: normal;
font-style: normal;
}
</style>
</mj-raw>
<%= yield %>
</mj-container>
</mj-body>
</mjml>
Wrapping Up
We are still very happy with MJML and are trying to integrate it into more and more of our projects.
The version 3 upgrade helps a lot in terms of DRY up the code and to integrate standard styling elements. But when the design becomes more complex, we did reach some of the limits of MJML. But the lively discussions and issue requests online promise that new features are soon to come.
We've been testing our emails with Litmus, a service which allows us to see how our emails get rendered on different devices with different email clients. Since the switch to MJML we've more or less stopped experiencing broken stylings or missing elements. 🤘
PS.: the official list of MJML packages also has been a great source of help.