All checks were successful
Build & Deploy / 🔍 Prepare Environment (push) Successful in 5s
Build & Deploy / 🧪 QA (push) Successful in 1m53s
Build & Deploy / 🏗️ Build (push) Successful in 2m8s
Build & Deploy / 🚀 Deploy (push) Successful in 14s
Build & Deploy / 🔔 Notifications (push) Successful in 2s
131 lines
4.1 KiB
TypeScript
131 lines
4.1 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import * as nodemailer from "nodemailer";
|
|
import directus, { ensureAuthenticated } from "@/lib/directus";
|
|
import { createItem } from "@directus/sdk";
|
|
import { getServerAppServices } from "@/lib/services/create-services.server";
|
|
|
|
export async function POST(req: Request) {
|
|
const services = getServerAppServices();
|
|
const logger = services.logger.child({ action: "contact_submission" });
|
|
|
|
try {
|
|
const { name, email, company, message, website } = await req.json();
|
|
|
|
// 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 });
|
|
}
|
|
|
|
// 1. Directus save
|
|
let directusSaved = false;
|
|
try {
|
|
await ensureAuthenticated();
|
|
await directus.request(
|
|
createItem("contact_submissions", {
|
|
name,
|
|
email,
|
|
company: company || "Nicht angegeben",
|
|
message,
|
|
}),
|
|
);
|
|
logger.info("Contact submission saved to Directus");
|
|
directusSaved = true;
|
|
} catch (directusError) {
|
|
const errorMessage =
|
|
directusError instanceof Error
|
|
? directusError.message
|
|
: String(directusError);
|
|
logger.error("Failed to save to Directus", {
|
|
error: errorMessage,
|
|
details: directusError,
|
|
});
|
|
services.errors.captureException(directusError, {
|
|
phase: "directus_save",
|
|
});
|
|
// We still try to send the email even if Directus fails
|
|
}
|
|
|
|
// 2. Email sending
|
|
try {
|
|
const { config } = await import("@/lib/config");
|
|
const transporter = nodemailer.createTransport({
|
|
host: config.mail.host,
|
|
port: config.mail.port,
|
|
secure: config.mail.port === 465,
|
|
auth: {
|
|
user: config.mail.user,
|
|
pass: config.mail.pass,
|
|
},
|
|
});
|
|
|
|
await transporter.sendMail({
|
|
from: config.mail.from,
|
|
to: config.mail.recipients.join(",") || "info@mb-grid-solutions.com",
|
|
replyTo: email,
|
|
subject: `Kontaktanfrage von ${name}`,
|
|
text: `
|
|
Name: ${name}
|
|
Firma: ${company || "Nicht angegeben"}
|
|
E-Mail: ${email}
|
|
Zeitpunkt: ${new Date().toISOString()}
|
|
|
|
Nachricht:
|
|
${message}
|
|
`,
|
|
});
|
|
|
|
logger.info("Email 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 Directus failed AND SMTP failed, then we really have a problem
|
|
if (!directusSaved) {
|
|
return NextResponse.json(
|
|
{ error: "Systemfehler (Speicherung und Versand fehlgeschlagen)" },
|
|
{ status: 500 },
|
|
);
|
|
}
|
|
|
|
// If Directus was successful, we tell the user "Ok" but we know internally it was a partial failure
|
|
await services.notifications.notify({
|
|
title: "🚨 SMTP Fehler (Kontaktformular)",
|
|
message: `Anfrage von ${name} (${email}) in Directus gespeichert, aber E-Mail-Versand fehlgeschlagen: ${smtpError instanceof Error ? smtpError.message : String(smtpError)}`,
|
|
priority: 8,
|
|
});
|
|
}
|
|
|
|
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 },
|
|
);
|
|
}
|
|
}
|