import { PayloadRequest } from "payload"; export const bulkMailEndpointHandler = async (req: PayloadRequest) => { try { let body: any = {}; if (req.body) { try { body = (await req.json?.()) || {}; } catch (_e) { body = req.body; } } const { contactIds, instructions, isTest } = body; if (!req.user) { return Response.json( { success: false, error: "Unauthorized" }, { status: 401 }, ); } if (!Array.isArray(contactIds) || contactIds.length === 0) { return Response.json( { success: false, error: "No contacts selected" }, { status: 400 }, ); } const OPENROUTER_KEY = process.env.OPENROUTER_KEY || process.env.OPENROUTER_API_KEY; if (!OPENROUTER_KEY) { return Response.json( { success: false, error: "Missing OPENROUTER_API_KEY" }, { status: 500 }, ); } const sentEmails = []; const interactions = []; for (const contactId of contactIds) { // Fetch contact with account populated const contact = await req.payload.findByID({ collection: "crm-contacts", id: contactId, depth: 1, }); if (!contact || !contact.email) continue; const account = contact.account as any; const accountInfo = account ? ` Company Name: ${account.name || "Unknown"} Website: ${account.website || "Unknown"} Industry: ${account.industry || "Unknown"} Website Status: ${account.websiteStatus || "Unknown"} Internal Notes: ${account.notes || "None"} ` : "No company information available."; const prompt = `You are an expert sales/business development AI assistant. Write a professional, personalized German B2B outreach email ("Anschreiben"). CONTEXT ABOUT THE CONTACT: Name: ${contact.fullName || contact.firstName || "Unknown"} Role: ${contact.role || "Unknown"} CONTEXT ABOUT THEIR COMPANY: ${accountInfo} USER INSTRUCTIONS / GOAL OF THE EMAIL: ${instructions} CRITICAL INSTRUCTIONS: 1. Write the email subject on the FIRST line as: "SUBJECT: " 2. The rest of the message should be the email body. 3. Keep it professional and natural in German (Sie-form unless you think Du is appropriate based on the industry, but prefer Sie). 4. Output only the email text, no markdown code blocks around it. No extra chit-chat. `; const res = await fetch("https://openrouter.ai/api/v1/chat/completions", { method: "POST", headers: { Authorization: `Bearer ${OPENROUTER_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ model: "google/gemini-3-flash-preview", messages: [{ role: "user", content: prompt }], }), }); const data = await res.json(); const generatedText = data.choices?.[0]?.message?.content?.trim() || ""; if (!generatedText) { console.error("AI Generation failed for contact", contactId); continue; } // Parse subject and body const lines = generatedText.split("\n"); let subject = "Information von Mintel"; let bodyText = generatedText; if (lines[0].startsWith("SUBJECT:")) { subject = lines[0].replace("SUBJECT:", "").trim(); bodyText = lines.slice(1).join("\n").trim(); } // Use a simple HTML wrapper to preserve line breaks const htmlBody = `

${bodyText.replace(/\n/g, "
")}

`; const targetEmail = isTest ? req.user.email : contact.email; // Send the email await req.payload.sendEmail({ to: targetEmail, subject: (isTest ? "[TEST] " : "") + subject, html: htmlBody, }); sentEmails.push({ contactId, email: targetEmail }); if (!isTest) { // Log interaction const interaction = await req.payload.create({ collection: "crm-interactions", data: { type: "email", subject: `Outbound AI Mail: ${subject}`, date: new Date().toISOString(), contact: contact.id, account: account?.id, content: { root: { type: "root", format: "", indent: 0, version: 1, direction: "ltr", children: [ { type: "paragraph", format: "", indent: 0, version: 1, direction: "ltr", children: [ { type: "text", mode: "normal", style: "", detail: 0, format: 0, text: bodyText, version: 1, }, ], }, ], }, }, }, }); interactions.push(interaction.id); // Update lead temperature to "warm" if it's currently cold and the status is lead if ( account && account.status === "lead" && account.leadTemperature === "cold" ) { await req.payload.update({ collection: "crm-accounts", id: account.id, data: { leadTemperature: "warm", }, }); } } } return Response.json({ success: true, sentEmails, testMode: isTest }); } catch (e: any) { console.error("Bulk Mail error", e); return Response.json({ success: false, error: e.message }, { status: 500 }); } };