A colorful post office sorting room with glowing envelopes

Maizzle: Tailwind CSS Meets the Email Inbox

The Orange Cat
The Orange Cat

Building HTML emails is one of those tasks that makes even experienced developers wince. Email clients have wildly inconsistent CSS support, inline styles are mandatory for many clients, and one wrong move can turn a polished design into a jumbled mess in Outlook. Maizzle takes the sting out of this process by letting you write emails using Tailwind CSS utility classes on real HTML markup, then running a build pipeline that handles CSS inlining, unused style purging, and a host of email-specific optimizations. If you already know Tailwind, you already know most of Maizzle.

What Makes It Click

Maizzle stands apart from tools like MJML or React Email by not abstracting away your HTML. You write actual table-based email markup (yes, tables are still the way) and decorate it with Tailwind classes. The framework then takes care of:

  • CSS inlining so every style attribute lands exactly where email clients need it
  • Unused CSS purging to keep your email payload tiny
  • Responsive email optimizations that work across the patchwork of email client rendering engines
  • Widow prevention to avoid lonely words on the last line of paragraphs
  • Hex color normalization using six-digit shorthand for maximum compatibility
  • HTML minification for production-ready output
  • Hot Markup Replacement (HMR) in development for a 10x faster feedback loop compared to the old Browsersync approach

Getting It Installed

Install @maizzle/framework with your preferred package manager:

// npm
npm install @maizzle/framework

// yarn
yarn add @maizzle/framework

To scaffold a brand-new project with all the starter files, use the CLI:

npx create-maizzle

This sets up a ready-to-go project with a default configuration, example templates, and the dev server wired up.

Your First Email Template

Setting Up the Config

Maizzle projects use a configuration file that controls the build pipeline. Here is a minimal setup:

// config.js
export default {
  build: {
    content: ['src/templates/**/*.html'],
    output: {
      path: 'build_production',
    },
  },
  css: {
    inline: true,
    purge: true,
  },
  prettify: true,
};

This tells Maizzle where to find your templates, where to output the built files, and to inline CSS while purging unused styles.

Writing a Template

Templates are HTML files with front matter for per-template configuration:

---
title: "Welcome to Our Service"
preheader: "Thanks for signing up"
---

<table class="w-full">
  <tr>
    <td class="p-6 bg-blue-600 text-white text-center">
      <h1 class="text-2xl font-bold m-0">Welcome Aboard</h1>
    </td>
  </tr>
  <tr>
    <td class="p-8 bg-white">
      <p class="text-gray-700 text-base leading-relaxed">
        We are thrilled to have you here. Your account is all set up
        and ready to go.
      </p>
      <table class="mx-auto">
        <tr>
          <td class="bg-blue-600 rounded px-6 py-3">
            <a href="https://example.com/dashboard"
               class="text-white text-sm font-semibold no-underline">
              Go to Dashboard
            </a>
          </td>
        </tr>
      </table>
    </td>
  </tr>
</table>

Every Tailwind class you know works here. After the build, each class gets inlined as a style attribute so that Gmail, Outlook, and Apple Mail all render it correctly.

Running the Dev Server

Start the development server to preview your emails in real-time:

npx maizzle serve

The HMR-powered dev server uses Express.js, WebSockets, and morphdom to update your preview instantly as you edit templates. No full page reloads needed.

Taking It Further

Conditional Content by Environment

Maizzle provides special tags for rendering content based on the build environment. This is useful when you want placeholder content in development but real tracking pixels in production:

<env:local>
  <p class="text-xs text-gray-400">
    Development mode - tracking disabled
  </p>
</env:local>

<env:production>
  <img src="https://track.example.com/open.gif"
       width="1" height="1" alt="" />
</env:production>

The <env:?> tags let you keep environment-specific markup in the same template without any runtime conditionals.

Events and Hooks

Maizzle exposes a powerful events system that lets you run custom JavaScript at key points in the build process:

// config.js
export default {
  build: {
    content: ['src/templates/**/*.html'],
  },
  events: {
    beforeRender(html, config) {
      // Modify the HTML string before compilation
      return html.replace(/{{year}}/g, new Date().getFullYear().toString());
    },
    afterTransformers(html, config) {
      // Run after all Maizzle transformers (inlining, purging, etc.)
      // Great for last-minute tweaks or custom post-processing
      return html;
    },
  },
};

These hooks give you full control over the pipeline without needing to eject from the framework.

Progressive Enhancement with Duplicate Properties

Email clients handle CSS differently, and sometimes you want to provide a fallback value alongside a modern one. Maizzle v5 supports inlining duplicate CSS properties for progressive enhancement:

<td style="background-color: #3b82f6; background-color: rgb(59, 130, 246);">
  Modern clients get the rgb value, older ones fall back to hex.
</td>

You can also exclude specific CSS from inlining using HTML comments, which is handy when you need styles to stay in the <style> tag for responsive media queries.

Why Not MJML or React Email

The choice between Maizzle and alternatives like MJML or React Email comes down to control versus abstraction. MJML uses custom tags like <mj-section> and <mj-column> that compile to email-safe HTML, hiding the table structure from you. This is great if you want to avoid thinking about tables, but it limits how much you can customize the final output.

React Email takes the component approach, which feels natural for React developers but adds React as a dependency and is a newer ecosystem with fewer email-specific optimizations.

Maizzle sits in the sweet spot for developers who want full control over their HTML while using a familiar styling system. You see exactly what gets sent, and Tailwind classes make the styling readable and maintainable.

Wrapping Up the Envelope

Maizzle turns email development from a dreaded chore into something that feels remarkably close to normal web development. The combination of Tailwind CSS utility classes, real HTML markup, and an automated build pipeline that handles CSS inlining, purging, and email quirks means you spend your time designing emails instead of debugging them across a dozen clients. With v5 bringing Hot Markup Replacement and a streamlined configuration, @maizzle/framework is a solid choice for anyone who builds HTML emails and values both speed and control.