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:
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’sLifecycleMailer 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) |