Skip to main content
Emailens
Blog
PK
·Founder, Emailens
Mar 4, 2026·9 min read

MJML Tutorial: Build Responsive Emails Without Fighting CSS

MJML is a markup language that compiles to responsive HTML email. You write semantic components, and MJML handles the table layouts, inline CSS, and client-specific hacks.

Quick Answer: Why Choose MJML for Email Coding

MJML eliminates the pain of writing raw nested tables and Outlook conditional comments. By declaring layouts with semantic tags like <mj-section> and <mj-column>, the MJML compiler automatically produces cross-client compatible HTML with inline styles, ghost tables for Windows Outlook, and fluid mobile breakpoints.

What MJML does

MJML abstracts away the complexity of HTML email. When you write <mj-section> and <mj-column>, MJML compiles these to nested <table> elements with precise width calculations, media queries for responsiveness, and inlined styles for maximum CSS compatibility.

The result is HTML that works in Outlook, Gmail, Apple Mail, and every other major client, without you having to write any of the underlying table markup.

Installation

Terminal
7 lines
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

MJML v5 is now async: the compileMjml() function returns a Promise. If you're upgrading from v4, update your build scripts to await the result.

Core components

mj-body

Root container. Sets background color and width for the entire email.

mj-section

Horizontal row. Compiles to a <table> with one <tr>. Accepts background-color, padding, and full-width.

mj-column

Vertical column within a section. Automatically calculates percentage widths based on sibling count.

mj-text

Text block with full inline CSS support. Wraps content in a <td> with proper padding.

mj-image

Responsive image with automatic width calculation and alt text support.

mj-button

CTA button rendered as a <table>-based structure for universal client support.

mj-divider

Horizontal line. More reliable than <hr> across email clients.

mj-spacer

Empty vertical space. Use instead of margin for consistent spacing.

A complete example

welcome.mjml
42 lines
<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>

Multi-column layouts

MJML's column system handles responsive stacking automatically. On desktop, columns sit side by side. On mobile, they stack vertically. You don't need media queries:

Columns
26 lines
<!-- 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>

MJML vs React Email

Both compile to email-safe HTML, but they suit different workflows:

AspectMJMLReact Email
SyntaxCustom XML-like markupJSX (React components)
LogicTemplate literals or external templatingFull JavaScript/TypeScript
ResponsiveBuilt-in (auto stacking)Manual (you handle it)
Best forMarketing emails, designersTransactional emails, React teams

Both are supported by Emailens. You can compare alternatives or paste either format directly into the preview tool.

Testing MJML emails

MJML's output is optimized for compatibility, but no tool can guarantee 100% consistency across clients. Outlook's Word rendering engine, Gmail's CSS stripping, and Apple Mail's dark mode all introduce edge cases.

Emailens accepts MJML source directly. It compiles, transforms per-client, and generates a compatibility report with MJML-specific fix suggestions.

See also: Compare MJML directly with React Email development, or read our deep dive on modern responsive email techniques.

Frequently Asked Questions

How does MJML handle responsive design across email clients?

MJML abstracts table-based responsive layouts behind intuitive tags like <mj-section> and <mj-column>. When compiled, it generates complex conditional MSO tables for Outlook and responsive media queries for modern mobile clients.

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.

Test your MJML email across 21 clients

Paste your MJML source and get a compatibility report with framework-specific fix snippets.

Preview your email

Free plan, 30 previews/day

PK

Philippe KAM

Founder & Lead Engineer at Emailens

Building next-generation email preview and QA infrastructure for developers. Focused on reverse-engineering rendering engines across Outlook (Word MSO & New Outlook), Gmail, and Apple Mail to eliminate email rendering bugs before dispatch.