import { randomUUID } from 'node:crypto' import { state } from '../state.js' import { queueContactSubmissionsWrite } from '../data.js' import { MAX_CONTACT_SUBMISSIONS } from '../config.js' export function register(app) { app.post('/api/inbound-email', (req, res) => { const secret = process.env.INBOUND_EMAIL_SECRET if (!secret) { res.status(503).json({ message: 'Inbound email not configured.' }); return } const provided = req.get('x-webhook-secret') ?? '' if (!provided || provided !== secret) { res.status(401).json({ message: 'Unauthorized.' }); return } const { from, to, subject, body, htmlBody, date, messageId, source } = req.body ?? {} if (!from || typeof from !== 'string') { res.status(400).json({ message: 'Missing from address.' }); return } // Extract display name and email address from "Name " format const fromMatch = /^(.*?)\s*<([^>]+)>$/.exec(from.trim()) const fromEmail = fromMatch ? fromMatch[2].trim() : from.trim() const fromName = fromMatch ? fromMatch[1].trim() : from.trim() // Deduplicate by messageId if provided if (messageId && typeof messageId === 'string' && messageId.trim()) { const exists = state.contactSubmissions.some(s => s.messageId === messageId.trim()) if (exists) { res.json({ ok: true, duplicate: true }); return } } const submission = { id: randomUUID(), submittedAt: date ? new Date(date).toISOString() : new Date().toISOString(), name: fromName || fromEmail, email: fromEmail, message: [subject ? `Subject: ${subject}` : '', body ?? ''].filter(Boolean).join('\n\n'), htmlBody: typeof htmlBody === 'string' && htmlBody.trim() ? htmlBody.trim() : null, messageType: 'general', subscribe: false, archived: false, source: 'inbound-email', inboundTo: typeof to === 'string' ? to : '', messageId: typeof messageId === 'string' ? messageId.trim() : '', emailStatus: { welcome: { status: 'not-applicable', lastEventAt: null, lastEventType: null, resendEmailId: null, error: null }, adminNotification: { status: 'not-applicable', lastEventAt: null, lastEventType: null, resendEmailId: null, error: null }, adminReply: { status: 'pending', lastEventAt: null, lastEventType: null, resendEmailId: null, error: null }, }, } state.contactSubmissions.unshift(submission) state.contactSubmissions = state.contactSubmissions.slice(0, MAX_CONTACT_SUBMISSIONS) queueContactSubmissionsWrite() console.log(`[inbound-email] received from ${fromEmail} — subject: ${subject ?? '(none)'}`) res.json({ ok: true }) }) }