Coding Responsive Emails with MJML’s Desktop App (for non-developers and developers) — Part II

How to put together an email with a Header, Hero + CTA, Body Copy, Image + Subtext, and a Footer…

postgradexpat
9 min readFeb 22, 2019

This is Part II of a “Coding Responsive Emails with MJML’s Desktop App (for non-developers and developers”). In Part I, we went over how to set up and use MJML’s desktop app and how to set up a basic email template.

Here in Part II, we’re going to start building out the pieces of our email by filling out our email template with various common components (header, hero + CTA, body copy, image + subtext, footer).

WHAT WE’LL COVER (PART I)

  • How to set up and use the MJML desktop app
  • How to set up a basic email template from scratch with MJML
  • How to create a snippet in the MJML desktop app

WHAT WE’LL COVER (PART II)

  • How to put together an email with the following pieces: Header, Hero Image + CTA, Body Copy, Image + Subtext, Footer
  • How to compile MJML into HTML

What we’re building:

DESKTOP VIEW
MOBILE VIEW

Check out the full code here: https://mjml.io/try-it-live/HkVE0pGY7

Alright, let’s get back to building. If you remember from Part I, we’d just put together a basic email template to set up our content, but we haven’t actually built any visible components.

This is what we should have going so far:

<mjml owa="desktop">
<mj-head>
<mj-title>INSERT TITLE HERE</mj-title>

<mj-font
name="Montserrat"
href="https://fonts.googleapis.com/css?family=Montserrat:400,600,800"
/>
<mj-attributes>
<mj-all
padding="0px"
font-family="Montserrat, Helvetica, sans-serif"
/>
</mj-attributes>
<mj-preview>
INSERT PREVIEW TEXT HERE
</mj-preview>
</mj-head>
<mj-body width="640px">
<mj-raw><!-- ==***== Mj-Body ABOVE ==***== --> </mj-raw>
PUT COMPONENTS HERE <mj-raw><!-- ==***== Mj-Body BELOW ==***== --></mj-raw>
</mj-body>
</mjml>

We’re going to replace the part in our template where it says “PUT COMPONENTS HERE” with mjml body components.

HEADER COMPONENT

...
...
<mj-raw><!-- ***** Header Component START ***** --></mj-raw>
<mj-section>
<mj-column>
<mj-image
src="https://bit.ly/2pujUXb"
alt="My fake logo"
href="https://medium.com/p/9c99dfcda68d/edit" />
</mj-column>
</mj-section>
<mj-raw><!-- ***** Header Component END ***** --></mj-raw>
...
...

Let’s break this down. You can ignore the ellipses (…), which I included just to signal the fact that there is code before and after this component (remember, we’re sticking this into basic template we set up in the previous section where it says PUT COMPONENT HERE).

  1. <mj-raw><! — ***** Header Component START ***** →</mj-raw>
    You already know what this is. It’s just a plain comment in English so I know where my Header starts. You could write anything between the opening and closing tags and they wouldn’t show up in your email, as you can see from looking at the previewer on the right side of your window.
Look, no text in the previewer! Just the logo…

2. <mj-section> is a row in your email. Learn more about it here.

3. <mj-column> is a column in your email. Best practice is to not to have emails with more than 3 columns, otherwise things start to get ugly as your screen size shrinks. In this case we have a single column that spans the entire width of the row. Learn more about it here.

4. Our fake logo is .png file. We used <mj-image> to load it in. It has lots of different attributes, which you can read more about in the docs. We gave it the following attributes:
- src (this is where your image is hosted).
- alt (this is alternative text for when your image doesn’t appear. It’s good practice for accessibility purposes)
- href (use this to make your image a link)
- width (specifies the width of the image)

HERO IMAGE COMPONENT with CTA and TEXT

...
...
<mj-raw><!-- ***** Hero Component START ***** --></mj-raw>
<mj-hero
mode="fixed-height"
background-width="640px"
background-url="https://bit.ly/2OHgHyl"
background-color="#2a3448"
height="400px">

<mj-text
padding-top="50px"
color="#ffffff"
align="center"
font-size="40px"
font-weight="600">
MJML
</mj-text>

<mj-button
padding-top="16px"
href="https://mjml.io/"
align="center">
LEARN IT NOW
</mj-button>
</mj-hero>
<mj-raw><!-- ***** Hero Component END ***** --></mj-raw>
...
...

<mj-hero> is one of the rare MJML components that don’t have to be nested within <mj-section> or <mj-column> . We gave it text and a CTA, but that’s totally optional. You could in theory just put up an image.

The break-down:

  1. <mj-raw> as usual to mark off the start of the component. We put it right after the Header component.
  2. <mj-hero> takes a few different attributes. We did the following:
    - made the hero image take a mode of “fixed height” so that the image size didn’t change between desktop and mobile view.
    - specified the background width to 640px (the default is 600px)
    - pulled in the image from wherever it is hosted using background-url
    - set a fallback background-color in case the image fails to load
    - specified the image height to 400px. image-height is a mandatory attribute if you set the mode to “fixed-height”.
  3. <mj-text> is what we use to display human-readable text. See the docs for more details. We gave it the following attributes and values:
    - padding-top of 50px to vertically center the text (this just adds space above the text). We guesstimated it lol
    - made the text white (#ffffff) using the color attribute
    - center-aligned it along the horizontal axis (you could also give the attribute align the values of left or right )
    - set the font-size to 40px (ie. how big the text is)
    - set the font-weight to “600” (ie. how thick the text is)
  4. <mj-button> creates a button, as you can tell by the name. It can have a lot of different attributes, but we only used three:
    - padding-top allows us to add 16px of space above the button so that it isn’t stuck to the text that comes before it. You can experiment with the value if you want it to have more or less space.
    - href allows us to send the button to another website
    - align="center" allows us to center the text along a horizontal axis

BODY COPY

...
...
<mj-raw><!-- ***** Body Copy START ***** --></mj-raw>
<mj-section
padding-left="16px"
padding-right="16px">
<mj-column>
<mj-text
font-size="16px"
line-height="22px"
padding-top="16px" >
This is how we write body copy. Here is a very long paragraph of several words.
</mj-text>

<mj-text
font-size="16px"
line-height="22px"
padding-top="16px" >
Here is another paragraph. Wow! I can write code my own emails now!
</mj-text>
</mj-column>
</mj-section>
<mj-raw><!-- ***** Body Copy END ***** --></mj-raw>
...
...
  1. Do I even need to explain the comments?
  2. <mj-section> has something a little different here. We added padding-left and padding-right as attributes so that the text inside the email wasn’t squashed to the sides. You can experiment with the value if you want more or less space.
  3. <mj-column> looks familiar, right?!
  4. We gave <mj-text> some familiar attributes we’ve already seen. We gave it a font-size and padding-top so that the paragraphs weren’t stuck to the previous elements. You can experiment with the value if you want more or less space.
    Repeat this component as many times as necessary. You could probably make it its own snippet if you need it more than a couple times…

IMAGE + TEXT BLOCK

So you want images in your email. Cool. This stuff can get pretty icky so keeping it simple is really helpful. We’re going to do a pretty basic setup.

...
...
<mj-raw><!-- ***** Image+Text Block START ***** --></mj-raw>
<mj-section
padding-top="16px"
padding-left="32px"
padding-right="32px"
padding-bottom="16px">
<mj-column width="49%" vertical-align="middle">
<mj-image
src="https://bit.ly/2I5qmw7"
width="280px"/>
</mj-column>

<mj-column width="2%" vertical-align="middle" />
<mj-column width="49%" vertical-align="middle">
<mj-text
font-size="24px"
padding-top="16px">
Sunset skate sesh!
</mj-text>
<mj-text
font-size="16px"
line-height="22px"
padding-top="16px">
Here's some more of that body copy from earlier. Maybe we should make this a snippet!
</mj-text>

<mj-text
font-size="16px"
line-height="22px"
padding-top="16px">
Wow, I wish I could keep my white sneakers squeaky clean all the time. That must take some effort.
</mj-text>
</mj-column>
</mj-section>
<mj-raw><!-- ***** Image+Text Block START ***** --></mj-raw>
...
...
  1. Comments as usual in the form of <mj-raw>
  2. <mj-section> has fourpadding attributes. We gave it some space on top of the column, below it, to its left and to its right so that the image and text weren’t stuck to the sides or to the preceding elements.
  3. Three columns are nested inside <mj-section> . The first column contains the image, for which we’ve set a source and a height. We’ve also given it a width of 49%. This is because we want there to be space between the first column (image) and the third column (text) in Desktop mode. Otherwise, the content would be stuck side to side.
    It also has an attribute called vertical-align which allows us to vertically align content within the column. A weird MJML bug means that if you want to vertically align elements inside one column, the other columns within the same section need to also be vertically aligned to the middle.
  4. The second column is self-closing: <mj-column width="4%" vertical-align="middle/>.This is basically just a spacer element, as explained above. It has a width and vertical-align as attributes.
  5. The third column has a width of 49% as well. (49 + 49 + 2= 100). Make sure your column widths never add up to over 100 otherwise weird things happen…
    This column contains the text. At this point everything here should be self-explanatory. You should also consider making anything you need more than once (or specifically in more than one email template) a snippet…

FOOTER

...
...
<mj-raw><!-- ***** Footer START ***** --></mj-raw>
<mj-section
padding-top="40px"
padding-left="60px"
padding-right="60px"
background-color="#f2f2f2">
<mj-column>
<mj-text
font-size="12px"
line-height="22px"
color="#7585a0"
align="center">
Here's our little footer. You can go crazy and add <a href="https://mjml.io" style="color:#7585a0; text-decoration: underline;">links</a> and other stuff like social icons. That's all up to you though. Check out the mj-social icons <a href="https://mjml.io/documentation/#mjml-social" style="color:#7585a0; text-decoration: none;">here</a>.
</mj-text>
</mj-column>
</mj-section>
<mj-raw><!-- ***** Footer END ***** --></mj-raw>
...
...

Here’s a little footer. Everything here should be pretty straightforward. The only thing that’s different on <mj-section> is that we’ve added a background-color to differentiate the header from the rest of the email.

The other thing that’s different is that we’ve written some inline plain old html inside of <mj-text> to give it two clickable links. This is an unusual pattern for MJML and you don’t have to do it often. If you’re not familiar with HTML/CSS, just remember that this is how you create a clickable link inside a text component in MJML: <a href="https://mylink.com" style="color:#000000"; text-decoration: underline;"> my clickable text </a>

Basically what all this translates into is the following:

The opening a-tag contains an attribute called href which takes a url as a value. It also takes an attribute called color which we can set to whatever we want. text-decoration is used to set an underline (or no underline) for the clickable text. Our footer looks like this:

The word “links” has an underline because we explicitly gave it a text-decoration value of ‘underline’ (although this is its default value anyway). The word “here” doesn’t have an underline, even though it is actually a link, because we explicitly set its text-decoration value to ‘none’.

How to Compile MJML into HTML

OK, so now we have our MJML email, but what we really want is the HTML version of it. MJML’s desktop app makes it really easy to compile our MJML into HTML.

In the top-right corner there is a drop-down menu to the that says “Copy HTML” by default. If you click this, you’ll get an html copy of your email saved to your clipboard, which you can then paste into an email tester like Litmus if you’re using one, or do whatever it is you want.

Or… You can click the little carat, which will open up the drop-down menu and allow you to choose one of three options: 1) Copy HTML; 2) Export to HTML file; 3) Screenshot

If you click “Export to HTML file”, it’ll open up a modal which allows you to choose the name your html and file and where you want to save it. Now you have an html email template! It’s as simple as that.

You can even take a screenshot of your email in both desktop and mobile mode by selecting the screenshot option. It’ll take both at once for you and save them under the same name as your MJML file, but with the .png extension.

And that’s it! See the full code here: https://mjml.io/try-it-live/HkVE0pGY7

Need to go back to PART I? Check it out here.

--

--