Full documentation: https://email.2plot.dev — the dedicated dash-email documentation site, with the complete API reference and deeper examples. This page is the quick-start overview.
Installation
pip install dash-email
Introduction
dash-email bridges Python-first development with the component patterns pioneered by React Email. Build email templates with familiar Dash syntax, preview them live inside your app, and export inline-styled, table-based HTML that renders correctly in Gmail, Outlook, Apple Mail, and every other major client.
- 15 email-safe components — structure, layout, typography, buttons, images, fonts.
- Email-client compatible by construction — rows and columns render as real HTML tables; all styling is inlined.
- First-class Dash citizens — every component takes an
idand works with callbacks like any other Dash component. - Send & schedule — integrated Resend support for single sends, batches up to 100 recipients, and scheduling.
import dash_email as de
Status: early release (0.0.x). The component API is stable; the AI builder and sending utilities are actively evolving.
Quick Start
A complete welcome email: Email → EmailBody → EmailContainer → EmailSection, with a heading, paragraph, and a bulletproof CTA button. What you see below is the live component tree rendered in the browser — the exact same tree converts to email-safe HTML at send time.
# File: docs/dash_email/quick_start.py
import dash_email as de
component = de.Email(
lang="en",
children=[
de.EmailBody(
style={"backgroundColor": "#f6f9fc", "padding": "40px 0",
"borderRadius": "12px"},
children=[
de.EmailContainer([
de.EmailSection(
style={
"backgroundColor": "#ffffff",
"borderRadius": "8px",
"padding": "40px",
},
children=[
de.EmailHeading(
"Welcome to 2plot.dev!",
as_="h1",
style={"color": "#1a1a1a", "marginBottom": "16px"},
),
de.EmailText(
"Thanks for creating an account. You now have access to "
"every live component example, full API references, and "
"the AI documentation assistant.",
style={"color": "#666666", "lineHeight": "1.6"},
),
de.EmailButton(
"Explore the docs",
href="https://2plot.dev",
style={
"backgroundColor": "#12B886",
"color": "#ffffff",
"padding": "12px 24px",
"borderRadius": "4px",
"fontWeight": "bold",
},
),
],
)
])
],
)
],
)
Rows & Columns
Email clients are not browsers — floats, flexbox, and grid are unreliable or stripped entirely. EmailRow / EmailColumn are the layout primitives that survive every client: rows render as HTML tables and columns as table cells. Set widths with percentage styles on each column.
# File: docs/dash_email/rows_columns.py
import dash_email as de
# Emails are always light-themed artifacts: every text element carries an
# explicit color so the preview renders identically on the docs site's
# light AND dark modes (unstyled text would inherit the page theme color).
CELL = {"padding": "12px", "verticalAlign": "top"}
HEADING = {"color": "#1a1a1a"}
BODY_TEXT = {"color": "#666666", "lineHeight": "1.6"}
component = de.Email([
de.EmailBody(
style={
"backgroundColor": "#f6f9fc",
"padding": "32px 0",
"borderRadius": "12px",
},
children=[
de.EmailContainer([
de.EmailSection(
style={
"backgroundColor": "#ffffff",
"borderRadius": "8px",
"padding": "24px",
},
children=[
de.EmailHeading("Two columns", as_="h3", style=HEADING),
de.EmailRow([
de.EmailColumn(
style={"width": "50%", **CELL},
children=[
de.EmailText(
"Left column — rows and columns render "
"as real HTML tables, the only layout "
"primitive every email client supports.",
style=BODY_TEXT,
)
],
),
de.EmailColumn(
style={"width": "50%", **CELL},
children=[
de.EmailText(
"Right column — set widths with "
"percentage styles on each column.",
style=BODY_TEXT,
)
],
),
]),
de.EmailDivider(style={"margin": "16px 0"}),
de.EmailHeading("70 / 30 split", as_="h3", style=HEADING),
de.EmailRow([
de.EmailColumn(
style={"width": "70%", **CELL},
children=[
de.EmailText("dash-email Pro license",
style=BODY_TEXT)
],
),
de.EmailColumn(
style={"width": "30%", "textAlign": "right", **CELL},
children=[
de.EmailText("$99.00", style=BODY_TEXT)
],
),
]),
],
)
])
],
)
])
Buttons & Links
EmailButton is a "bulletproof" call-to-action — a styled anchor that keeps its padding and background across clients. EmailLink is its inline counterpart for links inside running text.
# File: docs/dash_email/button_cta.py
import dash_email as de
component = de.Email([
de.EmailBody(
style={"backgroundColor": "#f6f9fc", "padding": "32px 0",
"borderRadius": "12px"},
children=[
de.EmailContainer([
de.EmailSection(
style={
"backgroundColor": "#ffffff",
"borderRadius": "8px",
"padding": "32px",
"textAlign": "center",
},
children=[
de.EmailHeading(
"New release: dash-leaflet2",
as_="h2",
style={"color": "#1a1a1a"},
),
de.EmailText(
"Leaflet 2-native maps for Dash — 26 components, no "
"react-leaflet dependency. Read the announcement, or "
"jump straight into the interactive docs.",
style={"color": "#666666", "lineHeight": "1.6"},
),
de.EmailButton(
"Read the docs",
href="https://2plot.dev/pip/dash_leaflet2",
style={
"backgroundColor": "#228be6",
"color": "#ffffff",
"padding": "12px 28px",
"borderRadius": "6px",
"fontWeight": "bold",
"marginRight": "8px",
},
),
de.EmailText(
[
"Prefer video? Watch the walkthrough on ",
de.EmailLink(
"YouTube @2plotai",
href="https://www.youtube.com/@2plotai",
style={"color": "#12B886"},
),
".",
],
style={"color": "#999999", "fontSize": "13px"},
),
],
)
])
],
)
])
The styling boundary
Email clients strip <style> tags and ignore most modern CSS, so every dash-email component takes a style dict of camelCase CSS that renders inline on the element.
Rules of thumb:
- Keep content at 600px or less —
EmailContainerenforces this for you. - Multi-column layout goes through
EmailRow/EmailColumn— never flexbox. - Prefer web-safe fonts, or load one via
EmailFontwith afallbackFontFamily. - Always set explicit
width/height+altonEmailImage.
de.EmailRow([
de.EmailColumn(style={"width": "70%"}, children=[de.EmailText("Product")]),
de.EmailColumn(style={"width": "30%", "textAlign": "right"}, children=[de.EmailText("$99.00")]),
])
Sending with Resend
Templates built with these components convert to email-safe HTML and send through the Resend API — single sends, batches up to 100 recipients, and scheduled delivery (up to 30 days ahead). Set RESEND_API_KEY in your environment:
from utils.email_sender import send_email, component_to_html
html = component_to_html(my_email_component)
result = send_email(
to_email="user@example.com",
subject="Welcome!",
html_content=html,
from_email="hello@yourdomain.com",
scheduled_at="in 1 hour", # optional — ISO 8601 or natural language
)
This documentation site uses exactly this pipeline for its own transactional and announcement emails.
Components
| Component | Category | What it is |
|---|---|---|
Email | Structure | Root wrapper for the email template |
EmailHead | Structure | Metadata container (font imports, etc.) |
EmailPreview | Structure | Inbox preview text — visible next to the subject, hidden in body |
EmailBody | Structure | Main content wrapper |
EmailContainer | Layout | Centered container at the 600px email standard |
EmailSection | Layout | Groups related content with its own background/padding |
EmailRow | Layout | Horizontal row — renders as an HTML <table> |
EmailColumn | Layout | Column within a row — renders as a <td> |
EmailHeading | Content | Headings h1–h6 via the as_ prop |
EmailText | Content | Paragraph text |
EmailButton | Content | Bulletproof call-to-action button (styled anchor) |
EmailLink | Content | Inline hyperlink |
EmailImage | Media | Image with explicit dimensions |
EmailDivider | Media | Horizontal rule separator |
EmailFont | Media | Web font loading with graceful fallback |
Component Properties
| Property | Type | Default | Description | |
|---|---|---|---|---|
| id | string | — | Dash callback identity — available on every component | |
| style | dict | — | camelCase CSS, rendered inline for email-client safety | |
| children | node | — | Child components / text | |
| as_ | string | "h1" | EmailHeading level: "h1"–"h6" (Python-safe alias for as) | |
| href | string | — | EmailButton / EmailLink target URL | |
| src | string | — | EmailImage source URL | |
| alt | string | — | EmailImage alt text | |
| width / height | string \ | number | — | EmailImage explicit dimensions |
| lang | string | "en" | Email document language | |
| fontFamily | string | — | EmailFont font family name | |
| fallbackFontFamily | string | — | EmailFont web-safe fallback | |
| webFont | object | — | EmailFont web font source configuration |