You need: email composed.
Pick a preset
The template model is what a preset is theming, notifying your users is the sending side, the email reference has the config, and words you supply are catalog keys like any other.
email({ theme: "midnight" })Four ship — saffron (the default), midnight, forest, rose.
Each has a hand-tuned dark palette rather than an auto-inverted one, so dark mode looks intentional instead of like a filter.
Or override part of one
email({
theme: "saffron",
themeOverride: {
accent: "#0b5fff",
logoUrl: "https://acme.com/logo.png",
},
})A partial, deep-merged override, and its type is derived from the theme itself — so it cannot drift into naming a key the theme does not have.
One accent, both modes
A single accent carries the CTA button and the header rule in light and dark alike.
That is deliberate: two accents is two things to keep in balance across two palettes, and the second one is always the one nobody checks.
Width belongs to the message, not the brand
Each template declares the body width it renders at.
A one-line security alert and a newsletter want different measures, and that difference is a property of the email type. So switching themes never re-flows a template into a shape it was not written for.
The compliance footer is part of the theme
Because it is the same on every message, and a marketing template cannot render without an unsubscribe link regardless.
Visual polish is deliberately secondary
The deliverable is the typed input contract — each template’s Zod payload schema, its category and its kind.
Bodies are Handlebars including shared head and foot partials, so every template inherits the theme and the Gmail-safe shell without restating either.
No catalog value may carry markup
What you cannot do, and why
There is no registerTemplate. Three reasons, and the first is not a matter of taste:
The Workers runtime forbids code generation, so a template cannot be compiled where it runs. Accepting yours means accepting a spec built by your Handlebars — and Handlebars refuses a spec whose compiler revision differs from the runtime’s. A skew nobody would notice until every email failed to render at once.
The kind would become a claim again. A registerable template makes this is transactional writable at a call site, and the mail it produces ignores an unsubscribe under your own sending domain.
Escaping is structural here. supportReply and testerNudge are safe because their bodies are fixed and the words arrive as escaped values. A supplied body with one triple-brace is a phishing page sent over your DKIM signature.
What the closure obliges instead: where a shape is missing the kit adds it, and where the words are yours the template takes them as payload. supportReply, testerNudge and operationalNotice are all that pattern.