type MailAddressLookupCandidateLike = { display_name: string; email?: string | null; }; export type MailAddressValue = { name?: string | null; email: string; }; const EMAIL_PATTERN = /([^<>;,\s]+@[^<>;,\s]+)/g; export function mailLookupSuggestions(candidates: readonly MailAddressLookupCandidateLike[]): MailAddressValue[] { const seen = new Set(); const suggestions: MailAddressValue[] = []; for (const candidate of candidates) { const email = String(candidate.email ?? "").trim().toLocaleLowerCase(); if (!email || seen.has(email)) continue; seen.add(email); suggestions.push({ name: candidate.display_name || email, email }); } return suggestions; } export function mailboxHeaderAddresses(value?: string | null): MailAddressValue[] { const input = String(value ?? "").trim(); if (!input) return []; const results: MailAddressValue[] = []; const seen = new Set(); for (const match of input.matchAll(EMAIL_PATTERN)) { const email = match[1]?.replace(/[)>]+$/, "").toLocaleLowerCase(); if (!email || seen.has(email)) continue; seen.add(email); const prefix = input.slice(Math.max(0, input.lastIndexOf(",", match.index) + 1), match.index).trim(); const name = prefix.replace(/[<"']/g, "").trim() || undefined; results.push({ name, email }); } return results; } export function mailtoHref(recipients: readonly MailAddressValue[]): string { const addresses = recipients.map((recipient) => recipient.email.trim()).filter(Boolean); return `mailto:${addresses.map(encodeURIComponent).join(",")}`; }