/** * GET /api/mail/lead-emails?leadId=[&provider=imap|archive][&account=] * GET /api/mail/lead-emails?partnerId=[&provider=…][&account=&address=] * E-mail history of a lead / contact, or of a business partner (all its addresses: * partner e-mail, invoice e-mail, contacts — ADMIN roles only). Nothing stored. * Two interchangeable providers: * - imap (default): live search in the configured mailboxes, one per `account` * - archive: the mailpiler archive (all mailboxes, one indexed lookup) * Without `account`: { status, email, name, accounts: [{ index, label }] }. * With `account`: { status, email, account, rows, folders, truncated, ms } for * that ONE source — the modal calls every source in parallel and merges the rows * as they arrive. Staff only. Never throws to the client. */ import { gateFromEvent } from '../../../utils/chatAccess' import { listMailAccounts, searchAccount } from '../../../utils/mail/leadMailbox' import { archiveAvailable, searchArchive } from '../../../utils/mail/mailArchive' import { resolveMailTarget } from '../../../utils/mail/leadEmailAddress' export default defineEventHandler(async (event) => { let token = '' try { token = (await gateFromEvent(event)).token } catch (err: any) { return { status: err?.statusCode || 403, message: 'Forbidden', accounts: [], rows: [] } } const q = getQuery(event) const provider = String(q.provider || 'imap') === 'archive' ? 'archive' : 'imap' const accounts: { index: number | string; label: string }[] = provider === 'archive' ? (archiveAvailable() ? [{ index: 'archive', label: 'Mailpiler-Archiv' }] : []) : listMailAccounts() try { const target = await resolveMailTarget(event, q, token) const { name, addresses } = target if (q.account === undefined || q.account === '') { // Without `account` the partner mode has no single address yet — report the first for the header. const email = target.email || addresses[0]?.email || '' if (provider === 'archive' && !accounts.length) return { status: 503, message: 'Mail archive not configured', email, name, accounts, addresses } return { status: 200, email, name, provider, accounts, addresses } } const email = target.email if (target.isPartner && !email) return { status: 400, message: 'Unknown address', rows: [] } const started = Date.now() if (provider === 'archive') { if (!email) return { status: 200, email, account: 'archive', rows: [], folders: 0, truncated: false } const res = await searchArchive(email) return { status: 200, email, account: 'archive', ...res, ms: Date.now() - started } } const index = Number(q.account) if (!Number.isInteger(index) || !listMailAccounts()[index]) return { status: 400, message: 'Unknown mail account', rows: [] } if (!email) return { status: 200, email, account: index, rows: [], folders: 0, truncated: false } const res = await searchAccount(index, email) return { status: 200, email, account: index, ...res, ms: Date.now() - started } } catch (err: any) { if (err?.statusCode === 403) return { status: 403, message: 'Forbidden', accounts: [], rows: [] } console.warn('[lead-emails] search failed:', err?.message || err) return { status: 502, message: err?.authenticationFailed ? 'Mailbox login failed' : (err?.message || 'Mailbox unavailable'), accounts, rows: [] } } })