| |

Tailwind CSS 75 🎨 Tailwind in Email Template Engines (maizzle / react-email CSS Inline Execution)

⏱️ Estimated read: 16 min | |

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 transformerThe purpose
css.inlineThe inline the CSS
css.purgeThe remove the unused
css.safeThe rewrite the class names
css.shorthandThe 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 elementThe purpose
<Tailwind>The wrap the content
<Head />The required
css.inlineThe inline the CSS
css.safeThe safe class names
@maizzle/tailwindcssThe 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 limitationThe reason
The proseThe complex selectors
The space-*The descendant selectors
The hover:The poor support
The context insideThe 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 elementThe purpose
<Tailwind>The wrap
pixelBasedPresetThe rem to px
The inline executionThe style attribute
The proseThe not supported
The space-*The not supported
The contextThe 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 aspectThe MaizzleThe React Email
The timeThe buildThe render
The templateThe Vue SFCThe React
The inlineThe css.inlineThe <Tailwind>
The unitThe Lightning CSSThe pixelBasedPreset
The variantsThe client-specificThe standard
The MSOThe mso-*The custom
The outputThe staticThe 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 categoryThe support
The flexboxThe ~60%
The gridThe ~55%
The transformThe ~46%
The negative marginThe not
The animationThe not
The responsiveThe no media query
The dark modeThe no
The hoverThe 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 elementThe purpose
<Tailwind>The wrap
<Head />The required
css.inlineThe inline
css.safeThe safe names
@maizzle/tailwindcssThe config
The mso-*The Outlook
The gmail:The variant

The React Email

The elementThe purpose
<Tailwind>The wrap
pixelBasedPresetThe rem to px
The classNameThe inlined
The configThe custom theme
The proseThe not supported
The contextThe provider higher

The Support Matrix

The featureThe support
The inline CSSThe universal
The border-radiusThe modern
The box-shadowThe no Outlook
The flexboxThe ~60%
The gridThe ~55%
The transformThe ~46%
The responsiveThe no
The dark modeThe no

The Units

The unitThe support
The pxThe universal
The remThe limited
The emThe limited
The %The good

The Client Variants

The variantThe 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 pitfallThe reasonThe fix
The styles not appliedThe Gmail strips the styleUse the css.inline
The class ignoredThe : strippedUse the css.safe
The rem ignoredThe client does not supportUse the pixelBasedPreset
The layout brokenThe flexboxUse the table
The Outlook brokenThe modern CSSUse the mso-*
The variant not appliedThe nested at-ruleUse the separate block
The context failsThe React limitationMove 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 itemThe value
The MaizzleThe build-time engine
The React EmailThe render-time engine
The <Tailwind>The wrap
The pixelBasedPresetThe rem to px
The css.inlineThe inline
The css.safeThe safe names
The mso-*The Outlook
The client variantThe targeting
The inline styleThe deliverable
The table layoutThe 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 style attribute is the deliverable.
  • The Maizzle uses the transformers. The css.inline inlines the CSS, the css.safe rewrites the class names, and the @maizzle/tailwindcss provides the email-friendly config .
  • The React Email uses the <Tailwind> component. The className values are looked up and inlined at the render. The pixelBasedPreset converts the rem to the pixel .
  • The special characters in the class names are the problem. The Gmail strips the : and the /. The css.safe rewrites the sm:block to the sm-block .
  • The rem is not the email-friendly. The email clients do not support the rem consistently. The pixelBasedPreset changes the base to the 16px .
  • 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, the Row, and the Column provide the table-based layout .
  • The MSO utilities target the Outlook. The mso-* properties work only in the Outlook. The @maizzle/tailwindcss exposes them as the utilities .
  • The client variants target the specific clients. The gmail:, the yahoo:, and the outlook-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.


Was this helpful?


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!