Skip to main content

Transform HTML with Tailwind CSS classes into email-client-compatible HTML with inline styles

Project description

tailwind-email

Transform HTML with Tailwind CSS classes into email-client-compatible HTML with inline styles.

Python 3.9+ License: MIT

Overview

tailwind-email is a Python library that converts Tailwind CSS utility classes in your HTML to inline styles that work across all major email clients. It's designed to help developers build beautiful email templates using familiar Tailwind CSS syntax while ensuring maximum compatibility.

Key Features

  • Full Tailwind v4 Support: Supports the complete Tailwind CSS v4 color palette and utility classes
  • Email-Safe CSS: Automatically converts modern CSS to email-compatible inline styles
  • Smart Filtering: Removes unsupported classes (flexbox, grid, transforms) that don't work in emails
  • MSO Properties: Includes Microsoft Office-specific properties for Outlook compatibility
  • VML Fallbacks: Generates VML markup for border-radius support in Outlook
  • Unit Conversion: Converts rem/em units to pixels for consistent rendering
  • Color Conversion: Converts all color formats (including OKLCH) to hex values
  • Zero JS Dependencies: Pure Python implementation with no Node.js required

Installation

pip install tailwind-email

Or install from source:

git clone https://github.com/tailwind-email/tailwind-email.git
cd tailwind-email
pip install -e .

Quick Start

Basic Usage

from tailwind_email import convert

html_input = """
<div class="bg-blue-500 p-4 text-white rounded-lg">
    <h1 class="text-2xl font-bold">Hello World</h1>
    <p class="mt-2 text-sm">This is an email-safe component.</p>
</div>
"""

html_output = convert(html_input)
print(html_output)

Output

<div style="background-color: #3b82f6; padding: 16px; color: #ffffff; border-radius: 8px;">
    <h1 style="font-size: 24px; line-height: 32px; mso-line-height-rule: exactly; font-weight: 700;">Hello World</h1>
    <p style="margin-top: 8px; font-size: 14px; line-height: 20px; mso-line-height-rule: exactly;">This is an email-safe component.</p>
</div>

Using the Converter Class

For multiple conversions or custom options, use the TailwindEmailConverter class:

from tailwind_email import TailwindEmailConverter
from tailwind_email.converter import ConversionOptions

# Create converter with custom options
options = ConversionOptions(
    base_font_size=16,
    include_mso_properties=True,
    include_vml_fallbacks=True,
    preserve_classes=False,
)
converter = TailwindEmailConverter(options)

# Convert multiple templates
html1 = converter.convert('<div class="p-4">First</div>')
html2 = converter.convert('<div class="m-4">Second</div>')

Configuration Options

Option Type Default Description
base_font_size int 16 Base font size in pixels for rem/em conversion
include_mso_properties bool True Include Microsoft Office properties for Outlook
include_vml_fallbacks bool True Generate VML fallbacks for border-radius in Outlook
preserve_classes bool False Keep original Tailwind classes in output
preserve_unsupported_classes bool True Keep non-Tailwind classes (e.g., custom classes)
compatibility str "strict" Compatibility mode: "strict" or "modern"

Example with Options

from tailwind_email import convert

# Disable MSO properties for non-Outlook targeting
html = '<div class="text-lg leading-relaxed">Content</div>'
output = convert(html, {
    "include_mso_properties": False,
    "base_font_size": 18,
})

Supported Tailwind Classes

Fully Supported (95%+ Email Client Compatibility)

Spacing

Class Pattern CSS Property Example
p-{size} padding p-4padding: 16px
px-{size} padding-left, padding-right px-4 → 16px horizontal
py-{size} padding-top, padding-bottom py-4 → 16px vertical
pt-{size}, pr-{size}, pb-{size}, pl-{size} Individual padding pt-2padding-top: 8px
m-{size} margin m-4margin: 16px
mx-{size}, my-{size} Horizontal/vertical margin mx-auto → auto centering
mt-{size}, mr-{size}, mb-{size}, ml-{size} Individual margin mt-2margin-top: 8px

Sizing

Class Pattern CSS Property Example
w-{size} width w-64width: 256px
w-{fraction} width (percentage) w-1/2width: 50%
w-full width: 100% Full width
h-{size} height h-32height: 128px
max-w-{size} max-width max-w-lgmax-width: 512px
min-w-{size} min-width min-w-0min-width: 0px
size-{size} width + height size-16 → 64px both

Colors

Class Pattern CSS Property Example
bg-{color}-{shade} background-color bg-blue-500#3b82f6
text-{color}-{shade} color text-gray-600#4b5563
border-{color}-{shade} border-color border-red-500#ef4444
bg-white, bg-black Special colors #ffffff, #000000
bg-transparent transparent Transparent background
text-current currentColor Inherit color
Color Opacity
# Color with opacity modifier
'<div class="bg-blue-500/50">...</div>'
# → background-color: rgba(59, 130, 246, 0.5)

Typography

Class Pattern CSS Property Example
text-xs to text-9xl font-size, line-height text-lg → 18px/28px
font-thin to font-black font-weight font-bold → 700
text-left, text-center, text-right text-align Alignment
leading-{value} line-height leading-relaxed → 1.625
tracking-{value} letter-spacing tracking-wide → 0.4px
underline, line-through text-decoration Text decoration
uppercase, lowercase, capitalize text-transform Text case
italic, not-italic font-style Italics
font-sans, font-serif, font-mono font-family Font stack

Borders

Class Pattern CSS Property Example
border, border-{width} border-width border-2 → 2px
border-{side}, border-{side}-{width} Side borders border-t-2 → top 2px
border-solid, border-dashed, border-dotted border-style Style
rounded-{size} border-radius rounded-lg → 8px
rounded-{corner}-{size} Corner radius rounded-tl-lg → top-left 8px

Supported with Limitations (60-80% Compatibility)

Category Classes Notes
Border Radius rounded-* VML fallback for Outlook
Box Shadow shadow-* Not supported in Outlook desktop
Opacity opacity-* Limited support in some clients
Overflow overflow-* May not work in all clients

Not Supported (Filtered Out)

These classes are automatically removed as they have poor email client support:

Category Classes Reason
Flexbox flex, flex-row, flex-col, justify-*, items-*, gap-* ~60% support
Grid grid, grid-cols-*, col-span-*, gap-* ~55% support
Transform rotate-*, scale-*, translate-*, skew-* ~46% support
Negative Margin -m-*, -mt-*, -mx-*, etc. Not supported
Animations animate-*, transition-*, duration-* Not supported
Responsive sm:*, md:*, lg:*, xl:* No media query support
Dark Mode dark:* No color scheme support
Hover/Focus hover:*, focus:*, active:* No pseudo-class support

Email Client Compatibility

Based on Can I Email data:

Client Compatibility Notes
Apple Mail (macOS/iOS) Excellent Full CSS support
Gmail (Web) Good Some limitations on embedded styles
Gmail (App) Good Similar to web
Outlook 365 (Web) Good Modern CSS support
Outlook (Desktop) Moderate MSO properties and VML needed
Outlook (Mobile) Good Better than desktop
Yahoo Mail Good Generally good support
Thunderbird Excellent Full CSS support
Samsung Email Good Generally good support

Advanced Usage

Arbitrary Values

Use Tailwind's arbitrary value syntax for custom values:

# Arbitrary pixel values
'<div class="w-[200px] h-[100px]">...</div>'
# → width: 200px; height: 100px

# Arbitrary rem values (converted to px)
'<div class="p-[2rem]">...</div>'
# → padding: 32px (at 16px base)

# Arbitrary properties
'<div class="[line-height:1.8]">...</div>'
# → line-height: 1.8

Preserving Custom Classes

If you have custom CSS classes you want to keep:

html = '<div class="my-custom-class p-4 bg-blue-500">Content</div>'

# Default: preserves non-Tailwind classes
output = convert(html)
# → class="my-custom-class" style="padding: 16px; background-color: #3b82f6;"

# Remove all classes
output = convert(html, {"preserve_unsupported_classes": False})
# → style="padding: 16px; background-color: #3b82f6;"

Handling Existing Inline Styles

Existing inline styles are preserved and merged with converted styles:

html = '<div class="p-4" style="color: red;">Content</div>'
output = convert(html)
# → style="color: red; padding: 16px;"

Email Template Patterns

Centered Container

<table class="w-full">
    <tr>
        <td>
            <table class="max-w-xl mx-auto bg-white">
                <tr>
                    <td class="p-8">
                        <!-- Content -->
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>

Email-Safe Button

<table>
    <tr>
        <td class="bg-blue-600 rounded-lg">
            <a href="#" class="block py-3 px-6 text-white font-bold text-center">
                Click Here
            </a>
        </td>
    </tr>
</table>

Two-Column Layout

<table class="w-full">
    <tr>
        <td class="w-1/2 p-4 align-top">
            <!-- Column 1 -->
        </td>
        <td class="w-1/2 p-4 align-top">
            <!-- Column 2 -->
        </td>
    </tr>
</table>

API Reference

convert(html: str, options: dict = None) -> str

Converts HTML with Tailwind classes to email-compatible HTML.

Parameters:

  • html (str): Input HTML string with Tailwind CSS classes
  • options (dict, optional): Configuration options

Returns:

  • str: Converted HTML with inline styles

TailwindEmailConverter

Class for creating reusable converter instances.

Methods:

  • __init__(options: ConversionOptions = None): Create converter with options
  • convert(html: str) -> str: Convert HTML string

ConversionOptions

Dataclass for configuration options.

Attributes:

  • base_font_size: int = 16
  • include_mso_properties: bool = True
  • include_vml_fallbacks: bool = True
  • preserve_classes: bool = False
  • preserve_unsupported_classes: bool = True
  • compatibility: str = "strict"

Development

Setup

# Clone the repository
git clone https://github.com/tailwind-email/tailwind-email.git
cd tailwind-email

# Install with development dependencies
pip install -e ".[dev]"

# Or use requirements files
pip install -r requirements-dev.txt

Running Tests

# Run all tests
pytest

# Run with coverage
pytest --cov=tailwind_email --cov-report=html

# Run specific test file
pytest tests/test_converter.py

# Run tests matching pattern
pytest -k "test_padding"

# Run with verbose output
pytest -v

Code Quality

# Lint with ruff
ruff check src tests

# Format with ruff
ruff format src tests

# Type check with mypy
mypy src

Comparison with Alternatives

Feature tailwind-email maizzle mjml
Language Python Node.js Node.js
Tailwind Support v4 v3 Limited
Template Syntax HTML Blade MJML
Inlining Built-in Built-in Built-in
Dependencies 2 Many Many
Learning Curve Low Medium Medium

Contributing

Contributions are welcome! Please read our contributing guidelines and submit pull requests.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE for details.

Acknowledgments

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tailwind_email-0.1.0.tar.gz (55.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tailwind_email-0.1.0-py3-none-any.whl (32.2 kB view details)

Uploaded Python 3

File details

Details for the file tailwind_email-0.1.0.tar.gz.

File metadata

  • Download URL: tailwind_email-0.1.0.tar.gz
  • Upload date:
  • Size: 55.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for tailwind_email-0.1.0.tar.gz
Algorithm Hash digest
SHA256 fba412e866471f8b117242009276ab6cdf67ecc053cb28857c70cabc402524e4
MD5 6525c7e5b6da187abf4fac7daea7cbef
BLAKE2b-256 a96a6bb9c987e03f86c13913cef82e8e3c5a72a560e2fa214860d8bffa46824f

See more details on using hashes here.

Provenance

The following attestation bundles were made for tailwind_email-0.1.0.tar.gz:

Publisher: publish.yml on SaltySkyPie/tailwind-email

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tailwind_email-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: tailwind_email-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 32.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for tailwind_email-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3e84275cf2c1620f921bf6c11ace103c624ddb18039e23b55fad3c4753cb7b93
MD5 d3f82af4d6a5be4d7a8d718647b7bdeb
BLAKE2b-256 e7a12dd8cf2aac2a1a4d8d22bdfbd83f5fe22e66a95a4b0bd8bbcddc1ef482ea

See more details on using hashes here.

Provenance

The following attestation bundles were made for tailwind_email-0.1.0-py3-none-any.whl:

Publisher: publish.yml on SaltySkyPie/tailwind-email

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page