# API Reference (/docs/api-reference) render(markdown, options?) [#rendermarkdown-options] Renders markdown to email-safe HTML. **Returns** `{ html, text, meta }` * `html` — complete HTML email document * `text` — plain text version for the `text/plain` MIME part * `meta` — extracted frontmatter metadata ```typescript import { render } from "emailmd"; const { html, text, meta } = render("# Hello"); ``` RenderOptions [#renderoptions] ```typescript { theme?: Partial; wrapper?: 'default' | WrapperFn; } ``` | Option | Type | Description | | --------- | ------------------------ | ----------------------------- | | `theme` | `Partial` | Override default theme values | | `wrapper` | `'default' \| WrapperFn` | Custom email wrapper function | RenderResult [#renderresult] ```typescript { html: string; text: string; meta: { preheader?: string; [key: string]: unknown }; } ``` | Property | Type | Description | | -------- | -------- | --------------------------------- | | `html` | `string` | Complete email-safe HTML document | | `text` | `string` | Plain text version | | `meta` | `object` | Extracted frontmatter metadata | Theme [#theme] The full theme interface with all customizable properties: ```typescript interface Theme { brandColor: string; // Links, highlights, accents headingColor: string; // Heading text bodyColor: string; // Body text backgroundColor: string; // Outer background contentColor: string; // Content area background cardColor: string; // Callout / code block background buttonColor: string; // Primary button background buttonTextColor: string; // Button text secondaryColor: string; // Secondary button border secondaryTextColor: string; // Secondary button text successColor: string; // Success button background successTextColor: string; // Success button text dangerColor: string; // Danger button background dangerTextColor: string; // Danger button text warningColor: string; // Warning button background warningTextColor: string; // Warning button text fontFamily: string; // Font stack fontSize: string; // Base font size (e.g. "16px") lineHeight: string; // Base line height (e.g. "1.6") contentWidth: string; // Email width (e.g. "600px") } ``` Pass a `Partial` to `render()` to override any subset of values. See [Theme](/docs/theme) for defaults. darkTheme [#darktheme] A pre-built dark theme object. Import and pass directly or spread with overrides: ```typescript import { render, darkTheme } from "emailmd"; // Use as-is render(md, { theme: darkTheme }); // Override specific values render(md, { theme: { ...darkTheme, brandColor: "#e11d48" } }); ``` buildHead(theme, preheader?) [#buildheadtheme-preheader] ```typescript function buildHead(theme: Theme, preheader?: string): string; ``` Generates the MJML `` element containing global styles, font imports, and the hidden preheader text. Used when building [custom wrappers](/docs/wrappers). segmentsToMjml(segments, theme) [#segmentstomjmlsegments-theme] ```typescript function segmentsToMjml(segments: Segment[], theme: Theme): string; ``` Converts parsed content segments into MJML body elements (sections, columns, text, buttons, images, tables, etc.). Used when building [custom wrappers](/docs/wrappers). Segment [#segment] ```typescript interface Segment { type: 'text' | 'callout' | 'centered' | 'highlight' | 'header' | 'footer' | 'button' | 'button-group' | 'image' | 'hr' | 'table' | 'hero'; content: string; attrs?: Record; buttons?: Array>; } ``` Represents a parsed block of content from the markdown. The `segments` array is what gets passed to `segmentsToMjml` and to custom wrapper functions. WrapperFn [#wrapperfn] ```typescript type WrapperFn = ( segments: Segment[], theme: Theme, meta?: Record, ) => string; ``` A function that receives parsed segments, the resolved theme, and frontmatter metadata, and returns a complete MJML string. See [Wrappers](/docs/wrappers) for usage examples. # Buttons (/docs/buttons) Add call-to-action buttons using the `{button}` attribute: ```markdown [Get Started](https://example.com){button} [Learn More](https://example.com){button.secondary} [Shop Sale](https://example.com){button color="#dc2626"} ``` Semantic Colors [#semantic-colors] Use preset color names for common actions: ```markdown [Confirm Account](https://example.com/confirm){button.success} [Delete Account](https://example.com/delete){button.danger} [Review Changes](https://example.com/review){button.warning} ``` These default to standard semantic colors (green, red, amber). You can customize them with `success_color`, `danger_color`, and `warning_color` in [frontmatter](/docs/frontmatter) or via the [theme API](/docs/theme). The secondary button color can be changed with `secondary_color`. Side-by-Side Buttons [#side-by-side-buttons] Place multiple buttons on the same line to render them side-by-side: ```markdown [Get Started](https://example.com){button} [Learn More](https://example.com/more){button.secondary} ``` Buttons on separate lines (separated by a blank line) stack vertically as usual. MJML handles responsive stacking automatically — side-by-side on desktop, stacked on mobile. Full-Width Buttons [#full-width-buttons] Make a button span the full width of the email content area with `width="full"`: ```markdown [Get Started](https://example.com){button width="full"} ``` This works with any variant or custom color: ```markdown [Learn More](https://example.com){button.secondary width="full"} [Shop Sale](https://example.com){button color="#dc2626" width="full"} ``` Border Radius [#border-radius] Override the default border radius (`8px`) on individual buttons with `border-radius="..."`: ```markdown [Get Started](https://example.com){button border-radius="24px"} [Sharp](https://example.com){button border-radius="0"} ``` To change the default border radius for all buttons (and callouts/highlights), set `border_radius` in [frontmatter](/docs/frontmatter) or via the [theme API](/docs/theme). Button Fallback [#button-fallback] Add a fallback URL below a button for accessibility. Some email clients block or strip buttons, so providing the raw URL ensures recipients can still take action: ```markdown [Reset Password](https://example.com/reset){button fallback} ``` This renders a small muted text below the button: *"If you're having trouble clicking the button, copy and paste this URL into your browser."* Works with button groups too — only buttons with `fallback` show their URL: ```markdown [Accept](https://example.com/accept){button fallback} [Decline](https://example.com/decline){button.secondary} ``` Custom Fallback Text [#custom-fallback-text] Override the default fallback message with `fallback="custom text"` to support different languages or custom wording: ```markdown [Réinitialiser](https://example.com/reset){button fallback="Si vous avez des difficultés, copiez cette URL :"} ``` The custom text is rendered before the URL link. When no value is provided (`fallback` without `="..."`), the default English message is used. # CLI (/docs/cli) Email.md ships with a built-in CLI. Install [#install] If emailmd is already a project dependency, you can run it via `npx`: ```bash npx emailmd input.md ``` To install it as a global command: ```bash npm install -g emailmd ``` Usage [#usage] ```bash emailmd [file] [options] ``` If no file is given, the CLI reads from stdin. Options [#options] | Option | Description | | ------------------ | ---------------------------------------- | | `-o, --output ` | Write output to a file instead of stdout | | `-t, --text` | Output plain text instead of HTML | | `-h, --help` | Show help | | `-v, --version` | Show version number | Examples [#examples] Render a markdown file to HTML: ```bash emailmd input.md ``` Write the output to a file: ```bash emailmd input.md -o output.html ``` Get the plain text version (for the `text/plain` MIME part): ```bash emailmd input.md --text ``` Pipe from another command: ```bash echo "# Hello" | emailmd curl -s https://example.com/template.md | emailmd -o email.html ``` # Emoji (/docs/emoji) Insert emoji by shortcode name using the `:shortcode:` syntax: ```markdown Gone camping! :tent: Be back soon. That is so funny! :joy: ``` The full set of \~1900 emoji shortcodes from [markdown-it-emoji](https://github.com/markdown-it/markdown-it-emoji) is supported. Emoji are rendered as native Unicode characters, so they display natively in all modern email clients without image fallbacks. Common Examples [#common-examples] | Shortcode | Emoji | Shortcode | Emoji | | -------------------- | ----- | ------------ | ----- | | `:smile:` | 😄 | `:heart:` | ❤️ | | `:wave:` | 👋 | `:fire:` | 🔥 | | `:rocket:` | 🚀 | `:star:` | ⭐ | | `:thumbsup:` | 👍 | `:tada:` | 🎉 | | `:white_check_mark:` | ✅ | `:warning:` | ⚠️ | | `:email:` | 📧 | `:calendar:` | 📅 | Usage in Emails [#usage-in-emails] ```markdown :wave: **Welcome aboard!** Your order has been confirmed :white_check_mark: :calendar: Delivery expected: Friday ``` Full Shortcode Reference [#full-shortcode-reference] Use the [emoji picker in the builder](/builder) to search all available shortcodes, or see the [full emoji list](https://gist.github.com/rxaviers/7360908). # Frontmatter (/docs/frontmatter) Add a YAML frontmatter block at the top of your markdown to override theme values and set metadata per-email: ```markdown --- preheader: "Don't miss our biggest sale" brand_color: "#e11d48" button_color: "#059669" --- # Sale Starts Now Everything is 50% off this weekend. ::: footer **Acme Corp** · [Unsubscribe](https://example.com/unsub) ::: ``` Frontmatter uses `snake_case` keys. They map directly to the same [theme options](/docs/theme) available in the JS API (which uses `camelCase`). Preheader [#preheader] The `preheader` field sets the preview text that email clients show in the inbox list next to the subject line. It's hidden in the email body itself: ```markdown --- preheader: "Your order has shipped — track it now" --- ``` Selecting a Theme [#selecting-a-theme] Use `theme` to switch the base theme for a single email. Individual overrides still layer on top: ```markdown --- theme: dark brand_color: "#e11d48" --- # Dark email with a custom brand color ``` Valid values: `light` (default), `dark`. All Frontmatter Keys [#all-frontmatter-keys] | Key | Description | | ---------------------- | ----------------------------------------------- | | `preheader` | Inbox preview text (hidden in email body) | | `theme` | Base theme — `light` or `dark` | | `brand_color` | Links, highlights, accents | | `heading_color` | Heading text color | | `body_color` | Body text color | | `background_color` | Outer background color | | `content_color` | Content area background | | `card_color` | Callout / code block background | | `button_color` | Primary button background | | `button_text_color` | Button text color | | `secondary_color` | Secondary button border | | `secondary_text_color` | Secondary button text | | `success_color` | Success button background | | `success_text_color` | Success button text | | `danger_color` | Danger button background | | `danger_text_color` | Danger button text | | `warning_color` | Warning button background | | `warning_text_color` | Warning button text | | `font_family` | Font stack | | `font_size` | Base font size | | `line_height` | Base line height | | `content_width` | Email content width | | `border_radius` | Border radius for buttons, callouts, highlights | Custom Metadata [#custom-metadata] Any keys beyond the ones above are passed through in the `meta` object returned by `render()`. This is useful for storing email metadata alongside the template: ```markdown --- preheader: "Welcome aboard" subject: "Welcome to Acme" campaign_id: "onboarding-v2" --- # Welcome! ``` ```typescript const { html, text, meta } = render(markdown); console.log(meta.subject); // "Welcome to Acme" console.log(meta.campaign_id); // "onboarding-v2" console.log(meta.preheader); // "Welcome aboard" ``` # Getting Started (/docs/getting-started) Installation [#installation] ```bash npm install emailmd ``` Basic Usage [#basic-usage] Import the `render` function and pass it a markdown string: ```typescript import { render } from "emailmd"; const { html, text } = render(` # Welcome! Thanks for signing up. [Get Started](https://example.com){button} `); ``` The `render` function returns: * `html` — a complete HTML document (DOCTYPE, html, head, body) ready to use as the `text/html` MIME part. Not a fragment — you can send it as-is. * `text` — plain text version for the `text/plain` MIME part. Buttons become `Label: https://url`, images become `[Image: alt]`, and all formatting is stripped. * `meta` — frontmatter metadata extracted from the markdown. Includes `preheader` (inbox preview text) and any custom keys you define. See [Frontmatter](/docs/frontmatter). Next Steps [#next-steps] * [Theme](/docs/theme) — Customize colors and fonts * [Frontmatter](/docs/frontmatter) — Set metadata per-email * [Buttons](/docs/buttons) — Add call-to-action buttons * [Directives](/docs/directives) — Use header, hero, callout, and more * [API Reference](/docs/api-reference) — Full API documentation # Images (/docs/images) Block images (standalone paragraph) are automatically rendered as responsive, centered email images: ```markdown ![Hero banner](https://example.com/hero.jpg) ``` Width [#width] Control image width with the attrs syntax: ```markdown ![Product](https://example.com/product.jpg){width="400"} ``` Alignment [#alignment] Images are centered by default. Override with: ```markdown ![Photo](https://example.com/photo.jpg){align="left"} ``` Rounded Corners [#rounded-corners] ```markdown ![Avatar](https://example.com/avatar.jpg){width="80" border-radius="50%"} ``` Linked Images [#linked-images] Wrap an image in a link to make it clickable: ```markdown [![Shop banner](https://example.com/banner.jpg)](https://example.com/shop) ``` Inline Images [#inline-images] Images mixed with text in a paragraph are rendered inline: ```markdown Feature one with icon ![check](https://example.com/check.png) included. ``` Vertical Alignment [#vertical-alignment] Inline images default to `vertical-align: middle`, centering them with adjacent text. Override per image with `valign`: ```markdown Top-aligned ![icon](https://example.com/icon.png){valign="top"} icon. ``` Supported values: `top`, `middle`, `bottom`, `baseline`, `text-top`, `text-bottom`. Float [#float] Use `float` to wrap text around an image instead of flowing beneath it: ```markdown ![Plant](https://example.com/plant.jpg){width="80" float="left"} **Monstera Deliciosa, 6" pot** Easy care · Bright indirect light · $42.00 ``` Supported values: `left`, `right`. Appropriate margin is added automatically. > **Note:** Outlook desktop ignores `float` and falls back to default inline behavior. Inline Image Size [#inline-image-size] Control inline image dimensions with `width` and `height`: ```markdown A small ![icon](https://example.com/icon.png){width="20" height="20"} icon. ``` # Introduction (/docs) Why Email.md? [#why-emailmd] Writing good email HTML is really hard. Unlike web pages, email clients don't share a modern rendering engine - Outlook still uses Microsoft Word's rendering engine, Gmail strips out `