102 lines
4.3 KiB
TypeScript
102 lines
4.3 KiB
TypeScript
import DOMPurify from 'dompurify';
|
|
|
|
/**
|
|
* Format and standardize email content for display following email industry standards.
|
|
* This function handles various email content formats and ensures proper display
|
|
* including support for HTML emails, plain text emails, RTL languages, and email client quirks.
|
|
*/
|
|
export function formatEmailContent(email: any): string {
|
|
if (!email) {
|
|
console.log('formatEmailContent: No email provided');
|
|
return '';
|
|
}
|
|
|
|
try {
|
|
// Get the content in order of preference with proper fallbacks
|
|
let content = '';
|
|
let isHtml = false;
|
|
let textContent = '';
|
|
|
|
// Extract content based on standardized property hierarchy
|
|
if (email.content && typeof email.content === 'object') {
|
|
isHtml = !!email.content.html;
|
|
content = email.content.html || '';
|
|
textContent = email.content.text || '';
|
|
} else if (typeof email.content === 'string') {
|
|
// Check if the string content is HTML
|
|
isHtml = email.content.trim().startsWith('<') &&
|
|
(email.content.includes('<html') ||
|
|
email.content.includes('<body') ||
|
|
email.content.includes('<div') ||
|
|
email.content.includes('<p>'));
|
|
content = email.content;
|
|
textContent = email.content;
|
|
} else if (email.html) {
|
|
isHtml = true;
|
|
content = email.html;
|
|
textContent = email.text || '';
|
|
} else if (email.text) {
|
|
isHtml = false;
|
|
content = '';
|
|
textContent = email.text;
|
|
} else if (email.formattedContent) {
|
|
// Assume formattedContent is already HTML
|
|
isHtml = true;
|
|
content = email.formattedContent;
|
|
textContent = '';
|
|
}
|
|
|
|
// If we have HTML content, sanitize and standardize it
|
|
if (isHtml && content) {
|
|
// Sanitize with industry-standard email tags and attributes
|
|
const sanitizedContent = DOMPurify.sanitize(content, {
|
|
ADD_TAGS: [
|
|
'style', 'table', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th',
|
|
'caption', 'col', 'colgroup', 'div', 'span', 'img', 'br', 'hr',
|
|
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'blockquote', 'pre',
|
|
'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'a', 'b', 'i', 'u', 'em',
|
|
'strong', 'del', 'ins', 'sub', 'sup', 'small', 'mark', 'q'
|
|
],
|
|
ADD_ATTR: [
|
|
'class', 'style', 'id', 'href', 'src', 'alt', 'title', 'width', 'height',
|
|
'border', 'cellspacing', 'cellpadding', 'bgcolor', 'color', 'dir', 'lang',
|
|
'align', 'valign', 'span', 'colspan', 'rowspan', 'target', 'rel',
|
|
'background', 'data-*'
|
|
],
|
|
ALLOW_DATA_ATTR: true,
|
|
WHOLE_DOCUMENT: false,
|
|
RETURN_DOM: false,
|
|
FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'form', 'input', 'textarea', 'select', 'button'],
|
|
FORBID_ATTR: ['onerror', 'onload', 'onclick', 'onmouseover', 'onmouseout']
|
|
});
|
|
|
|
// Wrap the content in standard email container with responsive styling
|
|
return `
|
|
<div class="email-content" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; line-height: 1.6; color: #333; max-width: 100%; word-wrap: break-word;">
|
|
${sanitizedContent}
|
|
</div>
|
|
`;
|
|
}
|
|
// If we only have text content, format it properly
|
|
else if (textContent) {
|
|
// Format plain text with proper line breaks and paragraphs
|
|
const formattedText = textContent
|
|
.replace(/\r\n|\r|\n/g, '<br>') // Convert all newlines to <br>
|
|
.replace(/((?:<br>){2,})/g, '</p><p>') // Convert multiple newlines to paragraphs
|
|
.replace(/<br><\/p>/g, '</p>') // Fix any <br></p> combinations
|
|
.replace(/<p><br>/g, '<p>'); // Fix any <p><br> combinations
|
|
|
|
return `
|
|
<div class="email-content plain-text" style="font-family: monospace; white-space: pre-wrap; line-height: 1.5; color: #333; max-width: 100%; word-wrap: break-word;">
|
|
<p>${formattedText}</p>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// Default case: empty or unrecognized content
|
|
return '<div class="email-content-empty">No content available</div>';
|
|
} catch (error) {
|
|
console.error('formatEmailContent: Error formatting email content:', error);
|
|
return '<div class="email-content-error">Error displaying email content</div>';
|
|
}
|
|
}
|