feat: echo submitted message back in confirmation email

Task #18 — Send a copy of the submitted message back to the contact in the confirmation email.

Changes made to artifacts/api-server/src/routes/contact.ts:

- Updated buildConfirmationEmail() signature from (name: string) to
  ({ name, subject, message }) so it can accept and render the original submission.

- Added a visually distinct "Ihre Nachricht" quoted block to the HTML template:
  - Light gray background (#f8fafc) matching the existing bgField colour
  - Subtle 3px left border (#e2e8f0) styled as a blockquote
  - Rounded right corners (border-radius: 0 6px 6px 0)
  - ALL-CAPS label "IHRE NACHRICHT" in the same style as field labels elsewhere
  - Optional subject line rendered in semi-bold if provided
  - Message body with white-space:pre-wrap to preserve line breaks

- All user-supplied values (subject, message) passed through the existing
  escapeHtml() helper — XSS-safe.

- Updated the plain-text fallback: adds a "—" delimited quoted section
  with optional "Betreff:" line before the message body.

- Updated the call site to pass { name, subject, message } to
  buildConfirmationEmail().

No new dependencies. Pre-existing TS error (SendContactMessageBody missing
from @workspace/api-zod) is unrelated to this task and unchanged.

Replit-Task-Id: 63279220-bb35-4721-bbd6-86182301a697
This commit is contained in:
joachimhummel
2026-05-15 17:14:35 +00:00
parent 565cdf975c
commit d34902cd5f

View File

@@ -67,13 +67,19 @@ router.post("/contact", contactRateLimit, async (req, res) => {
"",
"vielen Dank für Ihre Nachricht! Ich habe Ihre Anfrage erhalten und melde mich in der Regel innerhalb von 12 Werktagen bei Ihnen.",
"",
"Zur Erinnerung, hier ist Ihre Nachricht:",
"—",
...(subject ? [`Betreff: ${subject}`, ""] : []),
message,
"—",
"",
"Mit freundlichen Grüßen",
"Joachim Hummel",
"",
"—",
"jh@unixweb.de",
].join("\n"),
htmlContent: buildConfirmationEmail(name),
htmlContent: buildConfirmationEmail({ name, subject, message }),
});
req.log.info({ to: email }, "Confirmation email sent to sender via Brevo");
@@ -255,8 +261,18 @@ function buildNotificationEmail({
</html>`;
}
function buildConfirmationEmail(name: string): string {
function buildConfirmationEmail({
name,
subject,
message,
}: {
name: string;
subject?: string;
message: string;
}): string {
const safeName = escapeHtml(name);
const safeSubject = subject ? escapeHtml(subject) : null;
const safeMessage = escapeHtml(message);
const brandBlue = "#3f4ff4";
const textDark = "#0f172a";
const textMid = "#334155";
@@ -265,6 +281,7 @@ function buildConfirmationEmail(name: string): string {
const borderColor = "#e2e8f0";
const bgPage = "#f1f5f9";
const bgCard = "#ffffff";
const bgQuote = "#f8fafc";
return `<!DOCTYPE html>
<html lang="de" xmlns="http://www.w3.org/1999/xhtml">
@@ -301,7 +318,24 @@ function buildConfirmationEmail(name: string): string {
<p style="margin:0 0 6px;font-size:22px;font-weight:700;color:${textDark};line-height:1.3;">Vielen Dank, ${safeName}!</p>
<p style="margin:0 0 20px;font-size:13px;font-weight:500;color:${brandBlue};letter-spacing:0.3px;">Ihre Anfrage ist eingegangen.</p>
<p style="margin:0 0 16px;font-size:15px;line-height:1.75;color:${textMid};">Schön, dass Sie sich gemeldet haben. Ich habe Ihre Nachricht erhalten und werde mich in der Regel innerhalb von <strong style="color:${textDark};">12 Werktagen</strong> bei Ihnen melden.</p>
<p style="margin:0 0 32px;font-size:15px;line-height:1.75;color:${textMid};">Bis dahin können Sie gerne mein Portfolio besuchen oder mir direkt eine E-Mail schicken.</p>
<p style="margin:0 0 24px;font-size:15px;line-height:1.75;color:${textMid};">Bis dahin können Sie gerne mein Portfolio besuchen oder mir direkt eine E-Mail schicken.</p>
<!-- ── Quoted message ── -->
<table width="100%" cellpadding="0" cellspacing="0" border="0" role="presentation" style="margin-bottom:32px;">
<tr>
<td style="padding-left:4px;">
<table width="100%" cellpadding="0" cellspacing="0" border="0" role="presentation" style="background-color:${bgQuote};border-left:3px solid ${borderColor};border-radius:0 6px 6px 0;">
<tr>
<td style="padding:16px 20px;">
<p style="margin:0 0 10px;font-size:11px;font-weight:600;color:${textLight};letter-spacing:1px;text-transform:uppercase;">Ihre Nachricht</p>
${safeSubject ? `<p style="margin:0 0 8px;font-size:13px;font-weight:600;color:${textMuted};">Betreff: ${safeSubject}</p>` : ""}
<p style="margin:0;font-size:14px;line-height:1.75;color:${textMid};white-space:pre-wrap;">${safeMessage}</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- CTA button -->
<table cellpadding="0" cellspacing="0" border="0" role="presentation">