Maizzle: Tailwind CSS Meets the Email Inbox
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.