# Email.md Email.md is a markdown-to-email library that converts markdown into responsive, email-safe HTML that renders perfectly across Gmail, Outlook, Apple Mail, Yahoo, and every other email client. Built on MJML under the hood, it eliminates the need to write complex HTML tables and inline styles while supporting standard markdown syntax plus extensions like buttons, directives, and theming. The library provides a simple `render()` function that accepts markdown with optional YAML frontmatter and returns complete HTML documents ready for sending. It includes built-in themes (light and dark), extensive customization options, and generates both HTML and plain text versions for proper MIME multipart emails. ## Installation Install Email.md via npm for use in your Node.js or browser projects. ```bash npm install emailmd ``` ## render(markdown, options?) The main function that converts markdown into email-safe HTML. Returns an object containing the HTML document, plain text version, and extracted frontmatter metadata. ```typescript import { render } from "emailmd"; // Basic usage const { html, text, meta } = render(` # Welcome to Acme! Thanks for signing up. We're excited to have you on board. [Get Started](https://example.com/start){button} `); // html → Complete email-safe HTML document (DOCTYPE, html, head, body) // text → Plain text version for text/plain MIME part // meta → Extracted frontmatter metadata // With theme customization const result = render(` # Sale Alert Everything is 50% off this weekend! [Shop Now](https://example.com/sale){button color="#dc2626"} `, { theme: { brandColor: '#e11d48', buttonColor: '#e11d48', fontFamily: 'Georgia, serif', } }); console.log(result.html); // Complete HTML email ready to send ``` ## RenderOptions Configuration options passed to the render function for theme customization and wrapper selection. ```typescript interface RenderOptions { theme?: Partial; // Override default theme values wrapper?: 'default' | WrapperFn; // Custom email wrapper function } // Example with full options import { render, darkTheme } from "emailmd"; const { html } = render(markdown, { theme: { ...darkTheme, brandColor: '#e11d48', contentWidth: '640px', }, wrapper: 'default' }); ``` ## Theme The Theme interface defines all customizable visual properties for emails including colors, typography, and layout. ```typescript interface Theme { brandColor: string; // Links, highlights, accents (#18181b) headingColor: string; // Heading text (#09090b) bodyColor: string; // Body text (#71717a) backgroundColor: string; // Outer background (#fafafa) contentColor: string; // Content area background (#ffffff) cardColor: string; // Callout/code block background (#f4f4f5) buttonColor: string; // Primary button background (#18181b) buttonTextColor: string; // Button text (#fafafa) secondaryColor: string; // Secondary button border (#18181b) secondaryTextColor: string; // Secondary button text (#18181b) successColor: string; // Success button background (#16a34a) successTextColor: string; // Success button text (#ffffff) dangerColor: string; // Danger button background (#dc2626) dangerTextColor: string; // Danger button text (#ffffff) warningColor: string; // Warning button background (#d97706) warningTextColor: string; // Warning button text (#ffffff) fontFamily: string; // Font stack fontSize: string; // Base font size (16px) lineHeight: string; // Base line height (1.6) contentWidth: string; // Email width (600px) } // Using theme in render import { render, darkTheme, mergeTheme } from "emailmd"; // Use built-in dark theme const { html: darkHtml } = render(markdown, { theme: darkTheme }); // Override specific values on dark theme const { html: customDark } = render(markdown, { theme: { ...darkTheme, brandColor: "#e11d48" } }); // Custom theme with light base const { html: branded } = render(markdown, { theme: { brandColor: '#2563eb', buttonColor: '#2563eb', headingColor: '#1e3a8a', } }); ``` ## Frontmatter YAML frontmatter at the top of markdown files allows per-email theme overrides and metadata configuration using snake_case keys. ```markdown --- preheader: "Don't miss our biggest sale of the year" theme: dark brand_color: "#e11d48" button_color: "#059669" subject: "Summer Sale - 50% Off Everything" campaign_id: "summer-2024" --- # Summer Sale Everything is 50% off this weekend only! [Shop Now](https://example.com/sale){button} ::: footer **Acme Corp** · [Unsubscribe](https://example.com/unsub) ::: ``` ```typescript import { render } from "emailmd"; const markdown = ` --- preheader: "Your order has shipped" subject: "Order #12345 Shipped" tracking_number: "1Z999AA10123456784" --- # Your Order Has Shipped! Track your package using the button below. [Track Package](https://example.com/track){button} `; const { html, text, meta } = render(markdown); console.log(meta.preheader); // "Your order has shipped" console.log(meta.subject); // "Order #12345 Shipped" console.log(meta.tracking_number); // "1Z999AA10123456784" ``` ## Buttons Call-to-action buttons using the `{button}` attribute syntax with support for variants, colors, and side-by-side layouts. ```markdown [Get Started](https://example.com){button} [Learn More](https://example.com){button.secondary} [Confirm Account](https://example.com/confirm){button.success} [Delete Account](https://example.com/delete){button.danger} [Review Changes](https://example.com/review){button.warning} [Shop Sale](https://example.com/sale){button color="#dc2626"} [Subscribe Now](https://example.com/subscribe){button width="full"} [Accept](https://example.com/accept){button} [Decline](https://example.com/decline){button.secondary} [Reset Password](https://example.com/reset){button fallback} [Réinitialiser](https://example.com/reset){button fallback="Si vous avez des difficultés, copiez cette URL :"} ``` ## Images Responsive, centered email images with attributes for width, alignment, and border radius. ```markdown ![Hero banner](https://example.com/hero.jpg) ![Product](https://example.com/product.jpg){width="400"} ![Photo](https://example.com/photo.jpg){align="left"} ![Avatar](https://example.com/avatar.jpg){width="80" border-radius="50%"} [![Shop banner](https://example.com/banner.jpg)](https://example.com/shop) Feature one with icon ![check](https://example.com/check.png){width="20" height="20"} included. ![Plant](https://example.com/plant.jpg){width="80" float="left"} **Monstera Deliciosa** Easy care · Bright indirect light · $42.00 ``` ## Tables Standard GitHub Flavored Markdown tables rendered as styled, email-safe HTML with automatic theme styling. ```markdown | Name | Role | Status | | ----- | ---------- | ------ | | Alice | Engineer | Active | | Bob | Designer | Active | | Carol | Manager | Away | | Item | Qty | Price | | :----------------------- | ----: | -------: | | Monstera Deliciosa, 6" | 1 | $42.00 | | Ceramic Pot, White | 1 | $18.00 | | **Total** | | **$60.00** | ``` ## Header Directive Content rendered above the main body area, typically used for logos or brand images. ```markdown ::: header ![Logo](https://example.com/logo.png){width="150"} ::: ::: header left ![Logo](https://example.com/logo.png){width="150"} ::: ::: header color=#1e40af **Acme Corp** ::: ``` ## Hero Directive Full-width section with a background image and overlaid content for impactful banner headers. ```markdown ::: hero https://example.com/hero.jpg # Welcome aboard Get started with your new account today. ::: ::: hero https://example.com/sale-bg.jpg # Summer Sale Up to 50% off everything this weekend. [Shop Now](https://example.com/sale){button color="#e11d48"} ::: ``` ## Callout Directive Highlighted tip or note block with customizable alignment, padding, and colors. ```markdown ::: callout **Pro tip:** You can customize your dashboard in Settings. ::: ::: callout center **ABC-123** Your confirmation code. ::: ::: callout compact Short note. ::: ::: callout color=#1e40af bg=#eff6ff **Note:** Your account is pending review. ::: ::: callout center compact bg=#eff6ff **ABC-123** ::: ``` ## Highlight Directive Emphasized content block with brand color accent for promotions and key messages. ```markdown ::: highlight Limited time: first 100 signups get 50% off. ::: ::: highlight center **50% OFF** — This weekend only! ::: ::: highlight compact color=#ffffff bg=#dc2626 **URGENT:** Action required. ::: ``` ## Footer Directive Footer section with smaller, muted text for legal information and unsubscribe links. ```markdown ::: footer **Acme Corp** · [Unsubscribe](https://example.com/unsub) · [Preferences](https://example.com/prefs) ::: ::: footer left © 2024 Acme Corp · All rights reserved. ::: ::: footer color=#9ca3af Legal text here. ::: ``` ## Centered Directive Center-aligned text block for sign-offs and short messages. ```markdown ::: centered Thanks for reading. The Acme Team ::: ::: centered color=#71717a Have questions? Reply to this email. ::: ``` ## Markdown Text Formatting Standard and extended markdown syntax for inline text formatting. ```markdown **Bold text** and *italic text* and ***bold italic***. ~~Strikethrough~~ for deleted content. `inline code` renders with a subtle background. # Heading 1 ## Heading 2 ### Heading 3 [Visit our site](https://example.com) Autolinks work too: https://example.com - First item - Second item - Third item 1. Step one 2. Step two 3. Step three - [x] Design approved - [x] Content written - [ ] Ready to send > "The best way to predict the future is to create it." > — Peter Drucker Don't miss our ==biggest sale of the year==! H~2~O is water. E = mc^2^ is famous. :wave: Welcome! :rocket: Let's go! :heart: ``` ## Custom Wrappers Replace the default email structure with a custom wrapper function for full control over MJML output. ```typescript import { render, buildHead, segmentsToMjml } from 'emailmd'; import type { WrapperFn, Segment, Theme } from 'emailmd'; // Custom wrapper with edge-to-edge background const edgeToEdgeWrapper: WrapperFn = (segments, theme, meta) => { const head = buildHead(theme, meta?.preheader as string); const body = segmentsToMjml(segments, theme); return ` ${head} ${body} `; }; const { html } = render(markdown, { wrapper: edgeToEdgeWrapper }); // Helper functions available: // buildHead(theme, preheader?) - Generates with styles and fonts // segmentsToMjml(segments, theme) - Converts parsed content to MJML body elements ``` ## Complete Email Examples Full email templates demonstrating common use cases with all features combined. ```typescript import { render, darkTheme } from "emailmd"; // Transactional email (order confirmation) const orderEmail = render(` --- preheader: "Your order has been confirmed" --- ::: header ![Logo](https://example.com/logo.png){width="120"} ::: # Order Confirmed Your order **#12345** has been placed and is being processed. | Item | Qty | Price | | :--------------------- | --: | ------: | | Wireless Headphones | 1 | $149.00 | | USB-C Cable | 2 | $24.00 | | **Total** | | **$173.00** | You'll receive a shipping confirmation once your order is on its way. [View Order](https://example.com/orders/12345){button} ::: footer **Acme Corp** · [Help](https://example.com/help) · [Unsubscribe](https://example.com/unsub) ::: `); // Newsletter with dark theme const newsletter = render(` --- preheader: "Weekly update from Acme" theme: dark brand_color: "#818cf8" --- ::: hero https://example.com/weekly-bg.jpg # This Week at Acme Your weekly product updates and tips ::: We've been busy shipping new features and squashing bugs. ::: highlight center **New Feature:** Dark mode is now available! ::: ::: callout **Pro tip:** Enable keyboard shortcuts in Settings for faster navigation. ::: [See What's New](https://example.com/changelog){button} [View Docs](https://example.com/docs){button.secondary} ::: footer **Acme Corp** · [Unsubscribe](https://example.com/unsub) ::: `); // Welcome email with custom branding const welcomeEmail = render(` --- preheader: "Welcome to Acme - Let's get started" subject: "Welcome to Acme!" --- # :wave: Welcome aboard! Thanks for signing up. We're thrilled to have you. Here's what you can do next: - [x] Create your account - [ ] Set up your profile - [ ] Invite your team [Complete Setup](https://example.com/setup){button.success fallback} ::: centered color=#71717a Questions? Just reply to this email. ::: ::: footer **Acme Corp** · San Francisco, CA · [Unsubscribe](https://example.com/unsub) ::: `, { theme: { brandColor: '#2563eb', buttonColor: '#2563eb', } }); // Access results console.log(orderEmail.html); // Complete HTML for text/html MIME part console.log(orderEmail.text); // Plain text for text/plain MIME part console.log(orderEmail.meta); // { preheader: "Your order has been confirmed" } ``` ## Summary Email.md is ideal for developers who need to send transactional emails (order confirmations, password resets, account notifications), marketing newsletters, and automated communications. The markdown-based approach makes templates readable and maintainable while the MJML foundation ensures bulletproof rendering across all email clients. Common integration patterns include using Email.md with email services like Resend, SendGrid, or AWS SES by passing the generated `html` and `text` to the service's send API. The library shines in scenarios where email templates need to be authored by non-developers or stored in databases/CMS systems, as plain markdown is far more accessible than HTML table layouts. For teams using AI to generate email content, Email.md's markdown syntax is naturally well-suited for LLM output. The theming system and frontmatter support enable brand consistency across all emails while allowing per-email customization when needed.