"use client"; import { useTranslations } from "next-intl"; import { Paperclip, Download } from "lucide-react"; import { sanitizeEmailHtmlForIframe } from "@/lib/email-sanitization"; // A parsed message/rfc822 (.eml), as produced by postal-mime. Only the fields // this preview renders are typed. export type ParsedEml = { subject?: string; from?: { name?: string; address?: string }; to?: Array<{ name?: string; address?: string }>; date?: string; html?: string; text?: string; attachments?: Array<{ filename?: string; mimeType?: string; content?: ArrayBuffer | Uint8Array }>; }; function formatAddress(a?: { name?: string; address?: string }): string { if (!a) return ""; if (a.name && a.address) return `${a.name} <${a.address}>`; return a.address || a.name || ""; } function escapeHtml(s: string): string { return s .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } // Renders a .eml attachment like an email: header (from/to/subject/date) + the // body, plus the message's own attachments. The body is sanitized with // DOMPurify AND rendered in a fully-locked sandbox iframe (sandbox="" - no // scripts, no same-origin), so a script-bearing .eml can never execute in our // origin. Parsing happens in the caller (FilePreviewModal); this is pure // presentation. export function EmlPreview({ message }: { message: ParsedEml }) { const t = useTranslations("email_viewer"); const bodyDoc = message.html ? sanitizeEmailHtmlForIframe(message.html) : message.text ? `
${escapeHtml(message.text)}`
: "";
const downloadAttachment = (att: NonNullable