> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useduro.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Emails & Templates

> A shared template engine with per-tenant overrides, rendered and enqueued from the lifecycle the customer actually lives.

Every lifecycle moment that should reach a customer — a receipt, a renewal reminder, a dunning nudge, a recovery win — flows through one template system and one queue.

## Defaults plus per-tenant overrides

Template content lives in `@duro/email` as a set of **defaults** (keyed `receipt`, `renewal_reminder`, `dunning_1…4`, `payment_recovered`, `card_expiring`, `welcome`, …), each a `{ subject, body, channel }`. A merchant can **override** any of them, stored per-tenant in the core schema's `email_templates`. The resolver is simple and predictable:

```mermaid theme={null}
flowchart LR
    KEY["template key<br/>e.g. 'receipt'"] --> OVR{"tenant override<br/>exists + enabled?"}
    OVR -->|"yes"| USE["use override<br/>subject + body"]
    OVR -->|"no"| DEF["use default"]
    USE & DEF --> RENDER["TemplateRenderer.render(<br/>{{store_name}}, {{amount}},<br/>{{customer_name}}, …)"]
    RENDER --> ENQ["MailQueue.enqueue"]
```

Merge tags (`{{store_name}}`, `{{amount}}`, `{{plan_name}}`, `{{invoice_id}}`, `{{update_link}}`, `{{next_attempt}}`) are interpolated by an iterative renderer — no recursion, no template-injection surface. `{{store_name}}` is filled from the tenant automatically.

## Wired into the lifecycle

The worker's `LifecycleMailer` is the bridge between an event happening and an email being queued:

| Moment                                | Template                             |
| ------------------------------------- | ------------------------------------ |
| Successful renewal                    | `receipt`                            |
| First renewal failure                 | `dunning_1`                          |
| Subsequent dunning retries            | `dunning_2…4` (by attempt)           |
| Recovery succeeded                    | `payment_recovered`                  |
| Renewing within the merchant's window | `renewal_reminder`                   |
| Register / KYC submitted              | `welcome` / KYC templates (core-api) |

Each is rendered with the right context and **enqueued, not sent** — the [email worker](/platform/queues-and-workers#email-as-a-queue-not-an-await) drains the queue against SMTP. Verified end-to-end through real Redis: a successful renewal queues a templated receipt; a failed one queues a dunning reminder.

## The Email tab in the builder

The same template content is what the [appearance builder's](/platform/appearance) **Email** tab edits — subject, body, merge tags, live preview — and what the dunning settings' email-sequence editor sequences. One template store, edited from the UI, rendered by the worker. No divergence between "what the merchant configured" and "what the customer receives."

Next: the [appearance builder](/platform/appearance).
