MJML Guide: Tags, Columns, Outlook Code, Full Template
MJML compiles tags like mj-section and mj-column into nested tables with inline styles and Outlook conditional comments; columns stack below a 480px breakpoint unless you wrap them in mj-group.
No signup · Five clients free, Outlook Classic included · All 21 with an account
The checker needs a computer screen.
A free account opens all 21 clients and keeps your checks for 7 days. Create a free account →
Philippe Kam, founder of Emailens · Published 4 Mar 2026 · Updated 28 Oct 2026
@emailens/engine 0.18.22 · data last changed 10 Nov 2026
Part of the HTML email guide · all guides
MJML is a markup language that compiles to responsive HTML email. You write semantic tags, and MJML writes the nested tables, inline CSS, media queries and Outlook conditional comments. This guide covers installing it, every tag you need for a real template, the head settings most people miss, and how to check the compiled HTML.
What MJML does
When you write <mj-section> and <mj-column>, MJML compiles them to nested <table> elements with precise width calculations, media queries for responsiveness, and inlined styles for maximum CSS compatibility. For Outlook on Windows it adds MSO conditional tables, the same ghost tables you would otherwise write by hand.
The result is HTML that works in Outlook, Gmail, Apple Mail, and the other major clients, without you writing the underlying table markup.
Install MJML and compile your first file
npm install mjml
# Compile an MJML file to HTML
npx mjml input.mjml -o output.html
# Watch mode for development
npx mjml --watch input.mjml -o output.html
# Validate without compiling
npx mjml --validate input.mjmlFrom Node, call mjml2html(). In MJML 5 it is async and returns a Promise, so if you are upgrading from v4, update your build scripts to await the result.
MJML tags you will use in every template
mj-bodyRoot container. Sets background color and width for the entire email.
mj-sectionHorizontal row. Compiles to a <table> with one <tr>. Accepts background-color, padding, and full-width.
mj-columnVertical column within a section. Automatically calculates percentage widths based on sibling count.
mj-groupWraps columns that must stay side by side on mobile instead of stacking.
mj-wrapperWraps several sections so they share one background or border.
mj-textText block with full inline CSS support. Wraps content in a <td> with proper padding.
mj-imageResponsive image with automatic width calculation and alt text support.
mj-buttonCTA button rendered as a <table>-based structure for universal client support.
mj-dividerHorizontal line. More reliable than <hr> across email clients.
mj-spacerEmpty vertical space. Use instead of margin for consistent spacing.
mj-rawRaw HTML passed through untouched: Outlook conditional comments, VML, template tags.
A complete MJML email template
<mjml>
<mj-head>
<mj-attributes>
<mj-all font-family="Arial, sans-serif" />
<mj-text font-size="14px" color="#333333" line-height="1.6" />
</mj-attributes>
</mj-head>
<mj-body background-color="#f6f6f6">
<mj-section background-color="#ffffff" padding="40px 30px">
<mj-column>
<mj-image
src="https://example.com/logo.png"
width="120px"
alt="Company Logo"
/>
<mj-text font-size="24px" font-weight="bold" padding-top="24px">
Welcome to our platform
</mj-text>
<mj-text>
We're glad you're here. Here's what you can do next:
</mj-text>
<mj-button
background-color="#000000"
color="#ffffff"
href="https://example.com/dashboard"
border-radius="6px"
font-size="14px"
>
Go to Dashboard
</mj-button>
</mj-column>
</mj-section>
<mj-section padding="20px 30px">
<mj-column>
<mj-text font-size="12px" color="#999999" align="center">
You received this because you signed up at example.com
</mj-text>
</mj-column>
</mj-section>
</mj-body>
</mjml>mj-head: defaults, classes, styles and preview text
Everything in <mj-head> shapes the output without appearing in it:
mj-attributessets defaults:mj-allfor every tag, a tag name such asmj-textfor that tag, andmj-classfor a named set you apply withmj-class="name".mj-styleadds CSS. Withinline="inline"MJML inlines it onto the elements; without, it stays in a<style>block.mj-titleandmj-previewset the document title and the preview text shown after the subject line.mj-breakpointsets the width below which columns stack. The default is 480px.
<mj-head>
<mj-title>Your order has shipped</mj-title>
<mj-preview>Track your parcel in one click</mj-preview>
<mj-breakpoint width="480px" />
<mj-attributes>
<mj-all font-family="Arial, sans-serif" />
<mj-class name="muted" color="#999999" font-size="12px" />
</mj-attributes>
<mj-style inline="inline">
.footer-link { color: #999999; }
</mj-style>
</mj-head>
<!-- later, in the body -->
<mj-text mj-class="muted">You received this because you ordered.</mj-text>Multi-column layouts and mj-group
MJML's column system handles responsive stacking automatically. On desktop, columns sit side by side. Below the breakpoint, they stack vertically. You don't write the media queries. When two columns must stay side by side on a phone, such as an icon next to its label, wrap them in <mj-group>.
<!-- Two-column layout, MJML handles the table math -->
<mj-section>
<mj-column>
<mj-image src="https://example.com/feature-1.png" alt="Feature 1" />
<mj-text font-weight="bold">Fast Setup</mj-text>
<mj-text>Get started in under 5 minutes.</mj-text>
</mj-column>
<mj-column>
<mj-image src="https://example.com/feature-2.png" alt="Feature 2" />
<mj-text font-weight="bold">Full Testing</mj-text>
<mj-text>Test across 21 email clients.</mj-text>
</mj-column>
</mj-section>
<!-- Three-column layout, each column is automatically 33.33% -->
<mj-section>
<mj-column>
<mj-text align="center">Plan A</mj-text>
</mj-column>
<mj-column>
<mj-text align="center">Plan B</mj-text>
</mj-column>
<mj-column>
<mj-text align="center">Plan C</mj-text>
</mj-column>
</mj-section>
<!-- Side by side on every screen: wrap the columns in mj-group -->
<mj-section>
<mj-group>
<mj-column width="50%">
<mj-text>Left</mj-text>
</mj-column>
<mj-column width="50%">
<mj-text>Right</mj-text>
</mj-column>
</mj-group>
</mj-section>For the strategy behind stacking and fluid layouts, see the responsive email design guide.
Raw HTML, Outlook code and partials: mj-raw and mj-include
<mj-raw> passes its content through without escaping it: Outlook conditional comments, VML, or template syntax such as Handlebars, Liquid or Jinja. <mj-include> pulls a shared partial, such as a header or footer, into the template.
<mj-raw>
<!--[if mso]>
<p style="margin:0;">Shown only in Outlook for Windows</p>
<![endif]-->
</mj-raw>
<!-- Reuse a partial (MJML 5: includes are off by default) -->
<mj-include path="./partials/footer.mjml" />In MJML 5, includes are disabled by default for security. Turn them on with --config.allowIncludes true on the command line, or ignoreIncludes: false when calling mjml2html(). For writing the conditional comments themselves, see MSO coding for Outlook.
MJML validation: strict, soft and skip
MJML checks your markup for unknown tags and for each tag's allowed children, attributes and attribute values. The validation level decides what happens to the errors: soft, the default, compiles anyway and returns the errors alongside the HTML; strict stops the build on the first invalid template; skip does not validate. Use strict in CI so a typo in an attribute name fails the build instead of shipping silently.
MJML vs React Email
Both compile to email-safe HTML, but they suit different workflows:
| Aspect | MJML | React Email |
|---|---|---|
| Syntax | Custom XML-like markup | JSX (React components) |
| Logic | Template literals or external templating | Full JavaScript/TypeScript |
| Responsive | Built-in (auto stacking) | Manual (you handle it) |
| Best for | Marketing emails, designers | Transactional emails, React teams |
If your team already writes React, the React Email guide covers that route. You can also compare alternatives.
Testing MJML emails across clients
MJML's output is built for compatibility, but no compiler can guarantee the same result in every client. Outlook's Word rendering engine, Gmail's CSS stripping, and Apple Mail's dark mode all introduce edge cases, and anything you add through mj-raw or mj-style is yours to check.
Emailens accepts MJML source directly. It compiles, transforms per-client, and generates a compatibility report with MJML-specific fix suggestions. For the full pre-send routine, see how to test HTML emails.
Questions
How does MJML handle responsive design across email clients?
MJML abstracts table-based responsive layouts behind tags like <mj-section> and <mj-column>. When compiled, it generates conditional MSO tables for Outlook and media queries for mobile clients, so columns sit side by side on desktop and stack below the breakpoint (480px unless you set <mj-breakpoint>).
How do I stop MJML columns stacking on mobile?
Wrap the columns in <mj-group> inside the <mj-section>. Columns in a group stay side by side at every width, so keep their content narrow enough to fit a phone screen.
Do I need to manually inline CSS when using MJML?
No. The MJML engine automatically inlines styles declared inside <mj-attributes> and <mj-style inline='inline'> directly onto elements during compilation, ensuring Gmail and mobile clients receive inline CSS.
Can I include custom HTML or Outlook VML inside MJML?
Yes. The <mj-raw> tag allows you to inject arbitrary raw HTML, conditional comments (like <!--[if mso]>), or template syntax (Handlebars, Liquid, Jinja) directly into the generated output without MJML escaping it.
What is the difference between MJML and React Email?
MJML is a domain-specific XML markup language with built-in layout calculations that works across any backend language. React Email uses JSX and TypeScript within Node/React ecosystems, giving developers component composition and code sharing with web apps.
Your next question
Also useful: HTML email checker · Lint MJML templates in 21 clients · Free HTML email templates, tested in 21 clients
Paste the email that broke.
No signup · Five clients free, Outlook Classic included · All 21 with an account
The checker needs a computer screen.
Get new email CSS fixes by email, or follow by RSS.