Code With Ben Knox

MJML: Coding Great Email Templates

Frontend

January 24th, 2026

Have you ever heard of AWS Well Architected Framework? A "pillar" of the Well Architected Framework is operational excellence and a guiding principle they mention is automate where possible with code. Emails are easy to overlook for operational excellence, but using a framework called MJML you can create templates that exist in your repository alongside your application. Here's how to.

Prerequisites

- An understanding of how to use Node.js

Overview

It is easy to create and send an email using services like Mailchimp, just create a template once with some HTML and upload or pick one from the list of provided emails. I'm sure this is enough if there are only a few emails being sent out, but I can imagine this doesn't scale well if we are building an app where we would have dozens of emails to send (onboarding, password reset, support, etc.). For each of these emails we want to have the same branding and styles that match our app. And that's where something like Mailjet Markup Language, or MJML, comes in handy. Scalability here means that our emails are easier to update if branding changes. Using MJML we can write code for our email templates that are scalable and the workflow isn't difficult. Below are the steps you can take to start building your emails as code. Some other benefits of using MJML are, responsive emails, simplified mark up language, and it is available as an npm package.

Installation

MJML is easy to get going with, first step to get started is to install the npm package:

We can use this in a few different ways, either in the terminal as a command or in node script. We'll look at examples of both, but first let's look at an example of MJML markup language.

The Markup

MJML markup is very well documented and comes with a number of components out of the box. First we write the markup and use the npm package installed above to translate our email into an HTML document compatible with email clients. Here's a very simple example of the markup:

In the example above we have a few different components that should be mentioned:

1. The root wrapper, "<mjml>", which serves the same purpose as the HTML root tag

2. A tag, "<mj-head>", which is where our components related to the document head should be. In this example we are only using "<mj-title>", but there are other components provided that should be children of mj-head.

3. A tag, "<mj-body>", with a background color attribute. This tag contains all of our content and formatting, there are a number of provided components that belong as children of mj-body.


In the mj-body tag, there is a pattern that uses "<mj-section>" and "<mj-column>" with either "<mj-text>" and "<mj-image>" for its children.


This is how layouts work, the structure is generally: mj-body > mj-section > mj-column > child components. The tag mj-section component is repeated to generate rows in the email.


Let's save the MJML markup example above to a file called example-email.mjml in the same directory where you installed the npm package for mjml.

Translating to HTML Using the Terminal

Now that we have a simple email template written in mjml, we can translate that to a valid HTML email a few different ways. Let's start by opening a terminal in the same directory as the example-email.mjml and running the following command:

Now we should see a file that contains the following html:

Translating to HTML Programmatically

We can also create a node script to load the example-email.mjml file and create the email. This is useful when we are using an API to send emails, we can process the MJML at runtime in our application and send the generated HTML directly from the code. Here's how you can do that:

If we save and run that in a node script, we should see the translated HTML email on the console output of the script.


That script can be used with an email service that has an API (I use mailgun) to programmatically send emails in an app at runtime.

MJML Includes

As a final note, the "<mj-include>" component is just worth mentioning. It lets us include partial MJML files; and this gives us some ability to create email templates that have similar colors, branding, etc.

Conclusion

And that's how we can have our email templates codified in a way that actually makes sense, we looked at a simple responsive email with MJML markup, translated that into a real and valid HTML email that can be used, and wrote a simple node script that can be used with an API based email service. Happy emailing 📤

More About Frontend