mirror of
https://github.com/LogicLabs-OU/OpenArchiver.git
synced 2026-04-06 00:31:57 +02:00
Fixed inline attachment images not displaying in the email preview by modifying EmailPreview.svelte.
The email HTML references embedded images via `cid:` URIs (e.g., `src="cid:ii_19c6d5f8d5eee7bd6d91"`), but the component never resolved those `cid:` references to actual image data, even though `postal-mime` already parses inline attachments with their `contentId` and binary `content`. The `emailHtml` derived value now calls `resolveContentIdReferences()` before rendering, so inline/embedded images display correctly in the iframe preview.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import PostalMime, { type Email } from 'postal-mime';
|
||||
import PostalMime, { type Attachment, type Email } from 'postal-mime';
|
||||
import type { Buffer } from 'buffer';
|
||||
import { t } from '$lib/translations';
|
||||
import { encode } from 'html-entities';
|
||||
@@ -13,11 +13,57 @@
|
||||
let parsedEmail: Email | null = $state(null);
|
||||
let isLoading = $state(true);
|
||||
|
||||
/** Converts an ArrayBuffer to a base64-encoded string. */
|
||||
function arrayBufferToBase64(buffer: ArrayBuffer): string {
|
||||
const bytes = new Uint8Array(buffer);
|
||||
let binary = '';
|
||||
for (let i = 0; i < bytes.byteLength; i++) {
|
||||
binary += String.fromCharCode(bytes[i]);
|
||||
}
|
||||
return btoa(binary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces `cid:` references in HTML with inline base64 data URIs
|
||||
* sourced from the parsed email attachments. This ensures that images
|
||||
* embedded as MIME parts (disposition: inline) render correctly in the
|
||||
* iframe preview.
|
||||
*/
|
||||
function resolveContentIdReferences(html: string, attachments: Attachment[]): string {
|
||||
if (!attachments || attachments.length === 0) return html;
|
||||
|
||||
const cidMap = new Map<string, string>();
|
||||
for (const attachment of attachments) {
|
||||
if (!attachment.contentId) continue;
|
||||
|
||||
const cid = attachment.contentId.replace(/^<|>$/g, '');
|
||||
|
||||
let base64Content: string;
|
||||
if (typeof attachment.content === 'string') {
|
||||
base64Content = attachment.content;
|
||||
} else {
|
||||
base64Content = arrayBufferToBase64(attachment.content);
|
||||
}
|
||||
|
||||
cidMap.set(cid, `data:${attachment.mimeType};base64,${base64Content}`);
|
||||
}
|
||||
|
||||
if (cidMap.size === 0) return html;
|
||||
|
||||
return html.replace(/cid:([^\s"']+)/gi, (match, cid) => {
|
||||
return cidMap.get(cid) ?? match;
|
||||
});
|
||||
}
|
||||
|
||||
// By adding a <base> tag, all relative and absolute links in the HTML document
|
||||
// will open in a new tab by default.
|
||||
let emailHtml = $derived(() => {
|
||||
if (parsedEmail && parsedEmail.html) {
|
||||
return `<base target="_blank" />${parsedEmail.html}`;
|
||||
const resolvedHtml = resolveContentIdReferences(
|
||||
parsedEmail.html,
|
||||
parsedEmail.attachments
|
||||
);
|
||||
return `<base target="_blank" />${resolvedHtml}`;
|
||||
} else if (parsedEmail && parsedEmail.text) {
|
||||
// display raw text email body in html
|
||||
const safeHtmlContent: string = encode(parsedEmail.text);
|
||||
|
||||
Reference in New Issue
Block a user