/** * CENTRAL EMAIL FORMATTING UTILITY * * This is the centralized email formatting utility used throughout the application. * It provides consistent handling of email content, sanitization, and text direction. * * All code that needs to format email content should import from this file. * Text direction is preserved based on content language for proper RTL/LTR display. */ import DOMPurify from 'isomorphic-dompurify'; // Instead of importing, implement the formatDateRelative function directly // import { formatDateRelative } from './date-formatter'; /** * Format a date in a relative format * Simple implementation for email display */ function formatDateRelative(date: Date): string { if (!date) return ''; try { return date.toLocaleString('en-US', { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); } catch (e) { return date.toString(); } } // Reset any existing hooks to start clean DOMPurify.removeAllHooks(); // Configure DOMPurify for English-only content (always LTR) DOMPurify.addHook('afterSanitizeAttributes', function(node) { // We no longer force LTR direction on all elements // This allows the natural text direction to be preserved if (node instanceof HTMLElement) { // Only set direction if not already specified if (!node.hasAttribute('dir')) { // Add dir attribute only if not present node.setAttribute('dir', 'auto'); } // Don't forcibly modify text alignment or direction in style attributes // This allows the component to control text direction instead } }); // Configure DOMPurify to preserve direction attributes DOMPurify.setConfig({ ADD_ATTR: ['dir'], ALLOWED_ATTR: ['style', 'class', 'id', 'dir'] }); // Note: We ensure LTR text direction is applied in the component level // when rendering email content // Interface definitions export interface EmailAddress { name: string; address: string; } export interface EmailMessage { id: string; messageId?: string; subject: string; from: EmailAddress[]; to: EmailAddress[]; cc?: EmailAddress[]; bcc?: EmailAddress[]; date: Date | string; flags?: { seen: boolean; flagged: boolean; answered: boolean; deleted: boolean; draft: boolean; }; preview?: string; content?: string; html?: string; text?: string; hasAttachments?: boolean; attachments?: any[]; folder?: string; size?: number; contentFetched?: boolean; } interface EmailContent { html?: string; text?: string; } /** * Format email addresses for display */ export function formatEmailAddresses(addresses: EmailAddress[]): string { if (!addresses || addresses.length === 0) return ''; return addresses.map(addr => addr.name && addr.name !== addr.address ? `${addr.name} <${addr.address}>` : addr.address ).join(', '); } /** * Format date for display */ export function formatEmailDate(date: Date | string | undefined): string { if (!date) return ''; try { const dateObj = typeof date === 'string' ? new Date(date) : date; return dateObj.toLocaleString('en-US', { weekday: 'short', year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); } catch (e) { return typeof date === 'string' ? date : date.toString(); } } /** * Sanitize HTML content before processing or displaying * Implements email industry standards for proper, consistent, and secure rendering * * @param html HTML content to sanitize * @returns Sanitized HTML with preserved styling and structure */ export function sanitizeHtml(html: string): string { if (!html) return ''; try { // Use DOMPurify with comprehensive email HTML standards const clean = DOMPurify.sanitize(html, { ADD_TAGS: [ 'html', 'head', 'body', 'style', 'link', 'meta', 'title', 'table', 'caption', 'col', 'colgroup', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', 'div', 'span', 'img', 'br', 'hr', 'section', 'article', 'header', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'blockquote', 'pre', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'a', 'b', 'i', 'u', 'em', 'strong', 'del', 'ins', 'mark', 'small', 'sub', 'sup', 'q', 'abbr' ], ADD_ATTR: [ 'style', 'class', 'id', 'name', 'href', 'src', 'alt', 'title', 'width', 'height', 'border', 'cellspacing', 'cellpadding', 'bgcolor', 'background', 'color', 'align', 'valign', 'dir', 'lang', 'target', 'rel', 'charset', 'media', 'colspan', 'rowspan', 'scope', 'span', 'size', 'face', 'hspace', 'vspace', 'data-*' ], KEEP_CONTENT: true, WHOLE_DOCUMENT: false, ALLOW_DATA_ATTR: true, ALLOW_UNKNOWN_PROTOCOLS: true, // Needed for some email clients FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'form', 'input', 'button', 'select', 'textarea'], FORBID_ATTR: ['onerror', 'onload', 'onclick', 'onmouseover', 'onmouseout'], FORCE_BODY: false }); // Fix common email rendering issues return clean // Fix for Outlook WebVML content .replace(/