From dc31c610caaed5321b912d11bf9f3ede392fae6a Mon Sep 17 00:00:00 2001 From: alma Date: Mon, 21 Apr 2025 16:48:54 +0200 Subject: [PATCH] mail page fix --- app/courrier/page.tsx | 181 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 146 insertions(+), 35 deletions(-) diff --git a/app/courrier/page.tsx b/app/courrier/page.tsx index cf653ba1..f9c34b9f 100644 --- a/app/courrier/page.tsx +++ b/app/courrier/page.tsx @@ -120,46 +120,157 @@ function renderEmailContent(email: Email) { const body = bodyParts.join('\r\n\r\n'); - return ( -
-
- {/* Email Header */} -
-
-
-
- {email.fromName ? `${email.fromName} <${email.from}>` : email.from} -
- {email.to && ( -
- To: {email.to} -
- )} - {email.cc && ( -
- CC: {email.cc} -
- )} -
-
- {new Date(email.date).toLocaleString('fr-FR', { - day: 'numeric', - month: 'short', - hour: '2-digit', - minute: '2-digit' - })} + // Parse headers using Infomaniak MIME decoder + const headerInfo = parseEmailHeaders(headersPart); + const boundary = extractBoundary(headersPart); + + // If it's a multipart email + if (boundary) { + try { + const parts = body.split(`--${boundary}`); + let htmlContent = ''; + let textContent = ''; + let attachments: { filename: string; content: string }[] = []; + + for (const part of parts) { + if (!part.trim()) continue; + + const [partHeaders, ...partBodyParts] = part.split('\r\n\r\n'); + if (!partHeaders || partBodyParts.length === 0) continue; + + const partBody = partBodyParts.join('\r\n\r\n'); + const contentType = extractHeader(partHeaders, 'Content-Type').toLowerCase(); + const encoding = extractHeader(partHeaders, 'Content-Transfer-Encoding').toLowerCase(); + const charset = extractHeader(partHeaders, 'charset') || 'utf-8'; + + try { + let decodedContent = ''; + if (encoding === 'base64') { + decodedContent = decodeBase64(partBody, charset); + } else if (encoding === 'quoted-printable') { + decodedContent = decodeQuotedPrintable(partBody, charset); + } else { + decodedContent = convertCharset(partBody, charset); + } + + if (contentType.includes('text/html')) { + // For HTML content, we want to preserve the HTML structure + // Only clean up problematic elements while keeping the formatting + htmlContent = decodedContent + .replace(/]*>[\s\S]*?<\/style>/gi, '') + .replace(/]*>[\s\S]*?<\/script>/gi, '') + .replace(/]*>/gi, '') + .replace(/]*>/gi, '') + .replace(/]*>/gi, '') + .replace(/]*>[\s\S]*?<\/title>/gi, '') + .replace(/]*>[\s\S]*?<\/head>/gi, '') + .replace(/]*>/gi, '') + .replace(/<\/body>/gi, '') + .replace(/]*>/gi, '') + .replace(/<\/html>/gi, ''); + } else if (contentType.includes('text/plain')) { + textContent = decodedContent; + } else if (contentType.includes('attachment') || extractHeader(partHeaders, 'Content-Disposition').includes('attachment')) { + attachments.push({ + filename: extractFilename(partHeaders) || 'unnamed_attachment', + content: decodedContent + }); + } + } catch (partError) { + console.error('Error processing email part:', partError); + continue; + } + } + + // Prefer HTML content if available + if (htmlContent) { + return ( +
+
+ {attachments.length > 0 && renderAttachments(attachments)} +
+ ); + } + + // Fall back to text content + if (textContent) { + return ( +
+
+ {textContent.split('\n').map((line: string, i: number) => ( +

{line}

+ ))}
+ {attachments.length > 0 && renderAttachments(attachments)} +
+ ); + } + } catch (multipartError) { + console.error('Error processing multipart email:', multipartError); + throw new Error('Failed to process multipart email'); + } + } + + // If it's a simple email, try to detect content type and decode + const contentType = extractHeader(headersPart, 'Content-Type').toLowerCase(); + const encoding = extractHeader(headersPart, 'Content-Transfer-Encoding').toLowerCase(); + const charset = extractHeader(headersPart, 'charset') || 'utf-8'; + + try { + let decodedBody = ''; + if (encoding === 'base64') { + decodedBody = decodeBase64(body, charset); + } else if (encoding === 'quoted-printable') { + decodedBody = decodeQuotedPrintable(body, charset); + } else { + decodedBody = convertCharset(body, charset); + } + + if (contentType.includes('text/html')) { + // For HTML content, preserve the HTML structure + const cleanedHtml = decodedBody + .replace(/]*>[\s\S]*?<\/style>/gi, '') + .replace(/]*>[\s\S]*?<\/script>/gi, '') + .replace(/]*>/gi, '') + .replace(/]*>/gi, '') + .replace(/]*>/gi, '') + .replace(/]*>[\s\S]*?<\/title>/gi, '') + .replace(/]*>[\s\S]*?<\/head>/gi, '') + .replace(/]*>/gi, '') + .replace(/<\/body>/gi, '') + .replace(/]*>/gi, '') + .replace(/<\/html>/gi, ''); + + return ( +
+
+
+ ); + } else { + return ( +
+
+ {decodedBody.split('\n').map((line: string, i: number) => ( +

{line}

+ ))}
- - {/* Email Body */} -
-
-
- ); + ); + } + } catch (decodeError) { + console.error('Error decoding email body:', decodeError); + throw new Error('Failed to decode email body'); + } } catch (error) { console.error('Error rendering email content:', error); - return
Error displaying email content
; + return ( +
+
Error displaying email content: {error instanceof Error ? error.message : 'Unknown error'}
+
+          {email.body}
+        
+
+ ); } }