"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[number]) => { if (!att.content) return; // content is a real ArrayBuffer/Uint8Array at runtime; cast for the strict // BlobPart lib type (Uint8Array vs ArrayBuffer). const url = URL.createObjectURL(new Blob([att.content as BlobPart], { type: att.mimeType || "application/octet-stream" })); const a = document.createElement("a"); a.href = url; a.download = att.filename || "attachment"; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }; return (
e.stopPropagation()} >

{message.subject || ""}

{message.from && (
{t("from")}: {formatAddress(message.from)}
)} {message.to && message.to.length > 0 && (
{t("to")}: {message.to.map(formatAddress).join(", ")}
)} {message.date && (
{t("date")}: {new Date(message.date).toLocaleString()}
)}
{bodyDoc && (