Safely parsing email files in the browser
An email file is not just text plus a few attachments. It can contain HTML, nested MIME parts, misleading filenames, inline resources, remote tracking pixels, malformed encodings, and enough data to exhaust a browser tab. Moving parsing into the browser removes an upload from the architecture, but it does not automatically make the viewer safe. It changes the security job: untrusted content is now being interpreted next to the user’s active web session. This is the checklist I use for a local EML and winmail.dat/TNEF reader. Treat every parsed field as untrusted The sender, subject, recipient, filename, MIME type, and message body all came from a file. Render headers and filenames as text, never by concatenating HTML. The same applies to errors. A parser exception can include a filename...
An email file is not just text plus a few attachments. It can contain HTML, nested MIME parts, misleading filenames, inline resources, remote tracking pixels, malformed encodings, and enough data to exhaust a browser tab. Moving parsing into the browser removes an upload from the architecture, but it does not automatically make the viewer safe. It changes the security job: untrusted content is now being interpreted next to the user’s active web session. This is the checklist I use for a local EML and winmail.dat/TNEF reader. Treat every parsed field as untrusted The sender, subject, recipient, filename, MIME type, and message body all came from a file. Render headers and filenames as text, never by concatenating HTML. The same applies to errors. A parser exception can include a filename or fragment of malformed input. Showing that message verbatim may leak data into logs or turn it into markup. Map parser failures to stable error categories, then display a controlled explanation. Normalize into one internal model EML and TNEF have different container structures, but the UI should not contain two independent security implementations. Both parsers can produce a common message model: The normalization layer is the right place to enforce per-source limits and reject unsupported structures. The viewer and download code then work against the same constrained data regardless of input format. Sanitize HTML as hostile input Email HTML was designed for mail clients, not for direct insertion into an application DOM. A conservative policy removes: scripts and event handlers; forms and interactive controls; , , and elements; styles and CSS URLs; unsafe protocols; executable or unexpected embedded content. Use a maintained sanitizer with a pinned version, but do not stop at its default configuration. Email has resource-loading behavior that a generic “safe HTML” preset may still allow. Plain text should remain the fallback. If HTML cannot be sanitized into the allowed subset, showing text is better than trying to preserve every visual detail. Rewrite local inline images Legitimate messages often reference an attachment using or . Those images can be displayed without a network request: match the reference to a parsed attachment; create a Blob from the attachment bytes; create an object URL; replace the resource reference with that local URL; revoke the URL when the message is switched, removed, cleared, or the page exits. Matching needs normalized identifiers and explicit MIME checks. Do not let an attachment’s declared filename or content location become an arbitrary URL. Keep remote images out of the DOM by default Removing a visible remote image after rendering is too late. The request may already have exposed the user’s IP address, time, user agent, and a unique tracking token. The safer sequence is: parse and sanitize the body; replace remote image sources with inert placeholders before insertion; tell the user that external images are blocked; only after an explicit action for the current message, restore allowed HTTPS sources; use a no-referrer policy. “For the current message” is important. Permission should not silently carry to another email in the batch, and it does not belong in local storage. A browser test should observe the network and assert zero remote-image requests before the click. After the click, it should allow only the expected image request and no navigation or script execution. Make downloads path-safe Attachment names can contain path separators, control characters, reserved device names, or repeated values. Normalize every name before using it in a download or ZIP archive: strip directory components; remove control and unsafe characters; provide a fallback when the result is empty; cap length; deduplicate names deterministically. ZIP creation can happen entirely in memory. Object URLs used for individual files, PDF previews, and archives should have a clear owner and lifecycle. Revoke too early and downloads fail