Stay Ahead in Ruby!
From development processes to the most useful gems, get it all straight in your inbox. Join our Ruby blog today!

Skip to main content

MJML

Attention! This article might be outdated, refer to latest documentation if solution does not work.
MJML - cover image
You’ve got mail!

Nowadays, emails are everywhere, every business is using email campaigns as a marketing tool to promote their products and deals, while email campaigns have become a standard to such an extent that we have thousands of emails in our mailboxes that we’ve got too lazy to open.

However, despite such a vast number of email campaigns, writing them is not a trivial matter and the reason why is each mailing service having its requirements for an email, not to mention different engines display those emails in different ways, meaning that not every email will look the same when you send them to multiple mailing services and it requires adapting your email code to fit all the needs.

Nowadays there are over a hundred email services and satisfying them all would be a work of a madman, setting this issue aside, another one rises, which is a favorite problem of a frontend developer - responsive design. Companies want to look presentable in every part of communication with their clients, which creates new challenges and new requirements for writing emails, responsive design is one such thing. Considering that nowadays we have so many devices with different screen resolutions and web browsers to support, writing emails becomes a hardcore challenge, and depending on the design complexity, using plain old methods becomes no longer practical. As developers, we need to search for new ways to make our lives easier, our solutions better and superior. And in this article, I am going to share with you my personal preference for writing email layouts, without further ado, let me introduce you to MJML!

Why and what is MJML? #

MJML is an HTML framework and a template that shortens HTML syntax by providing MJML-specific components that are later on interpreted into HTML. There are several reasons why MJML is a great choice for using instead of HTML + CSS:

  • It is much faster to develop an email design thanks to MJML components. MJML components contain a certain chunk of HTML and CSS code. Something a developer would write for 10 minutes, MJML got it out of the box with 1 tag.
  • It is very easy to use from the get-go.
  • It follows standard HTML syntax and has custom elements as components.
  • It has an IDE, that allows you to preview your emails as you write them. Normally this is impossible with HTML since browsers interpret HTML code a bit differently from how email engines do. You spend your whole day writing an HTML page that’s looking good in the browser, then send an email with that code just to get utterly disappointed. The preview window is specifically made for previewing emails as they would look in an email engine.
  • You can use MJML as a library for your project. Normally you would use a template to build an email and send it like ERB or HAML. MJML has its own template that you can integrate into your project. It supports popular choices for web development and there are integration libraries written for Rust, .NET, Elixir, Ruby, JS, Python, and PHP.
  • It is extensive. MJML community has provided plenty of extensions for MJML. These extensions add more features to it like drawing charts or adding a QR code to your email.
  • Libraries have a built-in validation system that can validate the syntax of your template in accordance with email engines’ requirements, which means that you won’t have to bother with looking at the code for an hour to find some syntax error or figure out why the template is not working. MJML got your back in these regards.
  • Responsive design is a huge headache when it comes to writing emails. For different email engines, there is a different problem with CSS. MJML solves this issue. As we’ve already mentioned, MJML is not using HTML, but custom components that contain some HTML and CSS chunks, and under the hood, they are already designed to be responsive. You write it right for one screen, you get it right for all screens.
  • MJML is quite flexible. You can even write an MJML template as a JSON object and then interpret it into HTML. Here is an example of MJML code written in JSON:
  let mjml2html = require('mjml')

  mjml2html({
    tagName: 'mjml',
    attributes: {},
    children: [{
        tagName: 'mj-body',
        attributes: {},
        children: [{
            tagName: 'mj-section',
            attributes: {},
            children: [{
                tagName: 'mj-column',
                attributes: {},
                children: [{
                    tagName: 'mj-image',
                    attributes: {
                        'width': '100px',
                        'src': '/assets/img/logo-small.png'
                    }
                },
                {
                    tagName: 'mj-divider',
                    attributes: {
                        'border-color' : '#F46E43'
                    }
                },
                {
                    tagName: 'mj-text',
                    attributes: {
                        'font-size': '20px',
                        'color': '#F45E43',
                        'font-family': 'Helvetica'
                    },
                    content: 'Hello World'
                }]
            }]
        }]
    }]
  })

MJML Client Compatibility #

For the most part, MJML is compatible with the most popular email services such as Gmail, Outlook, Yahoo Mail, Apple Mail, etc. However it also depends on what components you use and what platform you are trying to make your template compatible with. For example, some component for Apple Mail on an iOS device might be incompatible, while they might work just fine for OSX app of the Apple Mail.

Each component compatibility is documented and updated by MJML team, you can check the compatibility lists here: Compatibility link

MJML Ruby and Ruby on Rails Integration #

As we’ve already mentioned, the MJML community provided lots of tools for integrating MJML into the work environment for different programming languages, Ruby is no exception and there are 2 gems that we can use to integrate MJML into Ruby and Rails environments, those are MJML-Ruby and MJML-Rails.

Both gems have familiar usage, but the installation steps and configuration options differ.

MJML-Ruby Integration #

MJML-Ruby is a more simplified integration that can be used for plain Ruby scripts.

To install MJML-Ruby, to install MJML-RUBy, you need to:

  • add MJML-Ruby to your Gemfile:
  # Gemfile

  gem 'mjml-ruby', '~> 0.4', require: 'mjml'
  • Run bundle install

Then you can write a template with the .mjml extension and write the code there. You can use Ruby code inside of the template, just like you would do with ERB.

  <mj-text>Hello, <%= @user.name %></mj-text>

MJML-Rails Integration #

MJML-Rails is specifically designed for usage with Ruby on Rails. It allows writing MJML elements inside of HTML views. It validates emails and displays errors if your email layout is faulty by raising exceptions and errors. Another interesting feature of MJML-Rails is version control, as of now there are 4 versions of MJML. New additions to MJML provide better compatibility, but also add on new restrictions for writing components to provide better compatibility with email services.

To install MJML-Rails, you will need to:

  • Install Node.js version 6 or higher.
  • Add MJML-Rails to your Gemfile.
  # Gemfile

  gem 'mjml-rails'
  • Run bundle install
  • Run npm install
  • Run npm install mjml

And that’s it, now you can write your mjml views. However, for comfortable work, we should also tweak the configuration options that this gem provides:

  # config/initializers/mjml.rb
Mjml.setup do |config|
  # Use erb as a template language
  config.template_language = :erb

  # Ignore errors silently
  config.raise_render_exception = false

  # Optimize the size of your emails
  config.beautify = true
  config.minify = true

  # Render MJML templates with errors
  config.validation_level = "strict"

  # Use custom MJML binary with custom version
  config.mjml_binary = "/path/to/custom/mjml"
  config.mjml_binary_version_supported = "3.3.5"
end

There are some interesting things that MJML-Rails provides if you look at the config:

  • You can use MJML directly inside standard templates.
  • We can call out error rendering if something is wrong with our template
  • We can beautify and minify our generated HTML for readability and optimization.
  • We can validate our templates. I recommend using strict validation, which will prevent emails from being sent if there is something wrong with the template.
  • You can use different versions of MJML while using the latest version of the gem, if you are confident that your layout looks perfectly fine on all the targeted email services, then you might want to save that version of MJML for future utilization.

MJML Usage #

MJML is as easy to use as Bootstrap, there is amazing documentation that can tell and show you what each component does. Besides that MJML has an online editor in the case when you want to try MJML or just want to use it without installing anything. To break down MJML and why it’s useful, we are going to use an example provided by MJML itself.

Here you can see the code, that MJML provides when you enter their online editor:

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

          <mj-image width="100px" src="/assets/img/logo-small.png"></mj-image>

          <mj-divider border-color="#F45E43"></mj-divider>

          <mj-text font-size="20px" color="#F45E43" font-family="helvetica">Hello World</mj-text>

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

When writing emails, layouts are written through table templates, it was quite a popular way of writing a webpage back in the early 2000s, which then hopped on to a standard for writing a layout for email, although web development has moved forward, now we can use flexbox and grid, which make the life of a web developer much easier and providing developers responsive layout with the least amount of effort and time, sadly emails didn’t go forward in these regards and we still build email templates with table template. The code itself is quite simple and self-descriptive:

mjml html
mj-body body
mj-section table row
mj-column table column
mj-image image
mj-divider empty block with border
mj-text paragraph

You can see that child components have CSS styles assigned to them. Unfortunately, you can’t apply any styling to any component and this is connected to an issue with email engines rendering of the template. Each component has specifically assigned styling options which you can check in the documentation.

The final result of this code looks like this for a desktop screen:

MJML Code Result

And considering that MJML is fully powered with responsive design, it also works just fine on a mobile:

MJML Code Mobile Result

As you can see, for this result, we’ve written very little code, now let’s take a look at the HTML version of this page:

  <!doctype html>
  <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com🏢office">

  <head>
    <title>
    </title>
    <!--[if !mso]><!-->
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <!--<![endif]-->
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style type="text/css">
      #outlook a {
        padding: 0;
      }

      body {
        margin: 0;
        padding: 0;
        -webkit-text-size-adjust: 100%;
        -ms-text-size-adjust: 100%;
      }

      table,
      td {
        border-collapse: collapse;
        mso-table-lspace: 0pt;
        mso-table-rspace: 0pt;
      }

      img {
        border: 0;
        height: auto;
        line-height: 100%;
        outline: none;
        text-decoration: none;
        -ms-interpolation-mode: bicubic;
      }

      p {
        display: block;
        margin: 13px 0;
      }
    </style>
    <!--[if mso]>
          <noscript>
          <xml>
          <o:OfficeDocumentSettings>
            <o:AllowPNG/>
            <o:PixelsPerInch>96</o:PixelsPerInch>
          </o:OfficeDocumentSettings>
          </xml>
          </noscript>
          <![endif]-->
    <!--[if lte mso 11]>
          <style type="text/css">
            .mj-outlook-group-fix { width:100% !important; }
          </style>
          <![endif]-->
    <style type="text/css">
      @media only screen and (min-width:480px) {
        .mj-column-per-100 {
          width: 100% !important;
          max-width: 100%;
        }
      }
    </style>
    <style media="screen and (min-width:480px)">
      .moz-text-html .mj-column-per-100 {
        width: 100% !important;
        max-width: 100%;
      }
    </style>
    <style type="text/css">
      @media only screen and (max-width:480px) {
        table.mj-full-width-mobile {
          width: 100% !important;
        }

        td.mj-full-width-mobile {
          width: auto !important;
        }
      }
    </style>
  </head>

  <body style="word-spacing:normal;">
    <div style="">
      <!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
      <div style="margin:0px auto;max-width:600px;">
        <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
          <tbody>
            <tr>
              <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
                <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
                <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
                  <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
                    <tbody>
                      <tr>
                        <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
                          <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="border-collapse:collapse;border-spacing:0px;">
                            <tbody>
                              <tr>
                                <td style="width:100px;">
                                  <img height="auto" src="/assets/img/logo-small.png" style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:13px;" width="100" />
                                </td>
                              </tr>
                            </tbody>
                          </table>
                        </td>
                      </tr>
                      <tr>
                        <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
                          <p style="border-top:solid 4px #F45E43;font-size:1px;margin:0px auto;width:100%;">
                          </p>
                          <!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:solid 4px #F45E43;font-size:1px;margin:0px auto;width:550px;" role="presentation" width="550px" ><tr><td style="height:0;line-height:0;"> &nbsp;
  </td></tr></table><![endif]-->
                        </td>
                      </tr>
                      <tr>
                        <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
                          <div style="font-family:helvetica;font-size:20px;line-height:1;text-align:left;color:#F45E43;">Hello World</div>
                        </td>
                      </tr>
                    </tbody>
                  </table>
                </div>
                <!--[if mso | IE]></td></tr></table><![endif]-->
              </td>
            </tr>
          </tbody>
        </table>
      </div>
      <!--[if mso | IE]></td></tr></table><![endif]-->
    </div>
  </body>

  </html>

This is what the code for a responsive email template looks like and this is what we need to create such a small block. If you weren’t convinced to use MJML earlier, now I am pretty sure that you are, so I highly recommend trying this amazing tool.

We are ready to provide expert's help with your product
or build a new one from scratch for you!

Contact MobiDev’s tech experts!