Sep 17, 2026 ยท 8 min read

How to Inline Tailwind CSS for HTML Emails

Inline Tailwind CSS for HTML email by generating used utilities, resolving modern values, preserving conditional rules, and merging declarations safely.

How to Inline Tailwind CSS for HTML Emails

To inline Tailwind CSS for HTML email, generate the utility rules used by the rendered template, resolve them to email-friendly values, apply unconditional declarations to matching elements, and preserve responsive or dark-mode rules in a small embedded stylesheet.

Do not inline your full application CSS. It creates unnecessary markup and can push long messages toward Gmail clipping.

Source and desired output

Source:

<p class="mt-4 text-base leading-7 text-slate-600">
  Your report is ready.
</p>

Output:

<p style="margin-top:16px;font-size:16px;line-height:28px;color:#475569">
  Your report is ready.
</p>

The output no longer depends on the utility classes for its base appearance.

Step 1: render the complete template

Resolve Blade, JSX, Vue, or other template syntax before extracting classes. Conditional sections and component variants must be present in the rendered fixture for their utilities to be detected.

Use realistic data, including long and empty states.

Step 2: collect complete utility tokens

Tailwind scans text for complete class names. Avoid partial construction:

// Avoid
`bg-${status}-600`

// Prefer
const statuses = {
  success: 'bg-emerald-600 text-white',
  failure: 'bg-red-600 text-white',
};

Extract candidates from class or className attributes, or let your Tailwind integration scan the template source. Generate CSS only for those tokens.

Step 3: compile Tailwind CSS

Tailwind CSS 4 uses CSS-first configuration and may emit values optimized for modern browsers.

An email pipeline should convert or lower:

  • CSS variables to concrete values;
  • oklch() colors to safer formats;
  • logical padding and margin properties to physical sides;
  • calculated spacing where a concrete pixel value is safer;
  • nesting into ordinary selectors; and
  • unsupported declarations out of the final map.

This is where a dedicated email configuration or compiler adds value beyond the normal Tailwind build.

Step 4: separate conditional rules

Do not treat all generated rules as candidates for inlining.

Keep these embedded:

  • @media breakpoint rules;
  • prefers-color-scheme dark-mode rules;
  • hover and focus selectors;
  • client-targeting selectors; and
  • any rule whose meaning depends on context.

The class names used by those rules must remain on their elements.

Step 5: create a class-to-style map

For simple utility selectors, build a map:

mt-4        โ†’ margin-top:16px
text-base   โ†’ font-size:16px;line-height:24px
leading-7   โ†’ line-height:28px
text-slate-600 โ†’ color:#475569

Apply Tailwind's generated cascade order. Class attribute order does not define precedence.

Utilities with compound selectors, child relationships, or pseudo-classes cannot be reduced to a simple unconditional map.

Step 6: merge with existing styles

Existing inline declarations may be intentional fallbacks:

<td class="bg-blue-600" style="mso-padding-alt:0">

Merge instead of replacing:

<td style="background-color:#155dfc;mso-padding-alt:0">

Handle specificity, !important, shorthand properties, and duplicate declarations deterministically. Add focused fixtures for every conflict rule.

Step 7: transform structure

Inlining alone does not make Flexbox or Grid compatible.

Before final serialization:

  • convert key rows and columns to presentation tables;
  • turn filled links into table-backed buttons;
  • convert spacers and dividers to stable structures;
  • add explicit image and table dimensions; and
  • add align, valign, or bgcolor where useful.

See how to convert Tailwind to email-safe HTML for the broader pipeline.

Step 8: remove unused classes

Remove a class when:

  • all of its useful declarations are inline; and
  • no retained conditional selector refers to it.

Keep a responsive class when a media query still targets it. Renaming escaped Tailwind selectors to email-friendlier names may be necessary, but the HTML and CSS must change together.

Step 9: wrap and sanitize

Create a complete document with language, metadata, preheader, body defaults, and a meaningful title.

Remove:

  • scripts;
  • forms and interactive inputs;
  • unsupported embedded content;
  • editor-only data attributes;
  • unused CSS;
  • temporary comments; and
  • unresolved template tokens.

Preserve deliberate Outlook conditional comments.

Responsive example

Source:

<div class="px-5 py-8 sm:px-10 sm:py-12">...</div>

Output strategy:

  • inline px-5 py-8;
  • keep a compact media query for the sm: overrides;
  • retain or normalize the responsive class selector; and
  • ensure the base layout is complete without the query.

Never inline the sm: value unconditionally.

Measure the generated HTML

Inlining repeats styles. Track:

  • total HTML bytes;
  • style attribute count;
  • retained CSS bytes;
  • repeated declaration groups;
  • unused class count; and
  • Gmail clipping headroom.

Minify only after compatibility validation, and protect Outlook comments during minification.

Test the pipeline

Create fixtures for:

  • colors and CSS variables;
  • spacing and logical properties;
  • font-size plus line-height precedence;
  • arbitrary values;
  • existing inline styles;
  • !important;
  • responsive variants;
  • dark mode;
  • filled buttons; and
  • grid or flex transformations.

Then run real HTML email tests.

Common failures

A class has no inline style

It was not scanned, generated, parsed, or supported. Trace each stage instead of patching the export.

Responsive behavior disappeared

The pipeline removed the retained media query or stripped the class it targets.

Colors are invalid in clients

Modern color functions or unresolved variables reached the output. Lower them before inlining.

HTML size exploded

The build included unused utilities or repeated a large declaration group on too many elements.

Outlook still breaks

The issue is structural, not merely style placement. Add a table or component fallback.

Frequently asked questions

Can a generic CSS inliner handle Tailwind?

It can inline simple compiled selectors, but a complete Tailwind email pipeline also needs value lowering, conditional-rule preservation, layout transformation, and cleanup.

Should I inline hover styles?

No. Hover is conditional. Keep it embedded as progressive enhancement.

Can I remove every class after inlining?

Only if no retained selector uses it. Responsive and dark-mode rules often require classes.

Should the source use inline CSS instead?

You can, but utility source is easier to standardize and reuse. The build should make output placement automatic.

Make inlining deterministic

The most important property of a Tailwind email inliner is repeatability.

The same template and data should produce the same declarations, structure, and retained CSS. When the pipeline is deterministic and covered by fixtures, teams can improve source components without hand-editing generated email HTML.

Share with friends

Ready to ship email-safe HTML?

Start with Tailwind markup, compile to clean HTML, and always preview or send a test before campaigns.