import { BRAND, BRAND_COLORS } from "@/lib/brand"; import { DOCUMENT_THEME } from "@/lib/document-brand"; /** * Brandfähige E-Mail-Template-Basis (Story S6). * * SMTP und der Einladungs-/Reset-Flow kommen erst mit Paket 4 — dieses Modul * liefert vorab das Certvia-Gerüst, damit die Templates dann nur noch Inhalt * einsetzen müssen und das CD nicht neu erfunden wird. * * Bewusste Einschränkungen für E-Mail-Clients: * - keine CSS-Variablen, keine externen Stylesheets → alles inline * - Tabellen-Layout statt Flex/Grid (Outlook) * - Logo als absolute URL, kein Inline-SVG (viele Clients rendern es nicht) * - immer eine Plaintext-Alternative mitschicken (`renderTextEmail`) */ export type EmailContent = { /** Betreff — wird nicht in den Body gerendert, nur durchgereicht */ subject: string; /** Überschrift im Body */ heading: string; /** Absätze; jeder Eintrag wird ein

*/ paragraphs: string[]; /** Optionaler Call-to-Action */ action?: { label: string; url: string }; /** Kleingedrucktes über der Fußzeile (z. B. Gültigkeitsdauer eines Links) */ note?: string; /** * Zusatzzeile in der Fußzeile — für den Abmelde-/Präferenzhinweis bei * Benachrichtigungsmails. Sicherheitsrelevante Transaktionsmails (Reset, * Passwortwechsel) setzen ihn bewusst NICHT: sie sind nicht abbestellbar. */ footerNote?: string; }; /** * Basis-URL für absolute Links/Bilder in Mails. Relative Pfade funktionieren in * E-Mail-Clients nicht. */ function baseUrl(): string { return (process.env.AUTH_URL ?? process.env.NEXTAUTH_URL ?? "https://app.certvia.de").replace( /\/+$/, "" ); } function escapeHtml(s: string): string { return s .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } /** Absenderzeile für den `From`-Header. */ export function emailSender(address: string): string { return `${BRAND.name} <${address}>`; } /** Signatur-/Fußzeilentext — enthält immer den Dachmarken-Hinweis. */ export function emailSignature(): string { return `${BRAND.name} — ${BRAND.byline}`; } /** * Rendert eine Mail im Certvia-CD (heller Grund, Marken-Violett, Poppins-Kopf). * Rückgabe ist ein vollständiges HTML-Dokument. */ export function renderHtmlEmail(content: EmailContent): string { const url = baseUrl(); const t = DOCUMENT_THEME; const paragraphs = content.paragraphs .map( (p) => `

${escapeHtml(p)}

` ) .join(""); const action = content.action ? `
${escapeHtml(content.action.label)}
` : ""; const note = content.note ? `

${escapeHtml(content.note)}

` : ""; return ` ${escapeHtml(content.subject)}
${BRAND.name}

${escapeHtml(content.heading)}

${paragraphs} ${action} ${note}
${escapeHtml(emailSignature())}${ content.footerNote ? `
${escapeHtml(content.footerNote)}` : "" }
`; } /** Plaintext-Alternative zur HTML-Mail (immer als `text` mitschicken). */ export function renderTextEmail(content: EmailContent): string { const lines = [content.heading, "", ...content.paragraphs]; if (content.action) lines.push("", `${content.action.label}: ${content.action.url}`); if (content.note) lines.push("", content.note); lines.push("", "—", emailSignature()); if (content.footerNote) lines.push(content.footerNote); return lines.join("\n"); }