diff --git a/src/utils/feed-generator.ts b/src/utils/feed-generator.ts index e6c8ef9..261b75e 100644 --- a/src/utils/feed-generator.ts +++ b/src/utils/feed-generator.ts @@ -17,11 +17,23 @@ function parseFromAddress(from: string): { name: string; email?: string } { // the body fragment in /, not a full document. export function extractBodyContent(html: string): string { const withClose = html.match(/]*>([\s\S]*?)<\/body>/i); - if (withClose) return withClose[1]; - // Some HTML emails omit ; capture everything after the opening tag - const withoutClose = html.match(/]*>([\s\S]*)/i); - if (withoutClose) return withoutClose[1].replace(/<\/html>\s*$/i, ""); - return html; + const body = withClose + ? withClose[1] + : (() => { + const withoutClose = html.match(/]*>([\s\S]*)/i); + return withoutClose + ? withoutClose[1].replace(/<\/html>\s*$/i, "") + : html; + })(); + // Strip mso-* properties from inline styles (Office HTML — triggers feed validator warnings) + return body.replace(/\bstyle="([^"]*)"/gi, (_match, style: string) => { + const cleaned = style + .split(";") + .map((p) => p.trim()) + .filter((p) => p && !/^mso-/i.test(p)) + .join("; "); + return cleaned ? `style="${cleaned}"` : ""; + }); } function buildFeed( @@ -56,13 +68,13 @@ function buildFeed( }); for (const email of emails) { - const uniqueId = `${email.receivedAt}-${Buffer.from(email.subject).toString("base64").substring(0, 10)}`; + const entryUrl = `${baseUrl}/entries/${feedId}/${email.receivedAt}`; const firstAttachment = email.attachments?.[0]; const bodyContent = extractBodyContent(email.content); feed.addItem({ title: email.subject, - id: uniqueId, - link: `${baseUrl}/entries/${feedId}/${email.receivedAt}`, + id: entryUrl, + link: entryUrl, description: bodyContent, content: bodyContent, author: [parseFromAddress(email.from)],