import { sanitizeEmailHtml, blockRemoteImages, unblockRemoteImages } from "./sanitizer"; import { resolveInlineImages, buildReaderDocument, type InlineImages } from "./emailBody"; /** What it takes to draw a message's body. */ export interface RenderableBody { html: string; inline_images?: InlineImages; } /** * The document the reader frame renders, or null for a message with no HTML. * * Order matters: sanitise first so nothing downstream handles untrusted * markup, then resolve the message's own inline parts, then block or restore * remote sources - which is the only part the reader chooses. */ export function messageDocument(message: RenderableBody, showImages: boolean): string | null { if (!message.html) return null; const sanitized = sanitizeEmailHtml(message.html); if (!sanitized) return null; const withInline = resolveInlineImages(sanitized, message.inline_images ?? {}); const body = showImages ? unblockRemoteImages(withInline) : blockRemoteImages(withInline); return buildReaderDocument(body); } /** * Whether anything was actually held back, so the privacy bar is not shown over * a message that has no remote content at all. */ export function hasBlockedRemoteContent(message: RenderableBody): boolean { if (!message.html) return false; const sanitized = resolveInlineImages(sanitizeEmailHtml(message.html), message.inline_images ?? {}); return blockRemoteImages(sanitized) !== sanitized; }