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 ` + + + + + +
+
+
|
+