# Marbl Email Templates

> **Status: LOCKED 13 May 2026.**
> Canonical source of truth for every transactional, verification, lifecycle, and digest email sent from any Marbl product. Do not bespoke an email - extend this set.
>
> **Canonical location:** `marbl-codes/src/website/components/emails/templates/` (this folder). Anything outside this folder is a mirror or a consumer copy; this folder is the source.

---

## What this is

Five universal email-building TypeScript modules. Each one exports:

1. A typed config interface (`WelcomeConfig`, `VerificationConfig`, etc.)
2. One or more pre-built product configs (e.g. `LUMA_WELCOME`, `ATLAS_WELCOME`)
3. A `build*Email(config, runtime data)` function that returns `{ html, text }`

Consumers import these or copy them, pass their product-specific config and runtime data, and pipe the returned HTML straight into Resend (or any other ESP).

## What this is not

- Not a generic email library. Tightly opinionated for the Marbl brand.
- Not a templating engine. The HTML is hand-authored email-safe markup using tables (Outlook-compatible) and inline styles only.
- Not a layout primitive set. Every template is a complete top-to-bottom email.

---

## The six canonical templates

| Template | Function | Used for | Trigger |
|----------|----------|----------|---------|
| [`daily-digest.ts`](./daily-digest.ts) | `buildDailyDigestEmail(config, editions, articles, firstName, unsubscribeUrl)` | Recurring newsletter with edition headlines + featured articles + listen CTA | Luma evening digest 20:00 UTC |
| [`welcome.ts`](./welcome.ts) | `buildWelcomeEmail(config, firstName)` | After verification, introduces the product + sets expectations + offers explore links | Verification complete |
| [`verification.ts`](./verification.ts) | `buildVerificationEmail(config, name, verificationToken)` | Single-CTA email asking the user to confirm their address | Signup |
| [`lead-notification.ts`](./lead-notification.ts) | `buildLeadNotificationEmail({ name, email, phone, keyPoints, interests })` | Internal alert when Nura captures a new lead | Nura conversation hands off |
| [`conversation-summary.ts`](./conversation-summary.ts) | `buildConversationSummaryEmail({ name, messages })` | Sent to the visitor after a Nura conversation (with consent) | User opts in for summary at conversation end |
| [`on-demand.ts`](./on-demand.ts) | `buildOnDemandEmail({ name, content })` | Sent when a user verbally asks Nura mid-conversation to email them content | ElevenLabs `send_email` tool fires |

### Available product configs

| Config | Template | Product |
|--------|----------|---------|
| `LUMA_DAILY_DIGEST` | `daily-digest.ts` | Luma |
| `LUMA_WELCOME` | `welcome.ts` | Luma |
| `ATLAS_WELCOME` | `welcome.ts` | Atlas |
| `LUMA_VERIFICATION` | `verification.ts` | Luma |
| `ATLAS_VERIFICATION` | `verification.ts` | Atlas |

`lead-notification.ts` and `conversation-summary.ts` are Nura-specific and don't take product configs - they accept runtime data only.

---

## See also

- **[BRAND-RULES.md](./BRAND-RULES.md)** - Locked design decisions every template must honour. Read before editing any template.
- **[USAGE.md](./USAGE.md)** - Integration patterns for TypeScript consumers (Luma worker, Atlas), MJS pipelines (Luma cron jobs), and HTML-placeholder consumers (Subscribe).
- **[CHANGELOG.md](./CHANGELOG.md)** - Lock-in dates and material design changes.
- **Rendered samples** - `../samples/*.html` (sibling folder) - regenerated from these canonicals via `npm run render:emails` from the marbl-codes repo root.
- **Render script** - `marbl-codes/scripts/render-email-samples.mjs`.
- **Live preview** - <https://marbl.codes/components/emails/preview> (password-gated).

---

## Adding a new product config

When a new product needs an existing template (e.g. Theia needs verification emails):

1. Open the template file (e.g. `verification.ts`)
2. Add a new exported config constant alongside `LUMA_VERIFICATION` and `ATLAS_VERIFICATION`:
   ```ts
   export const THEIA_VERIFICATION: VerificationConfig = {
     product: 'Theia',
     siteUrl: 'https://theia.marbl.codes',
     heading: 'Confirm your reading',
     bodyText: 'thanks for booking with Theia. Please confirm your email...',
     ctaLabel: 'Confirm My Email',
     subtext: '...',
     ignoreText: "If you didn't sign up, you can safely ignore this email.",
   };
   ```
3. Use it in the consumer: `const { html, text } = buildVerificationEmail(THEIA_VERIFICATION, name, token);`
4. Add a render entry to `marbl-codes/scripts/render-email-samples.mjs` so a preview sample exists
5. Run `npm run render:emails` and verify in the preview page

## Adding a new template type

When a fundamentally new email type is needed (e.g. password reset, receipt, abandoned cart):

1. Copy an existing template as a starting point - `welcome.ts` is the most general
2. Strip the body content, keep the header / card / footer chrome
3. Read [BRAND-RULES.md](./BRAND-RULES.md) and apply every rule
4. Run the new template through the Moirai before locking it in
5. Add to the table in this README

---

## Brand rules (one-line summary)

- **No icons.** No emoji, no unicode symbols, no CTA arrows.
- **No beige as text.** Beige (`#F3E2C8`) is for backgrounds only. Body text is `rgba(255, 255, 255, 0.7)`.
- **Buttons.** `border-radius: 12px`. CTA text is `#131112` (dark on ember). Padding `14px 32px`. Font-weight 700.
- **Category pills.** Per-category text/border colour, no fill. See [BRAND-RULES.md](./BRAND-RULES.md).
- **Footer always includes.** Unsubscribe (if applicable), Marbl Codes link, "Built by Richard Bland", MEM Digital Limited legal, Privacy + Terms.

Full detail in [BRAND-RULES.md](./BRAND-RULES.md). Don't drift.
