Tailwind CSS 75 🎨 Tailwind in Email Template Engines (maizzle / react-email CSS Inline Execution)
Email clients are not browsers. Gmail strips the <style> tags in some configurations. Outlook uses Microsoft Word as its rendering engine. Yahoo and AOL rewrite the class selectors. The CSS that works in a web page breaks in an email client, and the utilities that Tailwind generates are not the exception. The email template engines bridge the gap: they compile the Tailwind classes, lower the modern syntax, rewrite the unsafe selectors, and inline the CSS into the style attributes. The two dominant tools are Maizzle and React Email, and the two take the different approaches to the same problem.
Key point: The email client does not run the Tailwind engine. The engine runs at the build or the render time, and the output is the inline CSS. The Tailwind class name is the authoring convenience, and the style="..." attribute is the deliverable.
Why the email engines exist
The class-stripping problem. Gmail (the Android with the IMAP) ignores the <style> tags entirely . The class-based CSS does not apply, and the element renders unstyled. The inline CSS is the only reliable mechanism, and the engine produces it.
The selector-rewriting problem. The Tailwind variants use the : and the / in the class names. The sm:block and the w-1/2 are the examples. Some email clients (notably Gmail) strip the class names with the special characters, and the styles are lost. The safe class names transformer rewrites the sm:block to the sm-block .
The modern-syntax problem. The Tailwind v4 uses the oklch() colors, the CSS nesting, and the custom properties. The most email clients do not support the modern. The Maizzle uses the Lightning CSS and the custom tools to lower the syntax to the simple CSS .
The unit problem. The Tailwind uses the rem as the main unit for the accessibility. The email clients do not support the rem consistently. The pixelBasedPreset in the React Email changes the rem to the 16px base .
The table-layout problem. The email clients render the HTML tables more reliably than the modern layout. The Tailwind’s flexbox and grid utilities do not work in the Outlook. The Maizzle and the React Email provide the table-based components for the layout .
The support-matrix problem. The CSS support varies by the client. The border-radius works in the Apple Mail and the Gmail but not the older Outlook. The box-shadow does not work in the Outlook desktop. The audit is the manual, and the tools provide the guidance .
The two-engine problem. The Maizzle is the build-time engine: it compiles the templates to the HTML and the CSS, and the output is the static. The React Email is the render-time engine: it compiles the React components to the HTML and the inline CSS at the render .
a. The Maizzle
Maizzle is the framework for the HTML email. It uses the Vue SFC for the templates, the Tailwind CSS for the styling, and the transformers for the email-specific processing.
The Tailwind component
The <Tailwind> component wraps the content, and the classes inside are fed to the compiler . The <Head /> component is required, and the compiled <style> tag is injected into the head.
<template>
<Html>
<Head />
<Body>
<Tailwind>
<Container class="max-w-xl bg-white p-4">
<Text class="text-lg font-bold">Hello</Text>
</Container>
</Tailwind>
</Body>
</Html>
</template>
The max-w-xl and the text-lg are the Tailwind classes, and the compiler resolves them.
The transformers
The transformers run after the template is compiled. The css.inline inlines the CSS into the style attributes, the css.purge removes the unused, and the css.safe rewrites the class names .
| The transformer | The purpose |
|---|---|
css.inline | The inline the CSS |
css.purge | The remove the unused |
css.safe | The rewrite the class names |
css.shorthand | The shorten the margin and padding |
The css.inline is the critical one for the Gmail Android.
The @maizzle/tailwindcss
The @maizzle/tailwindcss is the email-friendly Tailwind v4 configuration. It ships the email-safe typography, the MSO utilities, and the client-targeting variants .
@import "@maizzle/tailwindcss";
The config includes the mso-* utilities for the Outlook and the variants like gmail:, yahoo:, and outlook-mac: .
The MSO utilities
The Outlook on Windows uses the Word rendering engine and the mso-* CSS properties. The @maizzle/tailwindcss exposes them as the utilities .
<div class="mso-padding-alt-4">...</div>
The utility produces the mso-padding-alt property that only the Outlook reads.
The client targeting
The variants target the specific clients. The gmail: applies only in the Gmail, and the outlook-mac: applies only in the Outlook Mac .
<div class="gmail:bg-red-500">...</div>
The variant compiles to the selector that the Gmail’s parser can match.
The nested blocks
The multiple <Tailwind> blocks in the same template share the same class names. The .text-brand from the block A and the block B target the same selector, and the cascade resolves to the last . The workaround is the distinct class names per region.
The Maizzle table
| The element | The purpose |
|---|---|
<Tailwind> | The wrap the content |
<Head /> | The required |
css.inline | The inline the CSS |
css.safe | The safe class names |
@maizzle/tailwindcss | The email config |
The mso-* | The Outlook |
The gmail: | The client variant |
b. The React Email
The React Email is the React component library for the email. It provides the unstyled components, and the <Tailwind> component processes the className values and the inlines them at the render time .
The Tailwind component
The <Tailwind> wraps the email content, and the className values are compiled to the inline styles.
import { Tailwind, pixelBasedPreset, Button } from "react-email";
const Email = () => (
<Tailwind config={{ presets: [pixelBasedPreset] }}>
<Button className="bg-brand px-3 py-2 text-white" href="...">
Click
</Button>
</Tailwind>
);
The bg-brand is the custom color, and the px-3 and the py-2 are the spacing .
The pixelBasedPreset
The pixelBasedPreset converts the rem-based utilities to the pixel values. The text-base becomes the 16px instead of the 1rem .
<Tailwind config={{ presets: [pixelBasedPreset] }}>
Without the preset, the text-base renders as the 1rem, and the email clients ignore or render inconsistently.
The inline execution
The <Tailwind> component looks up the className in the generated CSS and applies the matching declarations to the element’s style attribute at the render . The CSS is not the separate file; it is the inline.
<Button className="bg-brand px-3 py-2">
// The rendered
<a style="background-color: #007291; padding-left: 12px; padding-right: 12px; ...">
The known limitations
The <Tailwind> does not support the prose from the @tailwindcss/typography, the space-* utility, and the complex selectors with the more than the one class lookup . The hover: styles are the limited, and the media queries are not the inlined.
| The limitation | The reason |
|---|---|
The prose | The complex selectors |
The space-* | The descendant selectors |
The hover: | The poor support |
| The context inside | The technical limitation |
The context limitation
The React context provider inside the <Tailwind> does not work for the children. The workaround is to move the provider higher than the <Tailwind> .
The React Email table
| The element | The purpose |
|---|---|
<Tailwind> | The wrap |
pixelBasedPreset | The rem to px |
| The inline execution | The style attribute |
The prose | The not supported |
The space-* | The not supported |
| The context | The provider higher |
c. The comparison and the patterns
The two engines solve the same problem with the different architecture.
The build versus the render
The Maizzle compiles the templates to the static HTML at the build. The React Email renders the components to the HTML at the request . The Maizzle is the static, and the React Email is the dynamic.
The class handling
The Maizzle rewrites the class names with the css.safe and the inlines with the css.inline. The React Email looks up the class names and the inlines at the render .
The unit handling
The Maizzle lowers the modern CSS with the Lightning CSS. The React Email uses the pixelBasedPreset .
The client targeting
The Maizzle provides the variants like the gmail: and the outlook-mac: . The React Email relies on the standard Tailwind and the inline.
The components
The Maizzle uses the Vue SFC and the HTML. The React Email uses the React components like the Button, the Text, and the Section .
The MSO
The Maizzle provides the mso-* utilities. The React Email relies on the custom CSS and the inline.
The audit
The eslint-plugin-tailwindcss and the community plugins warn about the unsupported classes in the email . The audit is the manual, and the plugin is the CI.
The comparison table
| The aspect | The Maizzle | The React Email |
|---|---|---|
| The time | The build | The render |
| The template | The Vue SFC | The React |
| The inline | The css.inline | The <Tailwind> |
| The unit | The Lightning CSS | The pixelBasedPreset |
| The variants | The client-specific | The standard |
| The MSO | The mso-* | The custom |
| The output | The static | The dynamic |
The unsupported classes
The classes that do not work in the email: the flexbox, the grid, the transform, the negative margin, the animation, the transition, the responsive, the dark mode, and the hover . The engine filters or the rewrites them.
| The category | The support |
|---|---|
| The flexbox | The ~60% |
| The grid | The ~55% |
| The transform | The ~46% |
| The negative margin | The not |
| The animation | The not |
| The responsive | The no media query |
| The dark mode | The no |
| The hover | The no |
Complete Example Session
<!-- ============================================
PART 1: THE MAIZZLE TEMPLATE
============================================ -->
<template>
<Html>
<Head />
<Body class="bg-gray-100">
<Tailwind>
<Container class="max-w-xl mx-auto bg-white p-6">
<Text class="text-xl font-bold text-gray-900">Welcome</Text>
<Text class="text-base text-gray-600 mt-4">
Thanks for signing up.
</Text>
<Button
href="https://example.com"
class="mt-6 bg-blue-600 text-white px-4 py-2 rounded"
>
Get Started
</Button>
</Container>
</Tailwind>
</Body>
</Html>
</template>
<!-- ============================================
PART 2: THE TRANSFORMERS
============================================ -->
// maizzle.config.ts
export default defineConfig({
css: {
inline: true,
purge: true,
safe: true,
},
});
// The css.inline inlines the CSS into the style attributes.
// The css.safe rewrites the sm:block to the sm-block.
<!-- ============================================
PART 3: THE REACT EMAIL TEMPLATE
============================================ -->
import { Tailwind, pixelBasedPreset, Button, Container, Text } from "react-email";
const Email = () => (
<Tailwind config={{ presets: [pixelBasedPreset] }}>
<Container className="max-w-xl mx-auto bg-white p-6">
<Text className="text-xl font-bold text-gray-900">Welcome</Text>
<Button
href="https://example.com"
className="mt-6 bg-blue-600 text-white px-4 py-2 rounded"
>
Get Started
</Button>
</Container>
</Tailwind>
);
// The className values are inlined at the render.
<!-- ============================================
PART 4: THE CUSTOM THEME
============================================ -->
<Tailwind
config={{
presets: [pixelBasedPreset],
theme: {
extend: {
colors: {
brand: "#007291",
},
},
},
}}
>
<Button className="bg-brand px-3 py-2 text-white">Click</Button>
</Tailwind>
// The bg-brand uses the custom color.
<!-- ============================================
PART 5: THE MSO UTILITY
============================================ -->
<div class="mso-padding-alt-4">...</div>
// The mso-padding-alt is the Outlook-specific.
<!-- ============================================
PART 6: THE CLIENT VARIANT
============================================ -->
<div class="gmail:bg-red-500">...</div>
<div class="yahoo:underline">...</div>
// The variants target the specific clients.
<!-- ============================================
PART 7: THE PIXEL BASED
============================================ -->
<Tailwind config={{ presets: [pixelBasedPreset] }}>
<Text className="text-base">...</Text>
// The text-base is the 16px, not the 1rem.
</Tailwind>
<!-- ============================================
PART 8: THE INLINE OUTPUT
============================================ -->
// The source
<Button className="bg-blue-600 px-4 py-2">
// The rendered
<a style="background-color: #2563eb; padding-left: 16px; padding-right: 16px; padding-top: 8px; padding-bottom: 8px;">
<!-- ============================================
PART 9: THE UNSUPPORTED CLASSES
============================================ -->
// The flexbox, the grid, the transform, the animation.
// The responsive, the dark mode, the hover.
// The engine filters or the rewrites.
<!-- ============================================
PART 10: THE COMPLETE PATTERN
============================================ -->
// 1. Use the Tailwind component to wrap.
// 2. Use the pixelBasedPreset in the React Email.
// 3. The engine inlines the CSS.
// 4. The safe class names rewrite the special.
// 5. The mso-* utilities for the Outlook.
// 6. The client variants for the targeting.
// 7. The table layout for the structure.
// 8. Avoid the flexbox, the grid, the transform.
// 9. Avoid the responsive, the dark, the hover.
// 10. The output is the inline style.
The ten parts showed the Maizzle template, the transformers, the React Email template, the custom theme, the MSO utility, the client variant, the pixel-based, the inline output, the unsupported classes, and the complete pattern.
Quick Reference
The Maizzle
| The element | The purpose |
|---|---|
<Tailwind> | The wrap |
<Head /> | The required |
css.inline | The inline |
css.safe | The safe names |
@maizzle/tailwindcss | The config |
The mso-* | The Outlook |
The gmail: | The variant |
The React Email
| The element | The purpose |
|---|---|
<Tailwind> | The wrap |
pixelBasedPreset | The rem to px |
The className | The inlined |
The config | The custom theme |
The prose | The not supported |
| The context | The provider higher |
The Support Matrix
| The feature | The support |
|---|---|
| The inline CSS | The universal |
| The border-radius | The modern |
| The box-shadow | The no Outlook |
| The flexbox | The ~60% |
| The grid | The ~55% |
| The transform | The ~46% |
| The responsive | The no |
| The dark mode | The no |
The Units
| The unit | The support |
|---|---|
| The px | The universal |
| The rem | The limited |
| The em | The limited |
| The % | The good |
The Client Variants
| The variant | The client |
|---|---|
gmail: | The Gmail |
yahoo: | The Yahoo |
outlook-mac: | The Outlook Mac |
ios: | The iOS |
apple-mail: | The Apple Mail |
Best Practices
✅ Do This:
<!-- Wrap the content with the Tailwind component. -->
<Tailwind>
<Container class="max-w-xl p-6"> <!-- ✅ -->
// Use the pixelBasedPreset in the React Email.
<Tailwind config={{ presets: [pixelBasedPreset] }}> <!-- ✅ -->
// Enable the css.inline in the Maizzle.
css: { inline: true, safe: true } <!-- ✅ -->
<!-- Use the mso-* utilities for the Outlook. -->
<div class="mso-padding-alt-4"> <!-- ✅ -->
<!-- Use the client variant for the targeting. -->
<div class="gmail:bg-red-500"> <!-- ✅ -->
// Use the table-based components.
<Section><Row><Column> <!-- ✅ -->
// Use the px-based units.
<Text className="text-base"> <!-- ✅ The pixelBasedPreset -->
❌ Don’t Do This:
// Don't use the flexbox.
<div className="flex items-center"> <!-- ❌ The ~60% -->
// Don't use the grid.
<div className="grid grid-cols-2"> <!-- ❌ The ~55% -->
// Don't use the transform.
<div className="rotate-45"> <!-- ❌ The ~46% -->
// Don't use the responsive.
<div className="md:flex"> <!-- ❌ The no media query -->
// Don't use the dark mode.
<div className="dark:bg-gray-900"> <!-- ❌ The no -->
// Don't use the hover.
<button className="hover:bg-blue-700"> <!-- ❌ The no -->
// Don't use the space-* in the React Email.
<div className="space-y-4"> <!-- ❌ The not supported -->
Common Pitfalls
| The pitfall | The reason | The fix |
|---|---|---|
| The styles not applied | The Gmail strips the style | Use the css.inline |
| The class ignored | The : stripped | Use the css.safe |
| The rem ignored | The client does not support | Use the pixelBasedPreset |
| The layout broken | The flexbox | Use the table |
| The Outlook broken | The modern CSS | Use the mso-* |
| The variant not applied | The nested at-rule | Use the separate block |
| The context fails | The React limitation | Move the provider higher |
Real-World Examples
1. The Maizzle Wrap
<Tailwind><Container class="p-4">...</Container></Tailwind>
2. The React Email Wrap
<Tailwind config={{ presets: [pixelBasedPreset] }}>...</Tailwind>
3. The css.inline
css: { inline: true }
4. The css.safe
css: { safe: true }
5. The mso-* Utility
<div class="mso-padding-alt-4">
6. The Client Variant
<div class="gmail:bg-red-500">
7. The pixelBasedPreset
config={{ presets: [pixelBasedPreset] }}
8. The Custom Theme
config={{ theme: { extend: { colors: { brand: "#007291" } } } }}
9. The Inline Output
<a style="background-color: #2563eb; padding: 8px 16px;">
10. The Complete Pattern
<Tailwind><Container class="max-w-xl p-6">...</Container></Tailwind>
Visual
The Email Pipeline
┌────────────────────────────────────────────────────────────┐
│ THE EMAIL PIPELINE │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ THE SOURCE │ │
│ │ The Vue SFC / the React. │ │
│ │ The className="bg-blue-600 p-4". │ │
│ └────────────────────────┬─────────────────────────┘ │
│ │ │
│ v │
│ ┌──────────────────────────────────────────────────┐ │
│ │ THE TAILWIND COMPILER │ │
│ │ The class resolution. │ │
│ │ The CSS generation. │ │
│ └────────────────────────┬─────────────────────────┘ │
│ │ │
│ v │
│ ┌──────────────────────────────────────────────────┐ │
│ │ THE TRANSFORMERS / THE INLINE │ │
│ │ The css.inline. │ │
│ │ The css.safe. │ │
│ │ The pixelBasedPreset. │ │
│ └────────────────────────┬─────────────────────────┘ │
│ │ │
│ v │
│ ┌──────────────────────────────────────────────────┐ │
│ │ THE OUTPUT │ │
│ │ The HTML with the inline styles. │ │
│ │ The email-client-compatible. │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
The Class Rewriting
┌────────────────────────────────────────────────────────────┐
│ THE CLASS REWRITING │
│ │
│ THE SOURCE │
│ ┌──────────────────────────────────────────────────┐ │
│ │ class="sm:block w-1/2 hover:bg-blue-600" │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ THE GMAIL STRIPS THE SPECIAL │
│ ┌──────────────────────────────────────────────────┐ │
│ │ The ':' and the '/' are the special. │ │
│ │ The class is dropped. │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ THE SAFE REWRITE │
│ ┌──────────────────────────────────────────────────┐ │
│ │ class="sm-block w-1-2 hover-bg-blue-600" │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ The class survives the Gmail parser. │
└────────────────────────────────────────────────────────────┘
The Inline Execution
┌────────────────────────────────────────────────────────────┐
│ THE INLINE EXECUTION │
│ │
│ THE SOURCE │
│ ┌──────────────────────────────────────────────────┐ │
│ │ <div className="bg-blue-600 p-4 rounded"> │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ THE GENERATED CSS │
│ ┌──────────────────────────────────────────────────┐ │
│ │ .bg-blue-600 { background-color: #2563eb; } │ │
│ │ .p-4 { padding: 16px; } │ │
│ │ .rounded { border-radius: 4px; } │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ THE INLINE OUTPUT │
│ ┌──────────────────────────────────────────────────┐ │
│ │ <div style="background-color: #2563eb; │ │
│ │ padding: 16px; │ │
│ │ border-radius: 4px;"> │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ The email client reads the style attribute. │
└────────────────────────────────────────────────────────────┘
The Support Spectrum
┌────────────────────────────────────────────────────────────┐
│ THE SUPPORT SPECTRUM │
│ │
│ THE GOOD │
│ ┌──────────────────────────────────────────────────┐ │
│ │ The padding, the margin, the color, the font. │ │
│ │ The width, the height, the border. │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ THE LIMITED │
│ ┌──────────────────────────────────────────────────┐ │
│ │ The border-radius, the box-shadow, the opacity. │ │
│ │ The overflow. │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ THE NOT SUPPORTED │
│ ┌──────────────────────────────────────────────────┐ │
│ │ The flexbox, the grid, the transform. │ │
│ │ The animation, the transition, the negative. │ │
│ │ The responsive, the dark, the hover. │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
Summary
| The item | The value |
|---|---|
| The Maizzle | The build-time engine |
| The React Email | The render-time engine |
The <Tailwind> | The wrap |
The pixelBasedPreset | The rem to px |
The css.inline | The inline |
The css.safe | The safe names |
The mso-* | The Outlook |
| The client variant | The targeting |
| The inline style | The deliverable |
| The table layout | The structure |
Key takeaways:
- The email client does not run the Tailwind engine. The engine runs at the build (Maizzle) or the render (React Email), and the output is the inline CSS. The class name is the authoring convenience, and the
styleattribute is the deliverable. - The Maizzle uses the transformers. The
css.inlineinlines the CSS, thecss.saferewrites the class names, and the@maizzle/tailwindcssprovides the email-friendly config . - The React Email uses the
<Tailwind>component. TheclassNamevalues are looked up and inlined at the render. ThepixelBasedPresetconverts theremto the pixel . - The special characters in the class names are the problem. The Gmail strips the
:and the/. Thecss.saferewrites thesm:blockto thesm-block. - The
remis not the email-friendly. The email clients do not support theremconsistently. ThepixelBasedPresetchanges the base to the16px. - The modern CSS is lowered. The
oklch()colors, the CSS nesting, and the custom properties are lowered to the simple CSS by the Lightning CSS . - The table layout is the reliable. The flexbox and the grid are not supported in the Outlook. The
Section, theRow, and theColumnprovide the table-based layout . - The MSO utilities target the Outlook. The
mso-*properties work only in the Outlook. The@maizzle/tailwindcssexposes them as the utilities . - The client variants target the specific clients. The
gmail:, theyahoo:, and theoutlook-mac:apply only in the respective clients . - The support matrix is the guide. The flexbox (~60%), the grid (~55%), the transform (~46%), the responsive, the dark, and the hover are the not supported or the limited .
Remember: The Tailwind in the email is the different from the Tailwind in the web. The email clients are the limited, and the class names, the units, and the modern CSS are the problems. The Maizzle and the React Email solve the problems with the build-time or the render-time compilation, the inline CSS, the class rewriting, and the pixel-based units. The result is the email that renders consistently across the clients, and the Tailwind classes that are the authoring convenience.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!