← ClaudeAtlas

render-transactional-emailslisted

Use when sending a templated transactional email (or generating a templated PDF/document) — rendering from a named template + data through one shared render service, with per-locale template files, CSS inlining, returning subject/html/text, then dispatching via the notification facade (not inline). Covers reusing the same render for HTML→PDF. NestJS/TS reference, framework-flexible.
kennguyen887/agent-foundation · ★ 1 · Data & Documents · score 77
Install: claude install-skill kennguyen887/agent-foundation
# Render transactional emails (and documents) Producing transactional content — order receipts, OTPs, invites, notices, PDFs — from templates rather than hand-built strings. Examples NestJS/TS (an `email-templates`/EJS + CSS-inliner stack), neutral domain. principle → **▸ Example** → **▸ Other stacks**. Sending lives behind the notification facade in `integrate-external-services` §1; this skill is how the *content* is produced. ## Core principle **Never concatenate email HTML in a handler.** Render from a **versioned template + a typed data context** through one shared service — localized and CSS-inlined — and return a `{ subject, html, text }` the transport sends. Templates hold markup; code holds logic. ## 1. One render service over a template engine Wrap the template lib (EJS / Handlebars / …) + a CSS inliner (so styles survive email clients) in a single `render(templateName, context)`; resolve the file by **name + locale convention**; configure the template root via DI, not hard-coded paths. ```ts @Injectable() export class TemplateService { private email = new Email({ views: { root, options: { extension: 'ejs' } }, getPath: (file, template, ctx) => path.join(dir, template, `${file}.${ctx.language ?? 'en'}`), // <template>/<file>.<lang> juiceResources: { /* inline CSS */ }, }); render(name: string, ctx: { language?: string; data: unknown }) { return this.email.renderAll(name, ctx.data); // → { subject, html, text } } } ``` ## 2. Templates are