Files
skills/docs/communication/emails/email-templates/README.md
2026-05-29 08:20:56 +01:00

11 KiB

@suaveplan/email-templates - Universal React-free email template engine: VNode factories, nine reusable components, five built-in templates (welcome, verification, password-reset, notification, invoice), typed registry, fluent builder, theme system, structured errors, OTel instruments. Produces email-safe HTML strings with inline styles; runs in Bun, Node, and browser.

Universal, React-free email template engine. Produces email-safe HTML strings with inline styles via VNode factories — runs identically in Bun, Node, and the browser.

Documentation tree

  • email-button — EmailButton is the canonical call-to-action surface in an email body — a table-wrapped <a> with variant-driven them…
    • email-button — EmailButton is the canonical call-to-action surface in an email body — a table-wrapped <a> with variant-driven them…
  • email-container — EmailContainer groups related content inside an email body — a callout box, an info banner, a code-card. It emits a s…
    • email-container — EmailContainer groups related content inside an email body — a callout box, an info banner, a code-card. It emits a s…
  • email-divider — A horizontal divider rendered as a single-row <table> whose <td> carries border-top: 1px solid <color>. The table…
    • email-divider — A horizontal divider rendered as a single-row <table> whose <td> carries border-top: 1px solid <color>. The table…
  • email-footer — Renders the email footer block — company copyright, optional address, optional list of inline links (typically Privacy…
    • email-footer — Renders the email footer block — company copyright, optional address, optional list of inline links (typically Privacy…
  • email-heading — Renders an <h1>…<h6> element with a level-keyed font-size and line-height schedule tuned for inbox-rendering ergono…
    • email-heading — Renders an <h1>…<h6> element with a level-keyed font-size and line-height schedule tuned for inbox-rendering ergono…
  • email-image — Renders an <img> inside a centring <table> with the canonical responsive-email defaults (display:block, `max-widt…
    • email-image — Renders an <img> inside a centring <table> with the canonical responsive-email defaults (display:block, `max-widt…
  • email-layout — EmailLayout is the root VNode every email template wraps its body in. It emits a 100%-width <table> with a themed m…
    • email-layout — EmailLayout is the root VNode every email template wraps its body in. It emits a 100%-width <table> with a themed m…
  • email-link — Themed inline <a> link with safe defaults (target="_blank", rel="noopener noreferrer") for body-copy hyperlinks.…
    • email-link — Themed inline <a> link with safe defaults (target="_blank", rel="noopener noreferrer") for body-copy hyperlinks.…
  • email-text — Paragraph component for email-body copy. EmailText emits a themed <p> with one of three size variants (body / `ca…
    • email-text — Paragraph component for email-body copy. EmailText emits a themed <p> with one of three size variants (body / `ca…
  • error-codes — Stable error-code registry for @suaveplan/email-templates. Every failure raised by the package extends `SuaveplanErro…
    • error-codes — Stable error-code registry for @suaveplan/email-templates. Every failure raised by the package extends `SuaveplanErro…
  • message — createEmailMessage glues the renderer to the addressing envelope, producing an EmailMessageResult plain object suit…
    • message — createEmailMessage glues the renderer to the addressing envelope, producing an EmailMessageResult plain object suit…
  • renderer — The renderer is the bridge between the EmailTemplate<TProps> contract and a final { html, text, subject } triple re…
    • renderer — The renderer is the bridge between the EmailTemplate<TProps> contract and a final { html, text, subject } triple re…
  • telemetry — Exposes the OpenTelemetry instrument set published by @suaveplan/email-templates. Every public render or registry mut…
    • telemetry — Exposes the OpenTelemetry instrument set published by @suaveplan/email-templates. Every public render or registry mut…
  • template-builder — TemplateBuilder is a fluent API for assembling an EmailTemplate<TProps> value step-by-step. It exists because const…
    • template-builder — TemplateBuilder is a fluent API for assembling an EmailTemplate<TProps> value step-by-step. It exists because const…
  • template-registry — TemplateRegistry is a type-safe in-memory store for EmailTemplate values keyed by name. It supports per-name lookup…
    • template-registry — TemplateRegistry is a type-safe in-memory store for EmailTemplate values keyed by name. It supports per-name lookup…
  • invoice — The invoiceTemplate is the receipt / invoice / order-confirmation email. It renders a heading carrying the invoice nu…
    • invoice — The invoiceTemplate is the receipt / invoice / order-confirmation email. It renders a heading carrying the invoice nu…
  • notification — The notificationTemplate is the generic system-notification email — a configurable severity callout suitable for prod…
    • notification — The notificationTemplate is the generic system-notification email — a configurable severity callout suitable for prod…
  • password-reset — The passwordResetTemplate is the canonical password-reset message. It explains the request, exposes a reset CTA, comm…
    • password-reset — The passwordResetTemplate is the canonical password-reset message. It explains the request, exposes a reset CTA, comm…
  • verification — The verificationTemplate is the standard email-address verification flow message. It greets the recipient, optionally…
    • verification — The verificationTemplate is the standard email-address verification flow message. It greets the recipient, optionally…
  • welcome — The welcomeTemplate is the canonical post-signup onboarding email. It greets the recipient by name, summarises why th…
    • welcome — The welcomeTemplate is the canonical post-signup onboarding email. It greets the recipient by name, summarises why th…
  • theme — Provides the theme tokens consumed by every email component — colours, typography, spacing, branding, border-radius, an…
    • theme — Provides the theme tokens consumed by every email component — colours, typography, spacing, branding, border-radius, an…
  • vnode — Defines the universal VNode primitive — a { tag, attrs, children } triple plus a pure-string HTML renderer — tha…
    • vnode — Defines the universal VNode primitive — a { tag, attrs, children } triple plus a pure-string HTML renderer — tha…

What's included

  • Nine reusable components — EmailLayout, EmailContainer, EmailHeading, EmailText, EmailLink, EmailImage, EmailDivider, EmailButton, EmailFooter.
  • Five built-in templates — welcomeTemplate, verificationTemplate, passwordResetTemplate, notificationTemplate, invoiceTemplate.
  • VNode core — h(tag, attrs, children) hyperscript factory and a pure-string renderVNode walker.
  • Renderer — renderToHtml(template, props, options?) → { html, text, subject } with OTel instrumentation.
  • Theme system — defaultTheme, createTheme, mergeThemes.
  • Type-safe registry — TemplateRegistry<TMap> with category / tag / author search.
  • Fluent builder — TemplateBuilder<TProps> / createTemplateBuilder<TProps>().
  • Adapter — createEmailMessage(template, props, recipient, options?) returning a plain-object envelope ready for SMTP / SES / SendGrid.
  • Structured errors — EmailTemplatesError with six EMAIL_TEMPLATES.* codes.

Quick start

import {
  createEmailMessage,
  welcomeTemplate,
} from "@suaveplan/email-templates";

const message = createEmailMessage(
  welcomeTemplate,
  { recipientName: "Jane", ctaUrl: "https://app.example.test/get-started" },
  { to: "jane@example.test", from: "hello@suaveplan.com" },
);

await mailer.send(message);

Architecture

Upstream @suaveplan/email-templates was a React component library rendered via react-dom/server. The port honours the enterprise spec §3 ("Zero browser / Node / React dependencies") by re-implementing the full upstream surface as VNode factories — pure functions returning { tag, attrs, children } triples walked by a single HTML-emitter (renderVNode).

The renderer is the sole point at which child text is HTML-escaped and attributes are serialised. Components emit data; escaping happens once.

Universal

  • Zero React / DOM / Node-specific dependencies at runtime.
  • Injectable Clock (@suaveplan/types) for deterministic footer year.
  • OTel instruments via @opentelemetry/api.
  • Pure-TypeScript implementation, 100% statement / branch / function / line coverage.

Sub-path exports

@suaveplan/email-templates/vnode, …/theme, …/renderer, …/message, …/template-builder, …/template-registry, …/components, …/templates, …/errors, …/otel — each exposes a focused slice of the surface for tree-shake friendliness.