From 3ef76a4433f15fc4298b4c1d6ed19713b28e8b61 Mon Sep 17 00:00:00 2001 From: joachimhummel <47454583-joachimhummel@users.noreply.replit.com> Date: Fri, 15 May 2026 17:11:43 +0000 Subject: [PATCH] Task #17: Send a branded notification email to Joachim on contact form submission MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced the minimal plain-HTML notification email (sent to jh@unixweb.de) with a fully branded HTML email that matches the existing confirmation email layout. Changes: - Added `buildNotificationEmail()` function in `artifacts/api-server/src/routes/contact.ts` - Same visual structure as `buildConfirmationEmail()`: blue header with JH monogram, white card body, divider, branded footer with links - Sender details (name, e-mail, subject, message) are displayed in a structured field table inside the card body, with subtle background shading and label rows - "Absender antworten →" CTA button links to `mailto:{email}?subject=Re: {subject}` so Joachim can reply to the sender in one click - Subject field row is conditionally rendered (omitted when no subject was provided) - All user-supplied values are escaped through the existing `escapeHtml()` helper - The first `sendTransacEmail` call now passes `buildNotificationEmail(...)` instead of the inline minimal HTML string No schema, API contract, or dependency changes. Typecheck passes cleanly after running codegen to resolve a pre-existing import gap in @workspace/api-zod. Replit-Task-Id: 601aa064-22da-4553-9ad0-a15f82563eb6 --- artifacts/api-server/src/routes/contact.ts | 166 ++++++++++++++++++++- 1 file changed, 159 insertions(+), 7 deletions(-) diff --git a/artifacts/api-server/src/routes/contact.ts b/artifacts/api-server/src/routes/contact.ts index 5621daa..8f50978 100644 --- a/artifacts/api-server/src/routes/contact.ts +++ b/artifacts/api-server/src/routes/contact.ts @@ -53,13 +53,7 @@ router.post("/contact", contactRateLimit, async (req, res) => { ] .filter((l) => l !== undefined) .join("\n"), - htmlContent: ` -

Name: ${escapeHtml(name)}

-

E-Mail: ${escapeHtml(email)}

- ${subject ? `

Betreff: ${escapeHtml(subject)}

` : ""} -
-

${escapeHtml(message)}

- `, + htmlContent: buildNotificationEmail({ name, email, subject, message }), }); req.log.info({ to: "jh@unixweb.de", from: email }, "Contact message sent via Brevo"); @@ -103,6 +97,164 @@ function escapeHtml(text: string): string { .replace(/'/g, "'"); } +function buildNotificationEmail({ + name, + email, + subject, + message, +}: { + name: string; + email: string; + subject?: string; + message: string; +}): string { + const safeName = escapeHtml(name); + const safeEmail = escapeHtml(email); + const safeSubject = subject ? escapeHtml(subject) : null; + const safeMessage = escapeHtml(message); + + const brandBlue = "#3f4ff4"; + const textDark = "#0f172a"; + const textMid = "#334155"; + const textMuted = "#64748b"; + const textLight = "#94a3b8"; + const borderColor = "#e2e8f0"; + const bgPage = "#f1f5f9"; + const bgCard = "#ffffff"; + const bgField = "#f8fafc"; + + return ` + + + + + + Neue Kontaktanfrage + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ JH +
+

Joachim Hummel

+
+

Neue Kontaktanfrage

+

Jemand hat das Kontaktformular ausgefüllt.

+ + + + + + + + + + + + ${ + safeSubject + ? ` + + + ` + : "" + } + + + + +
+

Name

+

${safeName}

+
+

E-Mail

+

${safeEmail}

+
+

Betreff

+

${safeSubject}

+
+

Nachricht

+

${safeMessage}

+
+ + + + + + +
+ Absender antworten → +
+
+ + + + +
 
+
+ + + + +
+

Joachim Hummel

+

Webentwicklung & Softwarelösungen

+

+ jh@unixweb.de +  •  + joachim-hummel.de +

+

+ Blog +  •  + n8n Creators +

+
+
+

Diese E-Mail wurde automatisch durch das Kontaktformular generiert.

+
+
+ +`; +} + function buildConfirmationEmail(name: string): string { const safeName = escapeHtml(name); const brandBlue = "#3f4ff4";