MJML — Bringing HTML Emails out of the dark ages

Chris Beldam
Engineering at Runa
10 min readAug 6, 2021

If you’re an engineer looking to join a mission-driven company with an amazing engineering culture — check out our careers page!

At WeGift we use emails to communicate with our customers about changes on our platform. For example, your latest invoice has been generated or you’ve been granted access to a new product.

All of these emails contain critical information and we’ve attempted to present them in a design which is in keeping with our brand. However, the more we have customised our emails, the more the engineering experience has become painful, especially as the number of emails we send has grown and they’ve needed to work on a wider range of devices.

In the post we’ll talk about the steps I took to understand the existing problems with how we built our email templates at WeGift, the issues behind email clients and how we eventually settled on a solution to improve the process of generating email templates.

Why do we use HTML tables for emails?

The default way of writing email templates is with HTML tables. It used to be that all webpages were built in this way but web page layout has since moved on to Flexbox, CSS Grid and other layout libraries e.g. Bootstrap, which allow us more control over the layout of our pages. Emails however are largely still stuck using HTML tables for their layout.

You may be thinking, why then do we use tables to construct emails when the rest of the web has moved on so much? The big issue here is that nearly every single email client uses a different rendering engine. Rendering engines are what take the HTML you’ve written and lay it out onto the screen for users to see. The fragmentation of rendering engines presents a massive challenge when attempting to make emails compatible with various email clients.

The three most common email clients are Gmail, Outlook and Apple Mail. You’d imagine that they’d all support the same attributes and CSS properties right? Well… no that’s far from the truth. Outlook renders using the Microsoft Word templating engine whilst Gmail and Apple use their own. This presents you a problem as a developer. You want to add a border-radius, use a background image? Well you’d better check that it’s supported on the rendering engine for the clients your users are receiving their emails in.

Apple Mail on both mobile and desktop uses Safari’s WebKit engine. Anyone who’s ever written any CSS can tell you that WebKit is even more of a pain, often requiring special CSS properties which only work on WebKit e.g. `position: sticky` has to be `position: webkit-sticky`.

When working on email templates I often spend my time looking at https://www.caniemail.com/ which provides a good overview of whether an attribute or a CSS property is actually supported on specific email clients. This is extremely useful for older clients. Do you have a customer running AOL mail or Yahoo mail? Well good luck attempting to make your email work on those clients without using this website. These extremely old clients are often not updated to support recent properties and attributes.

HTML table elements have been around for a long time and have universal support in web browsers, and in most email client rendering engines. Therefore they are still one of the best ways to make sure that the structure and layout of your email looks the same across the myriad of different email clients that are still in use, even with the issues raised above.

What are the issues with using HTML tables?

Whilst using HTML tables allows us to gain a base level of structure across all clients it does present a few engineering headaches.

HTML tables can become extremely long and once your file is longer than 100 lines of nested table elements it becomes extremely difficult to read, debug and generally understand if you’re not the engineer who’s written it. You can of course add comments like <! — Inner Border →or <! — CTA Button → to try to help others understand the layout but in my opinion once you go down this road you’ve essentially already conceded that your file has become unmaintainable.

You may also need to repeat a lot of the same code across different emails. If you’re not using some sort of templating engine like Jinja where you can do {% extends ‘email/campaign_base.html’ %} then you’re going to be writing the same code over and over again. We all know that one of the principles of software development is DRY (don’t repeat yourself) and HTML tables make it near impossible to stick to that principle without a huge amount of time and effort.

There is also the issue that, if you’ve only recently taken up software engineering you’re likely not very familiar with tables. I know that until I wrote my first email template here at WeGift I’d used table elements very sparingly. Whilst it’s quick and easy to pick up, it requires a different way of thinking about layouts compared to CSS Grid or Flexbox.

Writing plain HTML tables without using a framework on top is also not the best idea if you want to make your emails responsive. There are an increasing number of devices which people use to read their emails: Desktop, Mobile, Tablet etc. To make your emails look professional you need them to work on many devices and at the most common screen resolutions. It is possible to make HTML tables responsive without using a framework and only using CSS but it’s more time consuming.

So, how did we improve this experience?

I became increasingly frustrated at needing to spend time debugging ancient clients and fixing weird issues between Gmail and Outlook. There was also a reluctance to touch email templates, it was a cumbersome process which we’d always wanted to improve but hadn’t yet had the time to do so.

I decided to take the typical engineering approach of `There must be a library for this`. This problem is not a new one, it’s been an ongoing problem for years and so, logically, someone must have developed a framework or a library to solve this problem, or at the very least ease the pain of constructing email templates.

I spent some time looking on the internet for a library or a framework that would solve this problem for me. I was a little surprised at how few there were that seemed to be at a professional level and are being regularly maintained. Especially due to the fact most businesses send out emails to their customers.

The couple I liked the look of were:

  1. MJML
  2. Foundation for email

I settled on MJML after trying both for the following reasons:

  1. Better documentation — After looking through the documentation for both MJML and foundation, I felt I had a much better understanding of MJML from the first few articles than I did foundation. If I was able to pick up MJML just from briefly reading their documentation and playing with some of their examples then it would be easy for other engineers in the team to pick this up as well.
  2. An active community — MJML has a slack channel where you can go to ask any questions and get support. The ability to get questions answered quickly was a massive selling point. They’re also very reactive to any GitHub issues raised, where they can offer support. I raised a GitHub issue and they responded to me within a few hours, offering help and suggestions.
  3. Actively being maintained — At the time of writing this, foundation for emails has not had a new release since June 2020. MJML however was updated 19 days ago (June 2021). Therefore when bringing a new package into our codebase it always makes more sense to have one that’s still being actively fixed, updated and maintained.

MJML

MJML is a markup language with its own simple and unique syntax which is transpiled into HTML tables. Hang on.. I thought you said HTML tables had issues? I did! The advantage of using MJML is when it’s transpiled, it is turned into quality responsive HTML, compliant with best practices. Therefore it tries to mitigate the differences between email clients. I can therefore be more confident that whilst it looks good on Gmail, it’s also more likely to work for other clients e.g. Outlook.

You might be thinking, what advantages does MJML hold over tables? For one, the syntax you write is extremely different. A good example is how you’d write a button. The screenshot below shows MJML at the top, then equivalent HTML at the bottom. You can see that the syntax when using HTML tables is much more complex. What this means is that it’s both easy to read MJML, especially if you’re just briefly reading through it and it’s also very easy to write.

MJML has built in components (such as the button above) which means as a developer you do not need to reinvent the wheel. You want a title? A button? These elements already exist for you and with their wide range of customisable attributes you can easily adapt them to your own needs.

As I mentioned earlier, we also use Jinja templating at WeGift. This combines perfectly well with MJML. You want to pass a variable into an email? Perhaps the customer name? Or maybe the number of new brands you’ve got access to? No problem! This is extremely simple to do. MJML on it’s own doesn’t contain any conditional logic, it allows you to implement another framework over the top of it.

If you’d like to include custom variables in your email, perhaps the customer name or maybe their organisation. You simple pass the variable to your template on the backend and simple call it in your MJML file

They also have a live editor https://mjml.io/try-it-live. This allows you to visually see both the HTML being generated and also a preview of what it’s going to look like. This is an amazing tool when it comes to learning MJML but also when it comes to debugging. Not sure why there is a button out of line? The live editor can easily help you debug the reason why, with handy syntax error highlighting. You can also get syntax checking when you transpile your MJML files into HTML, you can use a handy library such as https://github.com/mjmlio/gulp-mjml to allow you to amend the MJML engine and how the config determines what level of validation to do.

Our findings

We found that writing templates in MJML was much quicker and easier than it had been when writing pure HTML table format. Sure, there was a little learning curve but if you treat it like writing front end components then it’s extremely easy to pick up.

The setup didn’t take long at all, we configured a gulp task using gulp-mjml to tell our app where we wished to place the HTML files generated. We added it to our gulp watch task so we could easily make changes on the fly and see what our templates would render out to.

We also found that after the switch to MJML for new email templates, more devs were able to and wanted to write templates. That reduced the load on specific engineers and also up-skilled the team, so any of us were able to pick this up in the future.

The main thing MJML did for us was improve our confidence in the code we were writing. When we make an email template, check it and go through the QA/Code review process we can now be more confident that our code is clean, reusable and also will work on a wider variety of email clients.

However MJML isn’t magic, it cannot fix every single imperfection and incompatibility between email clients. We still sometimes have to make decisions about whether we’re willing to accept slight differences in how our emails are rendered between email clients. This happens less often now we’re using MJML than it did previously and luckily most of these differences are so small that they’re inconsequential to the overall email experience.

Summary — Future of email templating at WeGift

So now you’ve seen what benefits we gained by using MJML in some of our email templates. You may be thinking, what’s the future for email templates at WeGift? Well, MJML is the likely solution for now. You’ve seen how it’s improved our efficiency at writing emails, reduced disparities between email clients, helped us make our current emails responsive and also improved re-usability of our code.

Whilst we’ve not converted all of our existing email templates to MJML. It has become the default framework to use for any new email templates we create. Eventually I’d like us to convert them all but that’s a task for another time!

Come work at WeGift!

We’re building an engineering team where people can do their best work. We want to hire talented engineers who see WeGift as an opportunity to grow and to make a huge impact! We have structures in place from hiring and levelling to how we make technical decisions that really allow people to thrive. If you’re interested to find out more about life at WeGift and how you can join us on our mission to revolutionise the $20 Trillion B2C pay-out market, then take a look at our careers page or get in touch with Oliver Lochhead (oliver.lochhead@wegift.io) in the Talent Team.

--

--