.. toc::
.. llms_copy::Dash Email
๐ Full documentation: [dash-email-svmp.onrender.com](https://dash-email-svmp.onrender.com) โ every component with isolated live examples, props tables, and the AI email builder. This page is the quick-start overview.
Installation
[Visit GitHub Repo](https://github.com/pip-install-python/dash-email) ยท [PyPI](https://pypi.org/project/dash-email/)
``bash pip install dash-email ``
Introduction
dash-email bridges Python-first development with the component patterns pioneered by [React Email](https://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](https://resend.com) support for single sends, batches up to 100 recipients, and scheduling.
``python 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.
.. exec::docs.dash_email.quick_start :code: false
```python
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.
.. exec::docs.dash_email.rows_columns :code: false
```python
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.
.. exec::docs.dash_email.button_cta :code: false
```python
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.
``python 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](https://resend.com) API โ single sends, batches up to 100 recipients, and scheduled delivery (up to 30 days ahead). Set RESEND_API_KEY in your environment:
```python 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 |
Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs:
- /pip/dash_email/llms.txt โ LLM-friendly documentation
- /sitemap.xml
- /robots.txt