import { EmailMessage, EmailContent, EmailAddress, LegacyEmailMessage } from '@/types/email'; import { sanitizeHtml } from './email-formatter'; /** * Adapts a legacy email format to the standardized EmailMessage format */ export function adaptLegacyEmail(email: LegacyEmailMessage): EmailMessage { if (!email) { throw new Error('Cannot adapt null or undefined email'); } // Process content const content: EmailContent = normalizeContent(email); // Convert email addresses to string format as required by EmailMessage interface const from = formatAddressesToString(normalizeAddresses(email.from)); const to = formatAddressesToString(normalizeAddresses(email.to)); const cc = email.cc ? formatAddressesToString(normalizeAddresses(email.cc)) : undefined; const bcc = email.bcc ? formatAddressesToString(normalizeAddresses(email.bcc)) : undefined; // Convert flags if needed const flags: string[] = normalizeFlags(email.flags); // Create standardized email message return { id: email.id || '', from, to, cc, bcc, subject: email.subject || '', content, date: email.date || new Date().toISOString(), flags, attachments: normalizeAttachments(email.attachments), _originalFormat: email // Store original for debugging }; } /** * Detects if an email is in MIME format */ export function isMimeFormat(email: any): boolean { // Simple check for MIME format indicators if (!email) return false; // Check for typical MIME format properties return !!( email.mimeContent || (email.headers && (email.bodyParts || email.body)) || (typeof email.content === 'string' && email.content.includes('MIME-Version')) ); } /** * Adapts a MIME format email to the standardized EmailMessage format * This is a placeholder - actual implementation would depend on the MIME library */ export function adaptMimeEmail(mimeEmail: any): EmailMessage { // Placeholder implementation const content: EmailContent = { text: mimeEmail.text || mimeEmail.plainText || '', html: mimeEmail.html || undefined, isHtml: !!mimeEmail.html, direction: 'ltr' }; return { id: mimeEmail.id || '', from: mimeEmail.from || '', to: mimeEmail.to || '', cc: mimeEmail.cc, bcc: mimeEmail.bcc, subject: mimeEmail.subject || '', content, date: mimeEmail.date || new Date().toISOString(), flags: [], _originalFormat: mimeEmail }; } /** * Formats an array of EmailAddress objects to string format */ function formatAddressesToString(addresses: EmailAddress[]): string { return addresses.map(addr => { if (addr.name && addr.name !== addr.address) { return `${addr.name} <${addr.address}>`; } return addr.address; }).join(', '); } /** * Normalizes content from various formats into the standard EmailContent format */ function normalizeContent(email: LegacyEmailMessage): EmailContent { // Default content structure const normalizedContent: EmailContent = { html: undefined, text: '', isHtml: false, direction: 'ltr' }; try { // Extract content based on standardized property hierarchy let htmlContent = ''; let textContent = ''; let isHtml = false; // Step 1: Extract content from the various possible formats if (email.content && typeof email.content === 'object') { isHtml = !!email.content.html; htmlContent = 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('')); htmlContent = isHtml ? email.content : ''; textContent = isHtml ? '' : email.content; } else if (email.html) { isHtml = true; htmlContent = email.html; textContent = email.text || email.plainText || ''; } else if (email.text || email.plainText) { isHtml = false; htmlContent = ''; textContent = email.text || email.plainText || ''; } else if (email.formattedContent) { // Assume formattedContent is already HTML isHtml = true; htmlContent = email.formattedContent; textContent = ''; } // Step 2: Set the normalized content properties normalizedContent.isHtml = isHtml; // Always ensure we have text content if (textContent) { normalizedContent.text = textContent; } else if (htmlContent) { // Extract text from HTML if we don't have plain text if (typeof document !== 'undefined') { // Browser environment const tempDiv = document.createElement('div'); tempDiv.innerHTML = htmlContent; normalizedContent.text = tempDiv.textContent || tempDiv.innerText || ''; } else { // Server environment - do simple strip normalizedContent.text = htmlContent .replace(/<[^>]*>/g, '') .replace(/ /g, ' ') .replace(/\s+/g, ' ') .trim(); } } // If we have HTML content, sanitize it if (isHtml && htmlContent) { normalizedContent.html = sanitizeHtml(htmlContent); } // Determine text direction normalizedContent.direction = detectTextDirection(normalizedContent.text); return normalizedContent; } catch (error) { console.error('Error normalizing email content:', error); // Return minimal valid content in case of error return { text: 'Error loading email content', isHtml: false, direction: 'ltr' }; } } /** * Detects the text direction (LTR or RTL) based on the content */ function detectTextDirection(text: string): 'ltr' | 'rtl' { // Simple RTL detection for common RTL languages // This is a basic implementation and can be enhanced const rtlChars = /[\u0591-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC]/; return rtlChars.test(text) ? 'rtl' : 'ltr'; } /** * Normalizes email addresses to the EmailAddress format */ function normalizeAddresses(addresses: string | EmailAddress[] | undefined): EmailAddress[] { if (!addresses) { return []; } if (Array.isArray(addresses)) { // If already in EmailAddress format, return as is if (addresses.length > 0 && typeof addresses[0] === 'object') { return addresses as EmailAddress[]; } // Otherwise convert string elements to EmailAddress objects return addresses.map((addr: any) => { if (typeof addr === 'string') { return { name: addr.split('@')[0] || '', address: addr }; } return addr; }); } // Handle single address as string if (typeof addresses === 'string') { // Check if format is "Name " const match = addresses.match(/^([^<]+)<([^>]+)>$/); if (match) { return [{ name: match[1].trim(), address: match[2].trim() }]; } return [{ name: addresses.split('@')[0] || '', address: addresses }]; } return []; } /** * Normalizes email flags to string array format */ function normalizeFlags(flags: string[] | Record | undefined): string[] { if (!flags) { return []; } if (Array.isArray(flags)) { return flags; } // Convert object format to array return Object.entries(flags) .filter(([_, value]) => value === true) .map(([key]) => key); } /** * Normalizes attachments to the expected format */ function normalizeAttachments(attachments: any[] | undefined): Array<{ filename: string; contentType: string; encoding?: string; content?: string; }> { if (!attachments || !Array.isArray(attachments)) { return []; } return attachments.map(att => ({ filename: att.filename || att.name || 'unknown', contentType: att.contentType || 'application/octet-stream', encoding: att.encoding, content: att.content })); }