LabHub

Blog

HTML Email Development in 2026 — Maizzle / MJML / react-email / Postmark Templates / Foundation for Emails / Cerberus Deep Dive

한국어English日本語

Prologue — 1998's table is still alive

If you have only written modern HTML, the first time you open an email template the shock never quite leaves you. CSS Grid is unsafe. Flexbox is unsafe. Even div-based layouts are unsafe. Anyone who has ever met Outlook (specifically the Microsoft 365 desktop client with Word's rendering engine) knows the truth: the 1998-vintage table layout is still effectively the only universally compatible technique.

And yet, on top of that fossil, the period from 2024 to 2026 has been surprisingly lively. Resend's react-email has become the de-facto standard for indie startups. Maizzle has carried Tailwind CSS into email-land. MJML has kept its position as the open component standard. Postmark's server-side templates blur the line between marketing and engineering with a single Mustache expression. At the same time, drag-and-drop SaaS — Stripo, BEE, Stensul, Unlayer — keeps absorbing more of the marketing department's workload.

This article walks all four buckets — code (Maizzle, Cerberus), component DSL (MJML, react-email, Foundation for Emails, HEML), server-side templates (Postmark, HubSpot), drag-and-drop SaaS (Stripo, BEE, Stensul, Unlayer, mosaico, Email-Builder.js, Tabular) — and also covers dark mode, accessibility, MIME multipart, AMP for Email, and what Korean and Japanese teams actually do.


1. The 2026 HTML email map — code / component / drag-and-drop / SaaS

The space breaks into roughly four buckets.

BucketToolsPrimary userStrength
Code-firstMaizzle, Cerberus, classic ZURB FoundationFrontend engineersRaw HTML / Tailwind
Component DSLMJML, react-email, HEML, Foundation for EmailsFull-stack engineersComponent abstraction
Server-side templatesPostmark, HubSpot, SendGrid Dynamic TemplatesBackend + marketingVariable substitution
Drag-and-drop SaaSStripo, BEE, Stensul, Unlayer, mosaico, Email-Builder.js, TabularMarketing / designersNon-developer friendly

The boundaries blur. Maizzle is code-first but works as a component library too. react-email is a component DSL but is still code-first in spirit. Stripo is drag-and-drop but lets you edit raw HTML. Treat the table as a starting point, not a taxonomy.

Five meaningful trends as of May 2026:

  1. react-email (Resend) dominance — informal estimates put indie / startup adoption above 80 percent.
  2. Maizzle's quiet rise — Tailwind shops adopt it without thinking twice.
  3. MJML's stability era — fewer big features, more focus on integrations and AI assistance.
  4. Drag-and-drop SaaS absorbing marketing — Stripo / BEE / Stensul each find a niche.
  5. The de-facto death of AMP for Email — six years after launch, nearly every adopter has rolled back.

2. Why email is still hard — client fragmentation

The 2026 client share, roughly:

The problem is Outlook desktop. Microsoft pushed "New Outlook" in 2024, but in 2026 about 60 percent of corporate environments still run the Word engine. The Word engine:

So in 2026 the email template still leans on table + td + align="center", exactly as it did in 1998. Maizzle, MJML, and react-email all compile down to that.

<!-- Still the 2026 baseline -->
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
  <tr>
    <td align="center">
      <table role="presentation" cellspacing="0" cellpadding="0" border="0" width="600">
        <tr>
          <td style="padding: 20px;">
            Body goes here
          </td>
        </tr>
      </table>
    </td>
  </tr>
</table>

The critical piece is role="presentation" — it tells screen readers the table is layout, not data. Accessibility is covered in chapter 13.


3. Maizzle — the TailwindCSS-driven workflow

3.1 Origin

Maizzle started in 2018 from Romanian developer Cosmin Popovici. The core idea: use Tailwind for email. Tailwind is a utility-class framework built for web pages, but Maizzle adapts the same developer experience to email. Maizzle 5, released in 2024, was rewritten on top of Vite, and the current line is 6.x.

npx create-maizzle
# Maizzle Starter? Default
# Project name? my-emails
cd my-emails
npm install
npm run dev

Default layout:

my-emails/
  src/
    components/    # reusable components
    layouts/       # layouts (main.html etc.)
    templates/     # actual emails (welcome.html etc.)
  tailwind.config.js
  config.js
  package.json

3.2 How it works

At build time Maizzle:

  1. Converts Tailwind classes into inline styles.
  2. Inlines the classes that cannot survive in a <style> block.
  3. Leaves media queries in <style> (Outlook can ignore them, that's fine).
  4. Minifies the HTML.
  5. Optionally generates a plain-text version.

You write this:

<table class="w-full max-w-[600px] mx-auto bg-white">
  <tr>
    <td class="p-6 text-base font-sans text-slate-800">
      <h1 class="text-2xl font-bold mb-4">Welcome</h1>
      <p>Thanks for signing up. Hit the button below to get started.</p>
    </td>
  </tr>
</table>

You ship this:

<table style="width: 100%; max-width: 600px; margin: 0 auto; background-color: #ffffff;">
  <tr>
    <td style="padding: 24px; font-size: 16px; font-family: ui-sans-serif, system-ui; color: #1e293b;">
      <h1 style="font-size: 24px; font-weight: 700; margin-bottom: 16px;">Welcome</h1>
      <p>Thanks for signing up. Hit the button below to get started.</p>
    </td>
  </tr>
</table>

3.3 Strengths

3.4 Weaknesses

Maizzle shines when the frontend team owns the email pipeline directly.


4. MJML — Mailjet's component DSL

4.1 History

Mailjet (now Sinch Email) open-sourced MJML in 2015. It is pronounced "M-J-M-L". The project is an email-specific markup language plus a compiler that produces 1998-compatible HTML.

<mjml>
  <mj-head>
    <mj-title>Welcome</mj-title>
    <mj-preview>Thanks for joining. Let's get you started.</mj-preview>
    <mj-attributes>
      <mj-all font-family="Inter, Arial, sans-serif" />
      <mj-text color="#1e293b" line-height="1.5" />
    </mj-attributes>
  </mj-head>
  <mj-body background-color="#f8fafc" width="600px">
    <mj-section background-color="#ffffff" padding="24px">
      <mj-column>
        <mj-text font-size="24px" font-weight="700">Welcome</mj-text>
        <mj-text>Thanks for signing up. Tap the button below to get started.</mj-text>
        <mj-button background-color="#3b82f6" href="https://example.com">
          Get started
        </mj-button>
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>

4.2 What is good

import mjml2html from 'mjml'

const { html, errors } = mjml2html(mjmlSource, {
  minify: true,
  keepComments: false,
})

4.3 Weaknesses

MJML is still the right answer for teams that want an open standard but do not want a React dependency.


5. react-email (Resend) — the JSX-native option

5.1 How it took off

Resend founder Zeno Rocha published react-email in 2023. The premise was simple: "I want to write email as components, in JSX." Riding Resend's growth, it became the de-facto choice in the indie / startup world by 2024, and 4.x landed in January 2026.

npm install react-email @react-email/components -D
npx react-email dev    # local preview server
// emails/welcome.jsx
import {
  Body,
  Button,
  Container,
  Head,
  Heading,
  Html,
  Preview,
  Section,
  Text,
} from '@react-email/components'

export default function Welcome({ name = 'friend' }) {
  return (
    <Html lang="en">
      <Head />
      <Preview>Thanks for joining. Let's get you started.</Preview>
      <Body style={main}>
        <Container style={container}>
          <Heading style={h1}>Welcome, {name}</Heading>
          <Section>
            <Text>Thanks for signing up. Tap the button to get started.</Text>
            <Button href="https://example.com" style={btn}>
              Get started
            </Button>
          </Section>
        </Container>
      </Body>
    </Html>
  )
}

const main = { backgroundColor: '#f8fafc', fontFamily: 'Inter, Arial, sans-serif' }
const container = { maxWidth: 600, margin: '0 auto', backgroundColor: '#fff', padding: 24 }
const h1 = { fontSize: 24, fontWeight: 700, color: '#1e293b' }
const btn = { backgroundColor: '#3b82f6', color: '#fff', padding: '12px 24px', borderRadius: 6 }

(JSX curly braces above are inside a code block, so they are inert. Never expose bare curly identifiers in prose.)

5.2 Strengths

import { Resend } from 'resend'
import Welcome from '../emails/welcome'

const resend = new Resend(process.env.RESEND_API_KEY)
await resend.emails.send({
  from: 'Acme <hello@mail.acme.com>',
  to: ['user@example.com'],
  subject: 'Welcome',
  react: <Welcome name="Youngju" />,
})

5.3 Weaknesses

5.4 react-email vs MJML

Same conceptual model, different ergonomics:

If you are a React team, react-email. Otherwise, MJML.


6. Postmark Templates — server-side variable substitution

6.1 Positioning

Postmark is a transactional-first ESP with a strong template system based on MJML plus Mustachio (a Mustache variant). Postmark was acquired by ActiveCampaign in 2024 and continues to run as a standalone product in 2026.

<!-- Postmark template body -->
<table>
  <tr>
    <td>
      <h1>Hi {{name}}</h1>
      <p>Your order #{{order_id}} has been received.</p>
      {{#each items}}
        <p>{{name}} x {{quantity}} = {{total_usd}}</p>
      {{/each}}
      <a href="{{tracking_url}}">Track your shipment</a>
    </td>
  </tr>
</table>

You write the template with Mustachio placeholders, then inject data at send time through the API.

import { ServerClient } from 'postmark'

const client = new ServerClient(process.env.POSTMARK_TOKEN)

await client.sendEmailWithTemplate({
  From: 'orders@example.com',
  To: 'user@example.com',
  TemplateAlias: 'order-confirmation',
  TemplateModel: {
    name: 'Youngju',
    order_id: 'A-1234',
    items: [
      { name: 'Book', quantity: 1, total_usd: '20.00' },
      { name: 'Coffee', quantity: 2, total_usd: '12.00' },
    ],
    tracking_url: 'https://example.com/track/A-1234',
  },
})

6.2 Strengths

6.3 Weaknesses

Server-side templates work best when "marketing edits copy frequently, structure rarely" holds true.

6.4 Compared to SendGrid Dynamic Templates / HubSpot


7. Foundation for Emails (ZURB) — the classic framework

7.1 ZURB's legacy

ZURB was famous in the early 2010s for the Foundation CSS framework (Bootstrap's main rival). In 2015 they spun off an email-specific branch named Foundation for Emails (codename Ink). Version 2 shipped in 2017 and there have been no large updates since, but the project is still maintained.

<!-- Foundation for Emails - Inky markup -->
<container>
  <row>
    <columns small="12" large="6">
      <h1>Welcome</h1>
      <p>Thanks for signing up.</p>
      <button href="https://example.com">Get started</button>
    </columns>
    <columns small="12" large="6">
      <img src="https://example.com/welcome.png" alt="Welcome" />
    </columns>
  </row>
</container>

With the Inky markup you write container, row, columns, button, and the compiler converts them to table-based HTML. MJML's spiritual ancestor.

7.2 Is it worth using in 2026?

For new projects, mostly no. MJML and react-email are better in nearly every dimension. But:

For those, it remains reasonable.


8. Cerberus templates (Ted Goas)

8.1 What it is

Cerberus is a collection of plain HTML email templates published around 2013 by designer and developer Ted Goas. No build tooling — you copy the HTML file and edit. The repository is still maintained in 2026 with around 8.5k GitHub stars.

Three core templates:

  1. cerberus-fluid.html — single column, mobile-first.
  2. cerberus-responsive.html — media-query-based responsive.
  3. cerberus-hybrid.html — Outlook conditional comments plus mobile media queries.
<!--[if (gte mso 9)|(IE)]>
<table align="center" border="0" cellspacing="0" cellpadding="0" width="600">
<tr>
<td align="center" valign="top" width="600">
<![endif]-->
<table align="center" border="0" cellpadding="0" cellspacing="0"
       style="max-width: 600px; margin: auto;" class="email-container">
  <tr>
    <td>Body</td>
  </tr>
</table>
<!--[if (gte mso 9)|(IE)]>
</td>
</tr>
</table>
<![endif]-->

That is the famous Outlook conditional comment pattern. Only Outlook reads the markup inside <!--[if (gte mso 9)|(IE)]>. Because Outlook ignores max-width, you need a fixed-width 600-pixel table for it alone.

8.2 Why it still matters

The fastest learning path for an engineer new to email is: read Cerberus once, then move to Maizzle / MJML / react-email.


9. HEML / mosaico — the other OSS options

9.1 HEML

SparkPost (now MessageBird) open-sourced HEML in 2018.

<heml>
  <head>
    <subject>Hello</subject>
  </head>
  <body>
    <container>
      <h1>Welcome</h1>
      <p>Thanks for signing up.</p>
      <button href="https://example.com">Start</button>
    </container>
  </body>
</heml>

Concept-wise nearly identical to MJML, but there has been very little movement since 2020. In 2026 it is effectively in maintenance mode.

9.2 mosaico

An open-source drag-and-drop editor originally backed by Vox Media. You self-host it and hand it to your marketing team.

Occasionally adopted by teams that want an internal builder but cannot stomach SaaS pricing.


10. Stripo / BEE / Stensul / Unlayer — drag-and-drop SaaS

10.1 Where each tool sits

ToolParentPricing (2026)Primary customer
StripoStripo (independent)Free to $95/monthSMB marketing teams
BEEBEE Content DesignFree to $150/monthEnterprises, embed SDK
StensulStensulEnterprise onlyLarge enterprises with brand governance
UnlayerUnlayerFree to $200/monthSaaS embedding

10.2 Stripo

The most friendly general-purpose editor. Supports self-hosting, downloads, and direct ESP send. Strong module library (Shutterstock integration and similar).

10.3 BEE

Originally part of MailUp's BEE Free editor. Its biggest differentiator is the embedded SDK — you can drop BEE inside your own SaaS. HubSpot, ClickFunnels, and many others OEM it.

10.4 Stensul

Enterprise-only. Not really an editor so much as an email collaboration workflow — brand-guideline enforcement, approval routing, multi-language translation pipelines. Large finance / pharma / telco shops are the primary customers.

10.5 Unlayer

Built for SaaS embedding. The react-email-editor package drops Unlayer into your React product in under five minutes.

import EmailEditor from 'react-email-editor'

export default function Editor() {
  return (
    <EmailEditor
      projectId={12345}
      onLoad={(unlayer) => {
        // ready
      }}
      onReady={(unlayer) => {
        unlayer.exportHtml((data) => {
          console.log(data.html)
        })
      }}
    />
  )
}

(Again, the JSX braces are inside a code block.)

10.6 mosaico vs SaaS — the trade-off


11. Email-Builder.js (Microsoft) / Tabular — the newcomers

11.1 Email-Builder.js

Open-sourced by Microsoft in 2024. React-based email builder. The interesting bit is the company behind Outlook is shipping the tool.

import { Reader } from '@usewaypoint/email-builder'

const document = {
  root: {
    type: 'EmailLayout',
    data: {
      backdropColor: '#F5F5F5',
      canvasColor: '#FFFFFF',
      children: ['block-1', 'block-2'],
    },
  },
  'block-1': {
    type: 'Heading',
    data: { props: { text: 'Welcome', level: 'h1' } },
  },
  'block-2': {
    type: 'Text',
    data: { props: { text: 'Thanks for signing up.' } },
  },
}

export default function Preview() {
  return <Reader document={document} rootBlockId="root" />
}

11.2 Tabular

A 2024 drag-and-drop SaaS newcomer. Differentiator: AI-first. It generates copy, imagery, and layout from LLMs as a primary workflow. Already gaining traction with indie marketing teams.


12. Litmus / Email on Acid — testing

12.1 Origins

There are well over a hundred email clients and you cannot know how your email renders without actually opening it in each one. Litmus and Email on Acid exist because of that.

Both products are functionally similar:

  1. Client previews — screenshots across 90 to 100+ clients.
  2. Spam analysis — how SpamAssassin, Microsoft, and others score the message.
  3. Link / image checks — broken links, missing images.
  4. Accessibility checks — alt text, color contrast, font size.
  5. Analytics — opens and clicks.

12.2 The workflow

The typical loop:

  1. Build HTML with Maizzle / MJML / react-email.
  2. Upload to Litmus or Email on Acid (directly or via your ESP integration).
  3. Review per-client previews.
  4. Fix the broken ones and re-upload.
  5. When it passes, send through the ESP.
// Hypothetical Litmus preview request
import fetch from 'node-fetch'

const res = await fetch('https://api.litmus.com/v1/emails', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.LITMUS_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    html: htmlSource,
    subject: 'Test',
    clients: ['outlook2021', 'gmail-web', 'ios-mail-17', 'samsung-mail'],
  }),
})

12.3 Pricing

Both are expensive in 2026. Entry pricing sits around $99/month; serious usage lands at $199 to $400/month. Indie developers usually start with Mailtrap, HTML Email Check, or PutsMail (Litmus's free tool).


13. Dark mode, accessibility, MIME multipart, AMP for Email

13.1 Dark mode — Outlook's new hell

By 2024 every major client supports dark mode, but they implement it three different ways.

  1. Apple Mail (iOS / macOS) — honors prefers-color-scheme: dark honestly. The clean case.
  2. Outlook desktop / mobileinverts colors itself. White backgrounds become black, but only some colors invert, so logos break.
  3. Gmail — partial inversion. The result depends on the combination of client and OS settings.

A typical defense:

<head>
<style>
  /* Color-scheme metadata */
  :root {
    color-scheme: light dark;
    supported-color-schemes: light dark;
  }

  @media (prefers-color-scheme: dark) {
    .body-bg { background-color: #0f172a !important; }
    .text { color: #e2e8f0 !important; }
  }

  /* Try to stop Outlook from forcing inversion (client-dependent) */
  [data-ogsc] .body-bg { background-color: #0f172a !important; }
  [data-ogsc] .text { color: #e2e8f0 !important; }
</style>
</head>

The core rule: logos and icons should be SVG, or ship both dark and light versions — so inversion does not destroy your brand.

13.2 Accessibility — WCAG, for email

Email is subject to WCAG 2.2 AA. The short checklist:

<table role="presentation" aria-hidden="false">
  <tr>
    <td>
      <img src="logo.png" alt="Acme logo" width="120" height="40" />
    </td>
  </tr>
</table>

13.3 MIME multipart — plain text is non-optional

Virtually every marketing email should go out as multipart/alternative. Two reasons.

  1. A missing plain-text part raises spam scores — SpamAssassin and friends treat HTML-only as suspicious.
  2. Apple Watch, text-only clients, and screen readers consume the plain-text part.
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="boundary42"

--boundary42
Content-Type: text/plain; charset=utf-8

Welcome.

Thanks for signing up. Open this link to get started:
https://example.com/start

--boundary42
Content-Type: text/html; charset=utf-8

<html>...</html>
--boundary42--

react-email generates this with render(<Welcome />, { plainText: true }). Maizzle does it through juice automatically.

13.4 AMP for Email — almost dead, not quite

Google launched AMP for Email in 2019 to bring dynamic content into the inbox — form submission, carousels, live-updating data.

<!-- AMP for Email -->
<!DOCTYPE html>
<html amp4email data-css-strict>
<head>
  <meta charset="utf-8">
  <script async src="https://cdn.ampproject.org/v0.js"></script>
  <style amp4email-boilerplate>body{visibility:hidden}</style>
  <style amp-custom>
    .container { padding: 16px; }
  </style>
</head>
<body>
  <amp-form method="post" action-xhr="https://example.com/subscribe">
    <input type="email" name="email" required />
    <input type="submit" value="Subscribe" />
  </amp-form>
</body>
</html>

In 2026 it is effectively dead. Why:

Booking.com, Pinterest, and other early adopters mostly rolled back around 2024. If you are starting now, ignore AMP.


14. AI in email — MJML AI, Maizzle AI?, ChatGPT for design

14.1 MJML AI

Mailjet's 2024 tool. You describe the email in natural language — "welcome email, blue tones, one CTA button" — and it returns MJML.

[Input]
Make a sign-up welcome email. Blue tones, company logo on top, greeting, CTA button "Get started", social links at the bottom.

[Output]
<mjml>
  <mj-body>
    <mj-section>
      <mj-column>
        <mj-image src="logo.png" width="120px" />
      </mj-column>
    </mj-section>
    ...
  </mj-body>
</mjml>

Quality is above average. The design usually needs a human pass to feel less generic.

14.2 Maizzle / react-email + ChatGPT

No dedicated tool required. Asking ChatGPT or Claude to "write a Maizzle component for X" works well in 2026 — LLMs understand email markup well enough.

Effective prompt hints:

14.3 Tabular's AI integration

Tabular treats LLM-driven body generation as a first-class workflow. The marketing team sets a brand voice and Tabular drafts the weekly newsletter. Indie marketing teams are picking it up fast in 2026.


15. Korea / Japan — Toss, Kakao, Mercari, Cookpad

15.1 Korea

15.2 Japan

15.3 Korea / Japan in common — review and send timing


16. Tool selection guide — as of May 2026

By situation:

Whatever the path, test with Litmus or Email on Acid. Indie teams can start with the free PutsMail tool.

Dark mode, accessibility, and MIME multipart are non-negotiable across the board. And AMP for Email is safe to ignore in 2026.


References

Comments

No comments yet.

Sign in to leave a comment