diff --git a/components/email/RichEmailEditor.tsx b/components/email/RichEmailEditor.tsx index 27d1ce96..64b12a6e 100644 --- a/components/email/RichEmailEditor.tsx +++ b/components/email/RichEmailEditor.tsx @@ -41,15 +41,37 @@ function cleanupTableStructures(htmlContent: string): string { htmlContent.includes('blockquote') || htmlContent.includes('wrote:')); if (hasComplexTables) { - console.log(`Converting ${tables.length} tables in complex email content to prevent Quill errors`); + console.log(`Found ${tables.length} tables in complex email content`); + let convertedCount = 0; tables.forEach(table => { - // Skip simple tables that are likely to work fine with Quill - if (table.rows.length <= 1 && table.querySelectorAll('td, th').length <= 3) { + // Preserve the main forwarded email header table + if (isForwardedEmail && + table.innerHTML.includes('From:') && + table.innerHTML.includes('Date:') && + table.innerHTML.includes('Subject:')) { + console.log('Preserving forwarded email header table'); + // Ensure the table has proper styling + table.setAttribute('style', 'margin: 10px 0; border-collapse: collapse; font-size: 13px; color: #333;'); return; } - // Create a replacement div + // Skip simple tables that are likely to work fine with Quill + // Check more conditions to identify simple tables + const isSimpleTable = + table.rows.length <= 3 && + table.querySelectorAll('td, th').length <= 6 && + !table.querySelector('table') && // No nested tables + !table.innerHTML.includes('style=') && // No complex styling + !table.innerHTML.includes('rowspan') && // No rowspan + !table.innerHTML.includes('colspan'); // No colspan + + if (isSimpleTable) { + console.log('Preserving simple table structure'); + return; + } + + // Convert complex tables to divs const replacementDiv = document.createElement('div'); replacementDiv.className = 'converted-table'; replacementDiv.style.border = '1px solid #ddd'; @@ -62,9 +84,11 @@ function cleanupTableStructures(htmlContent: string): string { // Replace the table with the div if (table.parentNode) { table.parentNode.replaceChild(replacementDiv, table); + convertedCount++; } }); + console.log(`Converted ${convertedCount} complex tables to divs to prevent Quill errors`); return tempDiv.innerHTML; } diff --git a/lib/utils/dom-purify-config.ts b/lib/utils/dom-purify-config.ts index a57b366c..04686d19 100644 --- a/lib/utils/dom-purify-config.ts +++ b/lib/utils/dom-purify-config.ts @@ -39,7 +39,11 @@ export function configureDOMPurify() { // Blockquote attributes 'cite', 'datetime', // Form elements attributes (read-only) - 'readonly', 'disabled', 'selected', 'checked', 'multiple', 'wrap' + 'readonly', 'disabled', 'selected', 'checked', 'multiple', 'wrap', + // Additional attributes for forwarded emails + 'style', 'class', 'id', 'dir', 'lang', 'title', + // Table attributes commonly used in email clients + 'background', 'bordercolor', 'width', 'height' ], FORBID_TAGS: [ // Remove dangerous tags diff --git a/lib/utils/email-content.ts b/lib/utils/email-content.ts index be8b5242..46decf34 100644 --- a/lib/utils/email-content.ts +++ b/lib/utils/email-content.ts @@ -301,7 +301,9 @@ export function processHtmlContent( sanitizedContent = sanitizedContent // Preserve table styling for email headers .replace(/]*)>/g, '') - .replace(/]*)>/g, ''); + .replace(/]*)>/g, '') + // Ensure blockquote styling is preserved + .replace(/]*)>/g, ''); } // Fix common email client quirks without breaking cid: URLs @@ -318,6 +320,19 @@ export function processHtmlContent( // Remove excessive whitespace from the HTML string itself .replace(/>\s+ <'); + // Additional processing for quoted content in replies/forwards + if (sanitizedContent.includes('blockquote')) { + console.log('Enhancing blockquote styling'); + sanitizedContent = sanitizedContent + // Ensure blockquotes have proper styling + .replace(/]*)>/g, (match, attrs) => { + if (match.includes('style=')) { + return match; // Already has style + } + return ``; + }); + } + return { sanitizedContent, hasImages: sanitizedContent.includes('