import { NextResponse } from "next/server"; import { getPayload } from "payload"; import configPromise from "@payload-config"; import { getServerAppServices } from "@/lib/services/create-services.server"; import { render, ContactFormNotification, ConfirmationMessage, } from "@mintel/mail"; import React from "react"; export async function POST(req: Request) { const services = getServerAppServices(); const logger = services.logger.child({ action: "contact_submission" }); // Set analytics context from request headers for high-fidelity server-side tracking if (services.analytics.setServerContext) { services.analytics.setServerContext({ userAgent: req.headers.get("user-agent") || undefined, language: req.headers.get("accept-language")?.split(",")[0] || undefined, referrer: req.headers.get("referer") || undefined, ip: req.headers.get("x-forwarded-for")?.split(",")[0] || undefined, }); } try { const { name, email, company, message, website } = await req.json(); // Track attempt services.analytics.track("contact-form-attempt"); // Honeypot check if (website) { logger.info("Spam detected (honeypot)"); return NextResponse.json({ message: "Ok" }); } // Validation if (!name || name.length < 2 || name.length > 100) { return NextResponse.json({ error: "Ungültiger Name" }, { status: 400 }); } if (!email || !/^\S+@\S+\.\S+$/.test(email)) { return NextResponse.json({ error: "Ungültige E-Mail" }, { status: 400 }); } if (!message || message.length < 20) { return NextResponse.json({ error: "message_too_short" }, { status: 400 }); } if (message.length > 4000) { return NextResponse.json({ error: "message_too_long" }, { status: 400 }); } const payload = await getPayload({ config: configPromise }); // 1. Payload save let payloadSaved = false; try { await payload.create({ collection: "form-submissions", data: { name, email, company: company || "Nicht angegeben", message, }, }); logger.info("Contact submission saved to PayloadCMS"); payloadSaved = true; } catch (payloadError) { const errorMessage = payloadError instanceof Error ? payloadError.message : String(payloadError); logger.error("Failed to save to Payload", { error: errorMessage, details: payloadError, }); services.errors.captureException(payloadError, { phase: "payload_save" }); } // 2. Email sending via Payload (which uses configured nodemailer) try { const { config } = await import("@/lib/config"); const clientName = "MB Grid Solutions"; // 2a. Notification to MB Grid const notificationHtml = await render( React.createElement(ContactFormNotification, { name, email, message, company, }), ); await payload.sendEmail({ from: config.mail.from, to: config.mail.recipients.join(",") || process.env.CONTACT_RECIPIENT || "info@mb-grid-solutions.com", replyTo: email, subject: `Kontaktanfrage von ${name}`, html: notificationHtml, }); // 2b. Confirmation to the User try { const confirmationHtml = await render( React.createElement(ConfirmationMessage, { name, clientName, }), ); await payload.sendEmail({ from: config.mail.from, to: email, subject: `Ihre Kontaktanfrage bei ${clientName}`, html: confirmationHtml, }); } catch (confirmError) { logger.warn( "Failed to send confirmation email, but notification was sent", { error: confirmError }, ); } logger.info("Emails sent successfully"); // Notify success for important leads await services.notifications.notify({ title: "📩 Neue Kontaktanfrage", message: `Anfrage von ${name} (${email}) erhalten.\nFirma: ${company || "Nicht angegeben"}`, priority: 5, }); } catch (smtpError) { logger.error("SMTP Error", { error: smtpError }); services.errors.captureException(smtpError, { phase: "smtp_send" }); if (!payloadSaved) { return NextResponse.json( { error: "Systemfehler (Speicherung und Versand fehlgeschlagen)" }, { status: 500 }, ); } await services.notifications.notify({ title: "🚨 SMTP Fehler (Kontaktformular)", message: `Anfrage von ${name} (${email}) in Payload gespeichert, aber E-Mail-Versand fehlgeschlagen: ${smtpError instanceof Error ? smtpError.message : String(smtpError)}`, priority: 8, }); } // Track success services.analytics.track("contact-form-success", { has_company: Boolean(company), }); return NextResponse.json({ message: "Ok" }); } catch (error) { logger.error("Global API Error", { error }); services.errors.captureException(error, { phase: "api_global" }); return NextResponse.json( { error: "Interner Serverfehler" }, { status: 500 }, ); } }