/** Remove marketing preheader blocks before display (bluemonday strips display:none). */ const HIDDEN_STYLE = /display\s*:\s*none|mso-hide\s*:\s*all|max-height\s*:\s*0|opacity\s*:\s*0|visibility\s*:\s*hidden/i const HIDDEN_CLASS = /mcnPreviewText|preheader|preview-text/i const INVISIBLE_RUN = /[\u034f\u200b-\u200f\ufeff\u00a0]{4,}/g function hasSignificantChildElements(el: Element): boolean { for (const child of el.children) { const tag = child.tagName.toLowerCase() if (tag === "br" || tag === "wbr" || tag === "hr") continue return true } return false } function shouldStripElement(el: Element): boolean { if (el.hasAttribute("hidden")) return true if (el.getAttribute("aria-hidden") === "true") return true const cls = el.className?.toString() ?? "" if (HIDDEN_CLASS.test(cls)) return true const style = el.getAttribute("style") ?? "" if (!style) return false const compact = style.replace(/\s+/g, "") if ( HIDDEN_STYLE.test(style) || (compact.includes("overflow:hidden") && /max-height\s*:\s*0/.test(style)) ) { return true } if (/font-size\s*:\s*0/i.test(style) && !hasSignificantChildElements(el)) { return true } return false } export function stripHiddenEmailHtml(html: string): string { if (!html.trim() || typeof DOMParser === "undefined") { return html } try { const doc = new DOMParser().parseFromString(html, "text/html") const remove: Element[] = [] doc.body.querySelectorAll("*").forEach((el) => { if (shouldStripElement(el)) remove.push(el) }) for (const el of remove) el.remove() return doc.body.innerHTML } catch { return html } } /** Strip invisible padding; keep line breaks (do not collapse plain-text quotes). */ export function stripInvisibleTextRuns(text: string): string { return text .replace(INVISIBLE_RUN, " ") .split("\n") .map((line) => line.replace(/[^\S\n]+/g, " ").trimEnd()) .join("\n") .replace(/\n{3,}/g, "\n\n") .trim() }