Menu Search
Jump to the content X X
Smashing Conf San Francisco

We use ad-blockers as well, you know. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. upcoming SmashingConf San Francisco, dedicated to smart front-end techniques and design patterns.

Making Responsive HTML Email Coding Easy With MJML

Email is one of the best ways to engage with your users, especially during the holiday season. However, if you want to stand out, no matter how beautiful your emails are, you need to make sure they render correctly in your reader’s inbox, regardless of what email client they’re using. Creating responsive email is not an easy task, and there are various reasons for that.

First, there is no standard in the way email clients render HTML. This is true for email clients from different companies, such as Outlook and Apple Mail, but not only. Even different versions of Outlook, such as Outlook 2003, Outlook 2013 and Outlook.com, render HTML differently.

Then, while email clients render HTML, many of them have very limited support of it. Some email clients will just strip the head of your HTML file, including media queries, which is why inline styles are heavily recommended. On a good note, this is moving in the right direction with the Gmail update1.

Now, there are a few techniques out there to help email developers. You might be familiar with some of them, such as the hybrid approach2, the mobile-first approach3 or even the Fab Four technique4 by HTeuMeuLeu5. But because of the reasons stated earlier, and especially the lack of a standard, none of these techniques will enable you to tame all email clients at once.

Abstracting Away The Complexity Of Responsive Email With MJML Link

MJML is an open-source framework that abstracts away the complexity of responsive email. The idea behind it is pretty simple. Just as jQuery normalizes the DOM and abstracts low-level interactions and animations, MJML abstracts the low-level hacks for responsive emails with an easy syntax. MJML is responsive by design. This means you can forget about nested tables and conditional comments and, more generally, about making your email responsive. MJML does it for you.

Leveraging a semantic syntax and high-level components such as the carousel6 (yes, you can display an interactive image gallery within an email!), MJML is really easy to learn for anyone. Responsive emails are no longer only accessible to a handful of experts anymore.

Example of an MJML component: carousel.7
Example of an MJML component: carousel

Being easy to use doesn’t mean that MJML is not powerful. It just enables experts to streamline their development workflow, while still giving them the flexibility they need with lower-level components such as tables8.

For instance, our example email9 was coded in 788 lines of HTML10 and reproduced in fewer than 240 lines of MJML11.

The Approach Link

MJML is built in React12, a JavaScript library developed and maintained by Facebook, and it leverages the power of React’s components. The component names are semantic, starting with mj-, so that they are straightforward as well as easy to recognize and understand: mj-text, mj-image, mj-button, etc.

MJML will transpile to responsive HTML, following a mix of the mobile-first and hybrid coding approaches. Going mobile-first enables you to make sure that the most readable version is displayed by default in email clients that do not change the layout according to the device used.

For example, in Outlook.com, the mobile version will be displayed on both desktop and mobile (which is far more readable than a desktop version being displayed on mobile). The hybrid approach then enables the layout to change according to the device’s size wherever possible, using a mix of fallbacks, conditional comments, nested tables and media queries to target as many clients as possible. The layout degrades nicely, with multi-column layouts on desktop turning into single-column layouts on mobile.

2-column layout - desktop view.13
Two-column layout, desktop view
2-column layout - mobile view.14
Two-column layout, mobile view

Coding In MJML Link

Before we start the tutorial, let’s get ready to code in MJML. We have different ways to use MJML, such as running it locally15 or using the online editor2316. By choosing the online editor, you’ll be able to start immediately, but running it locally enables you to use MJML with your favorite code editor (with plugins for Atom17, Sublime Text18 and Vim19), task runners such as gulp-mjml20 and grunt-mjml21 and a lot more22.

For this tutorial, the online editor2316 is recommended because it doesn’t require any setup.

If you still want to use it locally, open your terminal and run npm install mjml -g (requires to have Node.js and npm24 installed).

Once MJML is installed, create a file named example.mjml (or any name you like) with some MJML and run mjml -r example.mjml in your terminal (make sure to be in the same folder as the file you’re rendering). It will render your MJML file in a file named example.html, with the responsive HTML inside. You can find all available options for the command line in the documentation25.

Creating Your First Newsletter With MJML Link

Now that you’re all set up, we can start creating a responsive newsletter together. To find inspiration, one of the best places around is ReallyGoodEmails26. I found a great example of a newsletter27 by Thrive Market28. Let’s recreate it with MJML!

(Brand names, logos and trademarks used herein remain the property of their respective owners, and their use does not imply any endorsement by or affiliation with Thrive Market.)

Thrive Market newsletter29
Thrive Market newsletter

First, here is what the basic layout30 of an MJML document looks like:

		
<mjml>
	<mj-head>
		<!-- Head components go here: https://mjml.io/documentation/#standard-head-components -->
	</mj-head>

	<!-- All of the content of our email will go in mj-body -->
	<mj-body>
		<!-- mj-container defines the default styling of our email, including the default width, set to 600px but overwritable -->
		<mj-container>
			<!-- Body components go here (https://mjml.io/documentation/#standard-body-components) -->
		</mj-container>
	</mj-body>
</mjml>
		

Streamlining The Style Link

While inlining is the norm in HTML to ensure responsiveness, MJML also allows you to create custom MJML classes and MJML styles, which will then automatically be inlined from the head of your MJML file31. In MJML, styles come as component attributes.

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

To start, we’ll set a default sans-serif font family for text components, because sans-serif is used for most text here. Then, we’ll create classes for elements used repeatedly, so that we don’t have to manually set styles over and over again. We could have created more custom classes and styles, but the most useful styles will be for:

  • buttons,
  • image descriptions,
  • text below the six icons in the footer.

Here, we’ll be leveraging head components32 in three ways:

  • Set a default padding of 0 for every component, using <mj-all />. This default padding can be overridden by manually specifying a padding directly on the components we are using.
  • Override the default font family of <mj-text>, using <mj-text /> in the head. Each time we use <mj-text>, the default font family will be sans-serif. We can still manually override this new default font by specifying a new one directly on the component.
  • Create classes using <mj-class /> and, more specifically, using the following mj-classes:
    • pill
      This is to design a nice button. Attributes worth noting are the background-color set to transparent and the inner-padding, used to size the button as we want.
    • desc
      This is to style the descriptions of the images in the two-column layout.
    • ico
      This is to style the text below the six icons just before the footer.
<mj-head>
  	<mj-title>Discover the latest trends</mj-title>
    <mj-attributes>
	    <mj-all padding="0" />
	    <mj-text font-family="sans-serif" color="#8e8b85" />
	    <mj-class name="pill" font-weight="700" color="#d5ad4b" border-radius="50" border="2px solid #d5ad4b" font-size="16px" line-height="16px" padding="8 20 20 20" inner-padding="10 75 10 75" background-color="transparent" />
	    <mj-class name="desc" font-family="Georgia" font-size="20px" color="#45495d" padding="25 5 10 10" />
	    <mj-class name="ico" font-family="Helvetica" font-size="14px" align="center" padding="0 0"/>
    </mj-attributes>
</mj-head>

(As you may have noticed, we have omitted the units on some attributes, such as padding. If you do so, MJML will output the attributes with px by default.)

Adding Content Link

Now that the styles are defined in the head (you can see here33 what your code should look like now), let’s start adding content to our email! MJML layouts are based on <mj-section>34 to create rows and <mj-column>3835 to create columns inside rows, which is very practical for email design. Note that, except for high-level components such as <mj-hero>36 and <mj-navbar>37, content should always be wrapped in a <mj-column>3835, which itself should go in a <mj-section>39, even when there is only one column in a section.

Let’s see this with two examples, the preheader and the header of the email.

Preheader Link

There’s nothing very fancy here. We’re just creating a text preheader using the <mj-text>40 component, wrapped in a column, and giving it some MJML styles.

Hack: <mj-text> enables you to use HTML directly inside MJML, granting you full control over the content and allowing you to use the <span> and <a> tags you’re used to, for example.

		
<mj-section padding="0" background-color="#eeebe7">
	<mj-column>
		<mj-text padding="0 2" align="center" font-size="10px">
			The latest tips, trends, recipes, and more
		</mj-text>
	</mj-column>
</mj-section>
		
Header of the email41
Header of the email

The header is a bit fancier but very easy to achieve with MJML. All we have to do is create a section that we’ll split into three equal columns (because columns are equal, we don’t even have to manually set the width). We’ll use images as in the original email, leveraging the explicit component <mj-image>42, which comes with the common attributes you would expect, including src, padding and border.

By default, columns will stack in the mobile version of our email. Here, because we want those three columns to stay side by side even on mobile, we’ll wrap them in an <mj-group>43 component, which will prevent the columns from stacking.

Hack: As noted in the documentation, due to a bug in iOS, you might have to use a minifier, or else the columns could stack on iPhone even if they’re wrapped in <mj-group>. The MJML command-line interface44 comes with a built-in minifier45 that you can use to run the -m option when rendering MJML.

<mj-section padding="0" background-color="#ffffff">
	<mj-group>
		<mj-column>
			<mj-image align="right" padding="40 0 0 0" width="100" href="https://thrivemarket.com/blog?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru"
						src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/blog_zpscedcgvla.jpg" alt="blog" title="blog" />
		</mj-column>
		<mj-column>
			<mj-image padding="15 0 0 0" href="https://thrivemarket.com/?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru"
				src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/thrive-logo-250_zps4lonavha.jpg" title="logo" alt="logo" />
		</mj-column>
		<mj-column>
			<mj-image align="left" padding="40 0 0 0" width="100" href="https://thrivemarket.com/customer/account/login/referer/aHR0cHM6Ly90aHJpdmVtYXJrZXQuY29tL2ludml0ZT9jY29kZT1LRzZPQ0QzSCZ1YWV4cHRpbWU9MTc3ODYzNzg2MiZ1YXRva2VuPTE0NjJiOTc3YzFmYTcwYjA5YjU4NWYzYTg5NDNkNzlhNzA3OWFiMzE0MzkzZmU4OTg1MmZkODNmZDA1YjYzMWUmdWlkPTUwMTk4NTAmdXRtX2NhbXBhaWduPWRheTgmdXRtX2NvbnRlbnQ9bGVhZF93ZWxjb21lJnV0bV9tZWRpdW09bGlmZWN5Y2xlJnV0bV9zb3VyY2U9c2FpbHRocnU,/"
				src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/refer_zpsnoo1uzvu.jpg" title="refer and win" alt="refer and win" />
		</mj-column>
	</mj-group>
</mj-section>
	

One-Column Layout for the GIF and CTA Link

We’ll create another section in which we’ll simply add an image, some text and a button. The only new component here is <mj-button>46, which should be clear enough and which comes with the standard attributes. Please note that you must specify an href, or else the text of the button might not display in some email clients.

<mj-section padding="20">
	<mj-column>
		<mj-image padding="5 0 23 0" width="200px" src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/566f6a67e871e_zpskalhjefi.gif" />
		<mj-text align="center" font-size="16px">
			Your daily destination for healthy living
		</mj-text>
		<mj-button padding="20 0 10 0" mj-class="pill" href="https://thrivemarket.com/blog?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">
			Read more
		</mj-button>
	</mj-column>
</mj-section>
	

Divider Between Body and Header Link

Yes, there’s a component for that, too! It’s a good practice to split different rows into different sections, instead of dumping everything into the same section, because that gives you more control over styling (especially through padding), and it also makes it easier to isolate any problems that occur.

<mj-section padding="0 0 20 0">
	<mj-column>
		<mj-divider border-width="5px" border-color="#EEEBE7" />
	</mj-column>
</mj-section>
	

We’ll use the same divider between the body and footer later.

Body Link

Now that we have a beautiful header47, let’s start with what seems to be the complex part of this email.

Two-Column Layout That Stacks on Mobile Link

Two-column layout48
Two-column layout

Here, we’ll create a section for each two-column row. Each column will consist of an image, a piece of text and a button. The good news is that, thanks to MJML’s hybrid approach, we don’t have to do anything to make the images stack on mobile. It’s responsive by default!

Regarding the styling, we don’t have much to do because we’re leveraging the mj-classes pill and desc, which we created earlier. All we need to do is add some padding to match the style of the original email.

Hack: Due to an issue with Outlook 2000, 2002 and 2003 ignoring the set width, it’s a good practice in MJML to set images to the sizes you want them to display at in those clients.

<mj-section padding="20 10 0 10">
	<mj-column>
		<mj-image width="280px" href="https://thrivemarket.com/blog/foods-for-happiness?uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&uid=5019850&utm_campaign=day8&utm_content=lead_welcome&utm_medium=lifecycle&utm_source=sailthru"
			src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/5-foods_zps9escvg7g.jpg" />
		<mj-text mj-class="desc">
			<a href="https://thrivemarket.com/blog/foods-for-happiness?uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&uid=5019850&utm_campaign=day8&utm_content=lead_welcome&utm_medium=lifecycle&utm_source=sailthru">
			5 Foods to Boost Your Happiness
			</a>
		</mj-text>
		<mj-button mj-class="pill" href="https://thrivemarket.com/blog/foods-for-happiness?uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&uid=5019850&utm_campaign=day8&utm_content=lead_welcome&utm_medium=lifecycle&utm_source=sailthru">
			Read more
		</mj-button>
	</mj-column>
	<mj-column>
		<mj-image width="280px" href="https://thrivemarket.com/blog/whiten-teeth-instantly-activated-charcoal?uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&uid=5019850&utm_campaign=day8&utm_content=lead_welcome&utm_medium=lifecycle&utm_source=sailthru"
			src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/teeth_zpsr1sycjxi.jpg" />
		<mj-text mj-class="desc">
			<a href="https://thrivemarket.com/blog/whiten-teeth-instantly-activated-charcoal?uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&uid=5019850&utm_campaign=day8&utm_content=lead_welcome&utm_medium=lifecycle&utm_source=sailthru">
				Whiten Teeth Instantly with Activated Charcoal
			</a>
		</mj-text>
		<mj-button mj-class="pill" href="https://thrivemarket.com/blog/whiten-teeth-instantly-activated-charcoal?uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&uid=5019850&utm_campaign=day8&utm_content=lead_welcome&utm_medium=lifecycle&utm_source=sailthru">
			Read more
		</mj-button>
	</mj-column>
</mj-section>
	

Here, we can see that the default HTML style for links is applied. In addition to <mj-attributes>, you can also inline CSS right into MJML using <mj-style>49. Let’s do just that by updating the head to overwrite the default style of links once and for all. We’ll also create a CSS class to apply to the <a> tags to give them the right color (we’re creating a class because the links in the email shouldn’t all have the same color).

	<mj-head>
	    <mj-title>Discover the latest trends</mj-title>
	    <mj-attributes>
	      <mj-all padding="0" />
	      <mj-text font-family="sans-serif" color="#8e8b85" />
	      <mj-class name="pill" font-weight="700" color="#d5ad4b" border-radius="50" border="2px solid #d5ad4b" font-size="16px" line-height="16px" padding="8 20 20 20" inner-padding="10 75 10 75" background-color="transparent" />
	      <mj-class name="desc" font-family="Georgia" font-size="20px" color="#45495d" padding="25 5 10 10" />
	      <mj-class name="ico" font-family="Helvetica" font-size="14px" align="center" padding="0 0"/>
	    </mj-attributes>
			<mj-style>
				a {
					text-decoration:none;
				}
				.desc {
					color: #45495d;
				}
			</mj-style>
	</mj-head>
	

Follow the same steps with the other two-column sections.

Blue Section With CTA Link

Blue section50
Blue section

To create this section, we’ll use the components that we’re getting familiar with: <mj-section>, <mj-column> and <mj-button>.

First, we’ll add a background-color to our section and some padding so that it looks as expected. Then, we just have to create two columns, one wider than the other, leveraging the width attribute with percentages. As usual, columns will stack on mobile. Because the button is different from the others here, we won’t use the pill class, but rather will manually create a new style.

Hack: Because of poor support for shorthand HEX colors in Internet Explorer, we recommend using six-digit HEX colors. This is a hack that we’ll reintegrate in MJML at some point to make sure that three-digit HEX codes are turned into six-digit codes.

<mj-section background-color="#6d8be1" padding="15 40 10 40">
	<mj-column width="60%">
		<mj-text font-weight="bold" color="#ffffff" font-size="16px" padding="0 0 10 0">
			Get all your healthy groceries at Thrive Market!
		</mj-text>
	</mj-column>
	<mj-column width="40%">
		<mj-button background-color="#ffffff" color="#45495d" font-weight="800" font-family="sans-serif" font-size="16px" border-radius="2px" inner-padding="15 60">
			Shop Now
		</mj-button>
	</mj-column>
</mj-section>
	

Last Section Of The Body Link

Last section of the body51
Last section of the body

To design the title, we’ll create a three-column layout. The columns will consist of the following, respectively:

  • the dark blue line to the left of the title,
  • the title "Want More Tips, Tricks, and Delicious Recipes?",
  • the dark blue line to the right of the title.

Then, we will wrap the three columns in an <mj-group> so that it doesn’t stack on mobile.

We’ll start creating the lines, leveraging the <mj-divider> component, setting its border-width to 2px and adding some padding so that it looks the way we want. By default, the divider will fill the column it’s contained in, so that it looks consistent across devices. Therefore, we don’t need to explicitly set the width of the divider.

Then, we’re just using <mj-text> to add our title, leveraging the desc mj-class (because we want to inherit some of the styles set in this class) and overriding the font-family and align properties that are different from this class. We could have also manually set the style without using the desc mj-class.

Finally, we just have to use our button with the pill mj-class as we did before. We’re overriding the inner-padding because, according to the original design, this button is not as wide as the others.

<mj-section padding="40px 0 0 0">
	<mj-group>
		<mj-column width="12%">
			<mj-divider border-width="2px" padding="10 0 0 10" />
		</mj-column>
		<mj-column width="75%">
			<mj-text padding="0 0 20 0" mj-class="desc" font-family="Helvetica" align="center">
				<a class="desc" href="https://thrivemarket.com/blog?utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">
					Want More Tips, Tricks, and Delicious Recipes?
				</a>
			</mj-text>
		</mj-column>
		<mj-column width="13%">
			<mj-divider border-width="2px" padding="10 10 0 0" />
		</mj-column>
	</mj-group>
</mj-section>

<mj-section padding="5px">
	<mj-column>
		<mj-image src="https://img.thrivemarket.com/emails/images/img-18.jpg" href="https://thrivemarket.com/blog?utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru" />
	</mj-column>
</mj-section>

<mj-section padding="15px">
	<mj-column>
		<mj-button mj-class="pill" inner-padding="12 25" href="https://thrivemarket.com/blog?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">
			Read our Blog
		</mj-button>
	</mj-column>
</mj-section>
	

You can see52 what our MJML template should look like so far.

Footer of the email53
Footer of the email

Title Link

We’re wrapping our title in a section and a column, as we’ve seen before, and we’re using the desc style that we created earlier. We need to alter only a few styles by manually setting a different align, font-size and font-style from our mj-class.

<mj-section background-color="#EEEBE7" padding="25">
  <mj-column>
	  <mj-text padding-top="20px" mj-class="desc" align="center" font-size="28px" font-style="italic">
			Stay Connected
		</mj-text>
	</mj-column>
</mj-section>
	

Six-Icon Section Link

This section is made up of six icons, with accompanying text below. The icons display side by side on desktop and wrap to two lines of three icons on mobile. By now, you probably know that creating such layouts is easy if we leverage the <mj-column> component. To make the icons stack onto two lines, all we have to do is wrap the columns in two groups of three columns in an <mj-group>.

To design the text below the icons, we just have to use the ico mj-class that we created before. We’ll also create a CSS class named ico to apply to the a tags, like we did in the two-column layout section.

<mj-section padding="40 0">
	<mj-group>
		<mj-column>
			<mj-image padding="10" src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/img-01_zpssvjtmopj.png" />
			<mj-text mj-class="ico"><a class="ico" href="https://thrivemarket.com/paleo?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">Paleo</a></mj-text>
		</mj-column>
		<mj-column>
			<mj-image padding="10" src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/img-02_zpshj3vgh1w.png" href="https://thrivemarket.com/gluten-free?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru"/>
			<mj-text mj-class="ico"><a class="ico" href="https://thrivemarket.com/gluten-free?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">Gluten Free</a></mj-text>
		</mj-column>
		<mj-column>
			<mj-image padding="10" src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/img-03_zpshvwomzpo.png" href="https://thrivemarket.com/vegan?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru"/>
			<mj-text mj-class="ico"><a class="ico" href="https://thrivemarket.com/vegan?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">Vegan</a></mj-text>
		</mj-column>
	</mj-group>
	<mj-group>
		<mj-column>
			<mj-image padding="10" src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/img-04_zpsyeczb1sp.png" href="https://thrivemarket.com/ingredients/gmo-free?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru" />
			<mj-text mj-class="ico"><a class="ico" href="https://thrivemarket.com/ingredients/gmo-free?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">Non-GMO</a></mj-text>
		</mj-column>
		<mj-column>
			<mj-image padding="10" src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/img-05_zpsryppwpok.png" href="https://thrivemarket.com/certifications/certified-organic?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru" />
			<mj-text mj-class="ico"><a class="ico" href="https://thrivemarket.com/certifications/certified-organic?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">Organic</a></mj-text>
		</mj-column>
		<mj-column>
			<mj-image padding="10" src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/img-06_zpsoq4ulmbq.png" href="https://thrivemarket.com/raw?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru" />
			<mj-text mj-class="ico"><a class="ico" href="https://thrivemarket.com/raw?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">Raw</a></mj-text>
		</mj-column>
	</mj-group>
</mj-section>

Social Networks Link

Once again, this section is easy to achieve by leveraging the <mj-column> component, using one column per social network icon and wrapping all of the icons in an <mj-group> so that they don’t stack on mobile. The only trick here is to fine-tune the width of the images and the padding so that the result is consistent with the original design.

Divider and Text Link

Because this part is pretty simple, it’s OK to wrap the divider and the text in the same column and section, even though we could have separated the divider from the text. As we did before when styling the links, we’ll create a footer class so that our links have the proper color.

<mj-section background-color="#EEEBE7" padding="25 40">
	<mj-column>
		<mj-divider />
		<mj-text padding="30 0 0 0" align="center" font-size="14"><a class="footer" href="https://thrivemarket.com/blog?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">Read Our Blog</a> <a class="footer" href="https://thrivemarket.com/">View Email Online</a></mj-text>
		<mj-text align="center" color="#45495d" font-size="10px" line-height="14px">
			<p>Please don't hit 'reply' to this email—we won't be able to email you back from this address and help you thrive! If you need anything, visit our <a class="footer" href="https://thrivemarket.com/faq?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">FAQ</a> or contact <a class="footer" href="https://thrivemarket.com/faq/contact?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">Member Services</a> anytime, and we'll be happy to help!</p>
			<p>We don't want to see you go, but if you no longer wish to receive promotional emails from us, you can <a class="footer" href="https://thrivemarket.com/">unsubscribe here</a> or <a class="footer" href="https://thrivemarket.com/">change your email preferences</a> anytime.</p>
			<p>4509 Glencoe Ave, Marina Del Rey, CA 90292 <br />@2016 Thrive Market All Rights Reserved</p>
		</mj-text>
	</mj-column>
</mj-section>
	

Rendering the HTML File and Testing Link

You should now have fewer than 240 lines of MJML (you can check the full code54), whereas the original file was a bit less than 800 lines of HTML. Congrats! You’ve just created your first responsive email using MJML! How easy was that?

Testing how an email renders in different email clients is always a good practice, so let’s do just that using Litmus55 (Email on Acid56 is another great platform for email testing).

Go to Litmus57 (create an account if you don’t have one already), create a new project, and paste the HTML that we generated earlier in the code area. You’ll be able to see the results in various email clients by clicking “Instant Previews” in the right pane. You can see58 the results for major email clients, from Outlook 2003 to Inbox by Gmail.

Going Further Link

Now that you know how to use MJML to easily create a responsive email, why not try to create your own component? My tutorial59 will guide you through this step by step.

What did you think about your first experience with MJML? Feel free to reach out on Twitter60 and join the MJML community now by signing up to the Slack61 channel. You can also subscribe to the newsletter62 to keep up to date on the latest news.

(rb, vf, yk, al, il)

Footnotes Link

  1. 1 https://www.mailjet.com/blog/gmail-responsive-email-design
  2. 2 https://litmus.com/blog/understanding-responsive-and-hybrid-email-design
  3. 3 https://getflywheel.com/layout/design-emails-for-mobile/
  4. 4 https://medium.freecodecamp.com/the-fab-four-technique-to-create-responsive-emails-without-media-queries-baf11fdfa848#.86y5xm2q7
  5. 5 https://twitter.com/hteumeuleu
  6. 6 https://mjml.io/documentation/#mjml-carousel
  7. 7 https://www.smashingmagazine.com/wp-content/uploads/2016/12/mj-carousel-gmail-preview-opt.gif
  8. 8 https://mjml.io/documentation/#mjml-table
  9. 9 http://reallygoodemails.com/wp-content/uploads/discover-the-latest-trends.html
  10. 10 http://codepen.io/mjml/pen/woeNwp
  11. 11 https://mjml.io/try-it-live/templates/thrive_email
  12. 12 https://facebook.github.io/react/
  13. 13 https://www.smashingmagazine.com/wp-content/uploads/2016/12/desktop-view2-preview-opt.png
  14. 14 https://www.smashingmagazine.com/wp-content/uploads/2016/12/mobile-view2-preview-opt.png
  15. 15 https://mjml.io/download
  16. 16 https://mjml.io/try-it-live
  17. 17 https://atom.io/users/mjmlio
  18. 18 https://packagecontrol.io/packages/MJML-syntax
  19. 19 https://github.com/amadeus/vim-mjml
  20. 20 https://github.com/mjmlio/gulp-mjml
  21. 21 https://github.com/smbeiragh/grunt-mjml
  22. 22 https://mjml.io/community
  23. 23 https://mjml.io/try-it-live
  24. 24 https://nodejs.org/en/
  25. 25 https://mjml.io/documentation/#command-line-interface
  26. 26 http://reallygoodemails.com/
  27. 27 http://reallygoodemails.com/wp-content/uploads/discover-the-latest-trends.html
  28. 28 https://thrivemarket.com/
  29. 29 https://www.smashingmagazine.com/wp-content/uploads/2016/12/thrive-market-newsletter-large-opt.png
  30. 30 https://mjml.io/documentation/#overview
  31. 31 https://mjml.io/documentation/#standard-head-components
  32. 32 https://mjml.io/documentation/#standard-head-components
  33. 33 https://mjml.io/try-it-live/templates/thrive_head
  34. 34 https://mjml.io/documentation/mjml-section
  35. 35 https://mjml.io/documentation/#mjml-column
  36. 36 https://mjml.io/documentation/#mjml-hero
  37. 37 https://mjml.io/documentation/#mjml-navbar
  38. 38 https://mjml.io/documentation/#mjml-column
  39. 39 https://mjml.io/documentation/#mjml-section
  40. 40 https://mjml.io/documentation/mjml-text
  41. 41 https://www.smashingmagazine.com/wp-content/uploads/2016/12/header-preview-opt.png
  42. 42 https://mjml.io/documentation/#mjml-image
  43. 43 https://mjml.io/documentation/#mjml-group
  44. 44 https://mjml.io/documentation/#command-line-interface
  45. 45 https://github.com/mjmlio/mjml/blob/master/packages/mjml-cli/README.md#render-and-minify-the-output-html
  46. 46 https://mjml.io/documentation/#mjml-button
  47. 47 https://mjml.io/try-it-live/templates/thrive_header
  48. 48 https://www.smashingmagazine.com/wp-content/uploads/2016/12/2-column-layout-preview-opt.png
  49. 49 https://mjml.io/documentation/#mjml-style
  50. 50 https://www.smashingmagazine.com/wp-content/uploads/2016/12/blue-section-preview-opt.png
  51. 51 https://www.smashingmagazine.com/wp-content/uploads/2016/12/last-part-preview-opt.png
  52. 52 https://mjml.io/try-it-live/templates/thrive_body
  53. 53 https://www.smashingmagazine.com/wp-content/uploads/2016/12/footer-preview-opt.png
  54. 54 https://mjml.io/try-it-live/templates/thrive_email
  55. 55 https://litmus.com/builder/
  56. 56 https://www.emailonacid.com/
  57. 57 https://litmus.com/builder/
  58. 58 http://imgur.com/a/l3xHE
  59. 59 https://medium.com/mjml-making-responsive-email-easy/tutorial-creating-your-own-mjml-component-d3a236ab7093#.d1ji1oheq
  60. 60 https://twitter.com/mjmlio
  61. 61 https://slack.mjml.io/
  62. 62 http://mjml.io/

↑ Back to top Tweet itShare on Facebook

Nicolas is a self-taught developer fond of JavaScript technologies (especially ReactJS & NodeJS). After joining Mailjet as the Lead Developer Evangelist for Europe, he's now an email geek and the Product Manager for MJML.

  1. 1

    Hello Nicolas,

    Congratulations! for MJML.

    This really looks cool. Past few weeks I have been developing various Email Campaign using various methods of responsive code. To an extend I kind a found the solution for major client Inbox.

    Only one major issue which are raised by my Clients and I have not been able to find any solutions.
    Issue is with iOS Gmail App (Android work fine), while I Forward / Reply it breaks the email. So does MJML take care of this issue?

    This is the major concern as mostly top level position like CEO’s are habitual to forward to their immediate team members to co-ordinate and the email really looks funny with many code breaks.

    Hoping to have some solutions to this issue.

    Thanks in advance.

    4
    • 2

      Nicolas Garnier

      January 24, 2017 5:41 pm

      Hey Dhiren, thanks for the kind words!

      > Issue is with iOS Gmail App (Android work fine), while I Forward / Reply it breaks the email. So does MJML take care of this issue?

      This is indeed a tricky issue, the problem in those situations is usually that the email clients tweaks the HTML (stripping some parts and even adding some others), so once it’s forwarded it’s broken… I’m not sure there’s much we can do about it except commanding email clients to stop messing with our code!

      2
  2. 3

    Federico Brigante

    January 24, 2017 3:15 pm

    Layout abstractions sound great, but are inline styles the only way to apply CSS? It’d be great to use CSS classes and the normal inheritance we’re used to.

    3
  3. 7

    Where’s the “SPONSORED CONTENT” notice for this article?

    Google should penalize you guys.

    -30
    • 8

      This article does not need that notice because it’s not sponsored content. MJML is clearly an open-source project, so I’m not sure where the misunderstanding is coming from :-)

      15
      • 9

        It may not be sponsored, but it IS written by the Product Manager of the project, not an impartial staff writer. This isn’t an independent look at MJML, and even though it’s open-source, that doesn’t mean they’re not making any money off the project. I guess it’s basically a free advertisement.

        I think it’s a good article, but I also think you guys are hurting your journalistic integrity by not labeling it as something separate from your normal, independent work. I think you’re even required by law to do so.

        0
    • 10

      As Iris mentioned, MJML is open-source under the very liberal MIT license. You can see it here: https://github.com/mjmlio/mjml/blob/master/LICENSE.md

      3
  4. 11

    Nice idea. Very promising. Questions:

    1. Can it support reusable elements? Say you have 10 email templates, but want to keep the header and footer the same across them all. It would be nice to be able to have reusable elements in external files.

    2. Does it support foreign languages? In particular, right-to-left languages, like Arabic or Hebrew?

    3. A variation of #1: Is there a way to reuse class definition across multiple templates? For example, say you have 10 email templates translated to 30 languages, most of which are left-to-right (LTR) and some are right-to-left (RTL). Majority of CSS class definition would be reusable across templates and languages. Is there a way to reference them instead of having to deal with hundreds of copy-paste elements?

    4. I’m on the Microsoft stack, so not very familiar with Node, etc. Just to clarify: the MJML workflow is development time, right? I mean you start with the MJML template and generate the final HTML template as part of development cycle, or is it part of run time? In the other words, do you deploy the MJML or HTML files to the production web server?

    5. Finally, I must have missed it, but mjml processor will inline the class definitions, right?

    Many thanks.

    0
    • 12

      Nicolas Garnier

      January 24, 2017 7:42 pm

      hey Alek, thanks for the feedback!

      1) You can indeed include snippets that will be applied to several templates at once, with mj-include: https://mjml.io/documentation/#mj-include

      2) rtl is not supported at the moment but was asked before (https://github.com/mjmlio/mjml/issues/230). I think it’s something that could be done without too much trouble as it’s mostly a matter of using the `dir` HTML attribute

      3) You could totally do that by creating a file in which you only have some classes, then import this files with the classes you want in the files where you want them

      4) MJML is a step before HTML indeed, but it depends how you want to use MJML. You can either do MJML on your local machine, render into HTML and deploy the HTML files. Or you can host the MJML files, run MJML on your server and deploy the HTML files if it answers a need you have

      5) MJML inline the styles that are defined in classes yes

      I hope I’m answering your questions, feel free to ask if anything is unclear!

      0
      • 13

        Awesome. Thanks for the answers. Looking forward to the RTL support (yes, it’s mostly the DIR attribute and ALIGN=RIGHT attributes). Cheers.

        0
  5. 14

    Pedro E. Matos

    January 24, 2017 7:16 pm

    One thing that the article does not mention is that the team that created MJML also released a standalone app on github for those who don’t want or care to setup MJML through terminal/command line. https://mjmlio.github.io/mjml-app/

    3
  6. 15

    Let me start by saying that this is a long time coming, and I look forward to crafting my next campaign with it. The industry has been waiting for email to die, but it keeps on chugging along like a Trance mix by Gabriel Dresden.

    Minor issue with the mjml editor though (mjml.io); It seems that the editor does not like the live display in Firefox (50.1.0) on the Mac. So the display is blank.

    Cheers!

    0
    • 16

      Nicolas Garnier

      January 24, 2017 7:47 pm

      Hey Jim, thanks for reporting this issue.

      Indeed there’s a small bug on Firefox, the initial rendering is not happening. Just type anything in the code area on the left pane and the preview will be rendered.

      Cheers

      0
  7. 17

    Just realized this this is Mac and Linux only (Windows not supported). That’s a huge bummer! :-(

    2
  8. 20

    What are some of the benefits or advantages to using MJML in lieu of Foundation for Emails by Zurb?

    4
  9. 23

    A new bullshit. Why recreate new codding where html is functioning very well ?
    Also many mailers can’t use your Script code, and spam filter will reject your work… Finally few people can see your emailing… very bad idea if you really want make a email marketing not playing with code.

    -15
    • 24

      Nicolas Garnier

      January 25, 2017 10:01 am

      Hi, MJML is layer of abstraction, so you write an email in MJML, render it in HTML and send the responsive HTML rendered by the MJML engine. You do **not** send the MJML markup which obviously wouldn’t be understood by email clients or mailers.

      Like jQuery normalised the different JavaScript methods needed to manipulate the DOM from a browser to another, MJML normalises the different HTML and CSS rules needed to make an email responsive from an email client to another.

      I hope this make it clearer how MJML works :).

      2
      • 25

        Hi rodyone,
        1.: to call the hard work of others “bulls…”, specially when they’re making it open source for everyone to use and they even have a proper documentation, is just rude. This behaviour is really demotivating the developers.

        2.: If you ever worked with HTML-Mails on a professional level, you know testing complex mails and guarantee your customers the mail looks good (or is even showing up proppery) in mail clients from GMail, Outlook.com, Outlook 2007–201*, OSX Mail is a huge pain. And just HTML will definitely not just “functioning very well”. Every “helper” or framework is a huge benefit and saves time, money and mental health. ;)

        7
  10. 26

    MJML may have only 235 lines of code versus 788 lines of HTML, but if you click at the “View HTML” on MJML’s siite, you can see it has over 1500 lines of HTML which is almost double the amount.

    No thanks, I’ll stick with HTML Emails and things that work out the box.
    Besides, many free tools already do a good job of generating responsive Email layout. See http://pulp.glitchpack.com/

    0
    • 27

      Nicolas Garnier

      January 25, 2017 10:22 am

      Hey Slinky, fair point! The advantage of the number of lines of code is really that with MJML, as a developer, it takes way less code (and headaches) to have a responsive email. This means your email is way easier to create, read, and maintain because all of the complexity is handled.

      Fair enough, the HTML generated is longer but this doesn’t really matter as:
      – you don’t really have to deal with this HTML (which is still readable and can be beautified by the way)
      – the difference in the length of the code doesn’t lead to any issue, and it doesn’t (the difference won’t make a regular email go over the 102kb limit on Gmail, for example)

      Anyway, if you’re comfortable with HTML emails and love it that’s totally fine :-).

      0
  11. 28

    Looks very nice and promising, however at least from my first test with their ready templates – the columns doesn’t seem to work in Outlook 2016, nor gmail.

    0
    • 29

      Nicolas Garnier

      January 25, 2017 11:48 am

      Hey Adrian, this is odd to say the least! MJML has good support on both those email clients. Interested to know more about the code you used on your tests, feel free to join our Slack so we can figure out what went wrong https://slack.mjml.io/

      0
      • 30

        Hi Nicolas,
        actually mj-column is appearing stacked on gmail webmail and it is written in mjml documentation that is not supported for gmail because media queries are not supported by gmail. https://mjml.io/compatibility/mj-column

        The odd part is that it works in outlook 2013 but not in outlook 2016.

        0
        • 31

          Nicolas Garnier

          January 26, 2017 9:53 am

          Thanks for your answer! Gmail used not to support media queries but now does, except for a few versions of Gmail where the update was not rolled out indeed. This is very rare though hence my surprise!

          0
  12. 32

    Looks awesome. Keep up the good work :)

    1
  13. 33

    Looks like a nice, well thought out solution. Hope to do a bit of testing with it soon.

    We pump out thousands of HTML emails out here but haven’t been able to justify responsive due to compatibility, and testing time. Working in the desktop software industry, we may be a in somewhat ‘unique’ situation whereby the majority of our opens are via desktop. Mobile numbers hover around the 25% range however, optimising layouts so our communications look great regardless of screen size have given us excellent lifts. We’re in the business of satisfying all our customers, so saying “85% of them use Gmail and Outlook so that’s what we’ll support” just doesn’t work.

    I do appreciate efforts like MJML to address the shortcomings of ageing technologies but at the end of the day, we can’t justify leaving one that works so well. Build a few table-based layouts and anyone who can click a mouse can be taught quickly how to modify them very easily, which speaks volumes. And based on the thousands of HTML emails I personally receive, it seems that very few other major players are willing to make the jump either.

    1
  14. 34

    I used MJML for a couple of weeks (the MJML Mac app is pretty awesome) when my shop was temporarily tasked with developing marketing emails for third-party design agency. We rarely did emails before, so I needed something to help speed up the process for these jobs. MJML worked GREAT for pretty simple responsive layouts, but when it came to real-world designs from this agency – major nation-wide campaigns with specific rendering demands – it just didn’t quite cut it for me. The main issue I ran into was that MJML has one, hard-coded responsive breakpoint, and didn’t give any options on how elements would respond. Again, fine if you have flexibility in your design, but I found myself hacking breakpoints by injecting raw code into the MJML. Also, MJML doesn’t add classes to elements that you can target for custom responsiveness, if you did need to add the raw breakpoints. I found myself writing crazy complex CSS selectors to target specific elements.

    So… I wound up switching to Foundation for Email, which turned out to be a MUCH better solution for these projects. It gives you total control over breakpoints and allows you to target elements any way you need. Foundation for Email also uses a workflow that very closely resembles the web dev workflow we already used, so it was a very small learning curve.

    In my experience, MJML is awesome for less complex, quick emails with fewer design demands, but if you need more control, Foundation for Email is the right tool for the job.

    1
  15. 35

    Looks nice! I’ll give it a try!

    I code e-mail marketing almost every day and know how hard it is to make it looks good on any e-mail client.

    Any effort on making our life easier is welcome!
    So thanks for helping us, MJML!

    1
  16. 36

    I personally got tired of the code bloat and lack of control over optimisation with Gulp/Grunt/whatever workflow frameworks. I respect their developers, I’ve learned a lot by using their work, but it’s just too much, most of the time.

    So I got back to basics and built my own email framework. It has no build system, but it’s solid (tested, documented) and simple to use. I’ve also added in some goodies, then licensed it MIT.

    If you’re interested or want to give feedback/contribute: https://github.com/ThemeMountain/tm-pine

    0
  17. 37

    viablethought

    February 2, 2017 2:50 am

    You need some lovin’

    just cuz

    1
  18. 38

    viablethought

    February 2, 2017 3:16 am

    Ok, all MJ jokes aside, I am so sick of tables at this point. Bring it on.

    1
  19. 39

    I get the idea of MJML, but it seems very verbose. As has been mentioned in comments, there are other approaches. On that’s worked for me is using Ruby and the Builder library to create a system for constructing html emails. Write compact Ruby code, run it (in a text editor typically) and generate the html. I wrote a blog article about the overall approach here:

    http://tdgq.com.au/design-and-publishing-notebook/using-ruby-builder-and-premailer-to-create-modular-email-system

    0
  20. 40

    Mossawir Ahmed

    February 11, 2017 5:33 pm

    well i dont agree with MJML. yet another framework type language. why not make HTML5 strong enough to support emails. or find a way in HTML. :S in the end there will be language for every task. HTML should be standardized not specific.

    0
    • 41

      Nicolas Garnier

      February 14, 2017 11:39 am

      Hey Mossawir, the issue is not with HTML. HTML5 is largely strong enough for email. The issue is with email clients that are not following any standard, and as long as they don’t change (even though I agree, that’s what they should do), you have to play by their rules.

      That’s exactly the point, MJML standardizes HTML email by generating valid HTML that works everywhere, and in the end you are indeed sending HTML.

      0
  21. 42

    For MJML to work the output has to be sent by an E-mail system that does not modify the code. That is not practical for many E-mail publishers and switching to a different vendor to distribute E-mails would be difficult if not impossible due to vendor lock-in.

    0
    • 43

      Nicolas Garnier

      February 14, 2017 11:46 am

      Well if you use a service that breaks the HTML you upload, then of course the HTML is not working as expected anymore, whether you use MJML or not.

      0

Leave a Comment

You may use simple HTML to add links or lists to your comment. Also, use <pre><code class="language-*">...</code></pre> to mark up code snippets. We support -js, -markup and -css for comments.

↑ Back to top