MJML vs TJML: Testing Email Frameworks in Action
Creating emails that would display correctly across all email clients used to be a real headache. Table-based layouts, outdated tags, and CSS hacks were an integral part of the process.
Now, everything has changed: email frameworks have emerged, simplifying this task. In this review, we will look at two of them: MJML and TJML, to determine which one is better suited for creating effective emails.
What are these frameworks?
MJML is the most popular framework for emails. It underpins many visual constructors and has practically become the standard in international email marketing.
TJML is a framework from Pixcraft, created based on extensive experience in email marketing. It is a tool that solves many problems that developers face daily.
With TJML, you don't have to worry about compatibility with different email clients and can focus on creating beautiful and adaptive emails. In addition, TJML allows you to combine HTML and AMP version of the email in one code.
Which framework to choose?
To figure it out, let's try each of them in practice. After that, we'll analyze the resulting code and evaluate the quality of the email's display in various email clients.
We'll create an email that includes adaptive blocks (product cards and banners with headings), scalable blocks (header elements), background images, text, and buttons.
Integrating the Framework
How to integrate MJML:
- Online sandbox. The easiest way to try MJML is to use the online editor directly on the website. This is suitable for those who want to quickly get acquainted with the framework's capabilities or create a simple email.
- Desktop version. For larger-scale tasks, you can use the desktop app. It's available for Windows, Mac, and Linux.
- Plugins. If you use popular code editors like VSCode, Atom, or Sublime Text, there are special plugins for MJML.
- Installation via npm. MJML can be installed via npm and used in any convenient development environment.
How to integrate TJML:
Online sandbox. Use the playground for quick creation and testing of emails. You can write code, immediately see the result, and make quick edits without leaving your browser.
As a JS library. If you prefer working in your familiar development environment, you can connect the JS library. All connection instructions can be found in the documentation.
VSCode plugin. This extension offers autocompletion and tooltips for all TJML tags and attributes.
Autocompletion for PhpStorm and WebStorm via Web-Types. You can connect web-types.json to get hints on tags and available attributes.
Setting up the email
Let's start with a blank email template.
With MJML:
1 2 3 4 5 6 7 8 9 10 11
<mjml> <mj-head> <mj-attributes> <!-- default font --> <mj-all font-family="Arial" /> </mj-attributes> </mj-head> <mj-body width="600px" background-color="#ffffff"> <!-- email body --> </mj-body> </mjml>
The code is enclosed in the <mjml>
tag. Inside, there are two sections: <mj-head>
and <mj-body>
.
- The optional
<mj-head>
section is used to define global styles, the page title, and default attribute values, avoiding the need to specify them for each tag. In our example, the default font is set to Arial. - The
<mj-body>
tag contains the main content of the email and is a required element of the structure.
With TJML:
1 2 3 4 5 6
<tjml> <m-body bgcolor="#ffffff" font-family="Arial, sans-serif"> <m-head preheader="text that is displayed next to the subject in the inbox list before opening the email"></m-head> <!-- email body --> </m-body> </tjml>
The code is enclosed in the <tjml>
tag. The <m-body>
tag is mandatory. Inside <m-body>
, an optional <m-head>
tag can be added to set preheader parameters. To set default text parameters, you can use the attributes of the <m-body>
tag.
Working on the structure
With MJML:
MJML has a block hierarchy that defines the rules for their nesting and placement. For example, the <mj-column>
tag can only be placed inside <mj-section>
or <mj-group>
, аnd <mj-section>
can only be placed inside <mj-body>
or <mj-wrapper>
. This limits the possibilities for creating various structures and, consequently, the design.
To insert the first block with a background image, we use <mj-wrapper>
. We set the padding, border radius, and image.
1 2 3
<mj-wrapper padding="30px 20px" border-radius="10px" background-url="img/bg.jpg"> <!-- block content --> </mj-wrapper>
The logo and phone number will fit on one line on a mobile device, so we'll create a scalable block that won't reflow. We'll add <mj-section>
inside <mj-group>
.
As a result, we get:
1 2 3 4 5 6 7 8 9 10 11 12
<mj-section padding="0"> <mj-group> <mj-column vertical-align="middle"> <mj-image align="left" src="img/logo.png" padding="0" width="132px" height="22px" alt="transistor"></mj-image> </mj-column> <mj-column vertical-align="middle"> <mj-text align="right" font-size="16px" color="#ffffff" font-weight="bold" padding="0px" padding-top="0"> <a href="#" style="text-decoration: none;color:#ffffff;">+1 877-635-4243</a> </mj-text> </mj-column> </mj-group> </mj-section>
The following block in the layout contains the product title and image, which need to be placed with the possibility of reflow. To do this, we take a similar structure but without using mj-group.
1 2 3 4 5 6 7 8 9 10
<mj-section padding="30px 0 0"> <mj-column vertical-align="middle"> <mj-text align="left" font-size="36px" color="#ffffff" padding="0px"> The best<br />choice </mj-text> </mj-column> <mj-column vertical-align="middle"> <mj-image align="left" src="img/img.png" padding="0" width="280px" height="234px"></mj-image> </mj-column> </mj-section>
The block with two products is more complex due to the background color of the product cards. There's no simple way to set a distance between them.
There are two options: adding a margin using a helper class or inserting custom HTML code.
Both of these methods go beyond the standard use of the framework, so we'll add a margin by inserting an empty column with a width of twenty pixels.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
<mj-section padding="30px 0 20px"> <mj-column width="290px" background-color="#F5F5F7" padding="20px" border-radius="14px"> <mj-image align="center" src="img/item1.png" padding="0" width="180px" height="116px"></mj-image> <mj-text align="center" font-size="22px" color="#222231" padding="10px 0 0"> $1,560.90 </mj-text> <mj-text align="center" font-size="16px" color="#6a6a71" padding="5px 0 10px"> Game console White </mj-text> <mj-button background-color="#6a66d3" width="94px" height="40px" font-size="14px"> Buy </mj-button> </mj-column> <mj-column width="20px"><mj-text></mj-text></mj-column> <mj-column width="290px" background-color="#F5F5F7" padding="20px" border-radius="14px"> <mj-image align="center" src="img/item2.png" padding="0" width="180px" height="116px"></mj-image> <mj-text align="center" font-size="22px" color="#222231" padding="10px 0 0"> $1,890.90 </mj-text> <mj-text align="center" font-size="16px" color="#6a6a71" padding="5px 0 10px"> Monitor 27” IPS LED FHD </mj-text> <mj-button background-color="#6a66d3" width="94px" height="40px" font-size="14px"> Buy </mj-button> </mj-column> </mj-section>
Next comes the footer.
1 2 3 4 5 6 7 8
<mj-section> <mj-column> <mj-text align="left" font-size="10px" color="#bababa" padding="0"> If you prefer not to receive emails like this, you may unsubscribe<br /> © 2024 Company. All rights reserved. </mj-text> </mj-column> </mj-section>
With TJML:
There is no strict hierarchy of elements in this framework. It offers three main abstractions for creating a structure:
- wrapper (m-wrap), which sets the background, borders, padding, size constraints, and alignment;
- reflowable blocks (m-boxes and m-box);
- non-reflowable blocks (m-row and m-column).
This approach provides flexibility in creating email structures. In addition to structural tags, elements such as text (m-text), button (m-button), image (m-img), and others are available.
The first block requires a background image and rounded corners. We use the <m-wrap>
tag, setting the attributes background-image, border-radius, as well as an alternative color (bgcolor) and padding.
1 2 3
<m-wrap width="600" padding="30px 20px" bgcolor="#473fac" background-image="img/bg.jpg" border-radius="10px"> <!-- email body --> </m-wrap>
Blocks that require collapsing are defined using m-row and m-column.
1 2 3 4 5 6 7 8
<m-row width="100%"> <m-column align="left"> <m-img src="img/logo.png" width="132" height="22" alt=""></m-img> </m-column> <m-column align="right" valign="middle"> <m-text href="#" color="#ffffff" bold font-size="16px">+1 877-635-4243</m-text> </m-column> </m-row>
Adaptive blocks with a header and image can be created using m-boxes and m-box.
1 2 3 4 5 6 7 8 9 10
<m-boxes align="left" valign="middle"> <m-box width="280" align="left"> <m-text color="#ffffff" font-size="36px"> The best<br />choice </m-text> </m-box> <m-box width="280"> <m-img src="img/img.png" width="280" height="234" alt=""></m-img> </m-box> </m-boxes>
Product cards are also reflowable blocks. To set the padding, we will apply nested m-wrap with the necessary sizes and background color.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
<m-wrap width="620"> <m-boxes> <m-box width="310"> <m-wrap width="290" bgcolor="#F5F5F7" border-radius="14px" padding="20px"> <m-img src="img/item1.png" width="180" height="116" alt=""></m-img> <m-wrap padding="10px 0"> <m-text color="#222231" font-size="22px" line-height="26px">$1,560.90</m-text> <m-text color="#6A6A71" font-size="16px" line-height="20px">Game console White</m-text> </m-wrap> <m-button color="#ffffff" border-radius="6px" bgcolor="#6a66d3" width="94" height="40">Buy</m-button> </m-wrap> <m-padding size="20"></m-padding> </m-box> <m-box width="310"> <m-wrap width="290" bgcolor="#F5F5F7" border-radius="14px" padding="20px"> <m-img src="img/item2.png" width="180" height="116" alt=""></m-img> <m-wrap padding="10px 0"> <m-text color="#222231" font-size="22px" line-height="26px">$1,890.90</m-text> <m-text color="#6A6A71" font-size="16px" line-height="20px">Monitor 27” IPS LED FHD</m-text> </m-wrap> <m-button color="#ffffff" border-radius="6px" bgcolor="#6a66d3" width="94" height="40">Buy</m-button> </m-wrap> <m-padding size="20"></m-padding> </m-box> </m-boxes> </m-wrap>
And finally, there is the footer.
1 2 3 4 5 6
<m-wrap width="620" padding="20px 10px" align="left"> <m-text font-size="10px" color="#BABABA"> If you prefer not to receive emails like this, you may unsubscribe<br /> © 2024 Company. All rights reserved. </m-text> </m-wrap>
What we got
The key aspect of the framework is the quality of the final markup, including code cleanliness, its volume, readability, and display in various email clients.
Size
Gmail automatically truncates emails if their size exceeds 102 KB. This will not only ruin the appearance but also make it difficult to track OR, as tracking pixels are usually added at the end before the closing <body>
tag. This means "bloated" code will lead to a decrease in open rate statistics.
To evaluate compression, we use the built-in compression tools of each framework.
TJML | MJML | |
Compressed code | 11.17 KB | 14.84 KB |
Uncompressed code | 13.52 KB | 22.35 KB |
Display in different email clients
In Gmail:
Now let's try something more complex — for example, let's see how the email looks in the desktop version of Outlook. Display problems in this program are quite common.
For B2C email campaigns, Outlook display may not be as critical, as its average open rate does not exceed 5%
However, for B2B email campaigns, the situation is different. Clients often prefer to check test emails in Outlook, so it's important to ensure proper display.
In this case, the display differences become apparent. In MJML, we encounter padding issues with blocks that have a background. This is due to the specifics of how Outlook handles padding within VML.
Buttons also display differently. In TJML, VML is used whenever possible to create buttons, ensuring precise alignment with the layout dimensions and maintaining rounded corners. In MJML, buttons are formed using a table, which causes the button height to increase due to additional padding.
MJML framework employs a "mobile first" principle, meaning the email structure is initially designed for mobile devices, and the desktop version is created using media queries. This approach yields good results in many email clients and ensures quality rendering on mobile devices, even if media queries aren't supported.
However, it's important to note that some email clients do not support media queries.
Unlike MJML, TJML doesn't initially use media queries for adaptation. Therefore, cards are displayed in their original size, not stretched to fill the entire screen. If desired, this can be fixed by adding classes and media queries to the m-style.
Background alignment also differs. In both frameworks, MJML and TJML, it's easy to change using the appropriate attribute.
Other tools
The TJML framework stands out from others by generating not only an HTML version of the email but also an AMP version. This AMP version supports AMP components like carousels, accordions, forms, AMP lists, and more. Unlike MJML, these elements will work correctly in email clients such as Gmail, Yahoo, and AOL.
There are also additional tools for convenience:
- Pixel Perfect allows you to ensure that every element on the screen is positioned exactly as intended by the designer, down to the individual pixel. Users can upload graphic mockups and adjust their transparency to visually compare them to the layout. This allows developers to fine-tune sizes, indents, and other parameters, achieving a perfect "pixel-perfect" match between design and implementation.
- Testing dark mode. Since many mobile users prefer dark mode, it has become necessary to adapt emails for email clients that implement this feature in different ways. To address this, we’ve added two display modes for dark themes: a standard mode (with inversion of light elements) and a full inversion mode, similar to Gmail on iOS.
Conclusion
Using email frameworks significantly speeds up and simplifies the process of email development while allowing flexible control over structure and design.
TJML is a practical and user-friendly solution for creating emails, designed to meet the real needs of developers. Compared to MJML, TJML offers greater flexibility and helps avoid compatibility issues with outdated email clients. It also enables the creation of both HTML and AMP versions within a single codebase.
If you're looking for a tool to streamline your development process, TJML is an excellent choice for your business.