From 56ebf652b1b9a532feb73e075e3998f3f35c4c43 Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Wed, 11 Dec 2024 18:09:16 +0100 Subject: [PATCH] i18n subject in mailer --- README.md | 7 ++----- docker-compose.yml | 1 + src/routes/email.ts | 5 ++--- src/swagger.ts | 5 +---- src/templates/index.ts | 5 +++++ src/templates/password-reset/de.subject.txt | 1 + src/templates/password-reset/en.subject.txt | 1 + src/templates/welcome/de.subject.txt | 1 + src/templates/welcome/en.subject.txt | 1 + 9 files changed, 15 insertions(+), 12 deletions(-) create mode 100644 src/templates/password-reset/de.subject.txt create mode 100644 src/templates/password-reset/en.subject.txt create mode 100644 src/templates/welcome/de.subject.txt create mode 100644 src/templates/welcome/en.subject.txt diff --git a/README.md b/README.md index b735772..72d2732 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,6 @@ curl -X POST http://localhost:3000/api/v1/email \ -H "Content-Type: application/json" \ -d '{ "to": "user@example.com", - "subject": "Welcome to Lauf für Kaya! 2025", "templateName": "welcome", "language": "en", "data": { @@ -52,13 +51,10 @@ curl -X POST http://localhost:3000/api/v1/email \ -H "Content-Type: application/json" \ -d '{ "to": "user@example.com", - "subject": "Password Reset Request", "templateName": "password-reset", "language": "de", "data": { - "name": "John Doe", - "resetLink": "https://example.com/reset/123", - "expiresIn": "24 hours" + "token": "123465789" } }' ``` @@ -79,6 +75,7 @@ SMTP_PASS="secret.1" EMAIL_FROM="noreply@lauf-fuer-kaya.de" EMAIL_REPLYTO="info@lauf-fuer-kaya.de" REDIS_URL=redis://localhost:6379 +FRONTEND_URL="https://run.lauf-fuer-kaya.de" ``` ## 🛠️ Development diff --git a/docker-compose.yml b/docker-compose.yml index 4f258e6..5b730c0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,6 +14,7 @@ services: - SMTP_PASS="secret.1" - EMAIL_FROM="noreply@lauf-fuer-kaya.de" - EMAIL_REPLYTO="info@lauf-fuer-kaya.de" + - FRONTEND_URL="https://run.lauf-fuer-kaya.de" depends_on: - redis diff --git a/src/routes/email.ts b/src/routes/email.ts index 7244bd9..2778461 100644 --- a/src/routes/email.ts +++ b/src/routes/email.ts @@ -11,7 +11,6 @@ const emailService = new EmailService() const sendEmailSchema = z.object({ to: z.string().email(), - subject: z.string(), templateName: z.string(), language: z.enum(['en', 'de']), data: z.record(z.any()) @@ -34,7 +33,7 @@ async function generateBarcodeDataURL(data) { } emailRouter.post('/', zValidator('json', sendEmailSchema), async (c) => { - let { to, subject, templateName, language, data } = c.req.valid('json') + let { to, templateName, language, data } = c.req.valid('json') try { const template = getEmailTemplate(templateName, language as Language) @@ -56,7 +55,7 @@ emailRouter.post('/', zValidator('json', sendEmailSchema), async (c) => { } await emailService.sendEmail({ to, - subject, + subject: template.subject(data), html: template.html(data), text: template.text(data) }) diff --git a/src/swagger.ts b/src/swagger.ts index 74ee0d5..dd3f681 100644 --- a/src/swagger.ts +++ b/src/swagger.ts @@ -10,15 +10,12 @@ const routes = { 'application/json': { schema: { type: 'object', - required: ['to', 'subject', 'templateName', 'language', 'data'], + required: ['to', 'templateName', 'language', 'data'], properties: { to: { type: 'string', format: 'email' }, - subject: { - type: 'string' - }, templateName: { type: 'string' }, diff --git a/src/templates/index.ts b/src/templates/index.ts index b58d15d..7994b1b 100644 --- a/src/templates/index.ts +++ b/src/templates/index.ts @@ -6,6 +6,7 @@ import { compile } from 'handlebars' interface TemplateCache { [key: string]: { html: HandlebarsTemplateDelegate + subject: HandlebarsTemplateDelegate, text: HandlebarsTemplateDelegate } } @@ -18,12 +19,15 @@ function loadTemplate(name: string, language: Language) { if (!templateCache[cacheKey]) { const htmlPath = join(process.cwd(), 'src', 'templates', name, `${language}.html`) const textPath = join(process.cwd(), 'src', 'templates', name, `${language}.txt`) + const subjectPath = join(process.cwd(), 'src', 'templates', name, `${language}.subject.txt`) const htmlTemplate = readFileSync(htmlPath, 'utf-8') const textTemplate = readFileSync(textPath, 'utf-8') + const subjectTemplate = readFileSync(subjectPath, 'utf-8') templateCache[cacheKey] = { html: compile(htmlTemplate), + subject: compile(subjectTemplate), text: compile(textTemplate) } } @@ -35,6 +39,7 @@ export function getEmailTemplate(name: string, language: Language) { const template = loadTemplate(name, language) return { + subject: (data: any) => template.subject(data), html: (data: any) => template.html(data), text: (data: any) => template.text(data) } diff --git a/src/templates/password-reset/de.subject.txt b/src/templates/password-reset/de.subject.txt new file mode 100644 index 0000000..f5a90d4 --- /dev/null +++ b/src/templates/password-reset/de.subject.txt @@ -0,0 +1 @@ +Lauf für Kaya! Passwort Reset \ No newline at end of file diff --git a/src/templates/password-reset/en.subject.txt b/src/templates/password-reset/en.subject.txt new file mode 100644 index 0000000..86c8fbc --- /dev/null +++ b/src/templates/password-reset/en.subject.txt @@ -0,0 +1 @@ +Lauf für Kaya! Password Reset \ No newline at end of file diff --git a/src/templates/welcome/de.subject.txt b/src/templates/welcome/de.subject.txt new file mode 100644 index 0000000..a729a52 --- /dev/null +++ b/src/templates/welcome/de.subject.txt @@ -0,0 +1 @@ +Willkommen beim Lauf für Kaya! 2025 \ No newline at end of file diff --git a/src/templates/welcome/en.subject.txt b/src/templates/welcome/en.subject.txt new file mode 100644 index 0000000..227fb76 --- /dev/null +++ b/src/templates/welcome/en.subject.txt @@ -0,0 +1 @@ +Welcome to Lauf für Kaya! 2025 \ No newline at end of file