Preserve email formatting in ticket display; paste-to-attach screenshots in replies

Inbound HTML emails were being flattened through html-to-text for display,
which lost all formatting and — for images embedded as data: URIs — leaked
the raw base64 as visible "[data:image/png;base64,...]" link text (an
Outlook/webmail screenshot-paste artifact). Customer messages now also
store a sanitized HTML rendering (messages.body_html) that preserves the
sender's fonts/colors/layout and shows inline images (data: URIs render
natively; cid: references are rewritten to the matching attachment's
serving URL via a new attachments.content_id column). Sanitization is a
tag/style allowlist (lib/mail/sanitize-html.ts, covered by
sanitize-html.test.ts) — no script/event handlers/javascript: hrefs, no
layout-breaking CSS. The plain-text fallback (used for channels other than
email) also drops image/data-URI link text via html-to-text selectors, for
the same underlying bug on that path.

Also: pasting a screenshot (Ctrl+V) into the agent reply box now attaches
it directly, reusing the existing attachment-upload/email-delivery path —
no more "save to disk, then click attach" round trip.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GteWhnWKTmnXcsd5jx6H7u
This commit is contained in:
ogrechkoandClaude Sonnet 5 committed 2026-08-19 07:40:19 +00:00
1 parent 019f4a1b53
commit 955fdeee41
14 files changed
+1332 -8

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
// message.bodyHtml is already sanitized server-side (see
// lib/mail/sanitize-html.ts) before it's ever stored — this only adds
// layout containment so an email's inline styles/tables can't blow out the
// message bubble's width.
export function MessageBodyHtml({ html, className = "" }: { html: string; className?: string }) {
return (
<div
className={`max-w-full overflow-x-auto text-sm break-words [&_img]:max-w-full [&_table]:max-w-full [&_td]:break-words [&_th]:break-words ${className}`}
dangerouslySetInnerHTML={{ __html: html }}
/>
);
}