mail page fix
This commit is contained in:
parent
e5e82c93a0
commit
dc31c610ca
@ -120,46 +120,157 @@ function renderEmailContent(email: Email) {
|
|||||||
|
|
||||||
const body = bodyParts.join('\r\n\r\n');
|
const body = bodyParts.join('\r\n\r\n');
|
||||||
|
|
||||||
return (
|
// Parse headers using Infomaniak MIME decoder
|
||||||
<div className="flex-1 overflow-y-auto p-4">
|
const headerInfo = parseEmailHeaders(headersPart);
|
||||||
<div className="space-y-4">
|
const boundary = extractBoundary(headersPart);
|
||||||
{/* Email Header */}
|
|
||||||
<div className="space-y-2">
|
// If it's a multipart email
|
||||||
<div className="flex items-start justify-between">
|
if (boundary) {
|
||||||
<div className="space-y-1">
|
try {
|
||||||
<div className="text-base font-medium">
|
const parts = body.split(`--${boundary}`);
|
||||||
{email.fromName ? `${email.fromName} <${email.from}>` : email.from}
|
let htmlContent = '';
|
||||||
</div>
|
let textContent = '';
|
||||||
{email.to && (
|
let attachments: { filename: string; content: string }[] = [];
|
||||||
<div className="text-sm text-gray-600">
|
|
||||||
<span className="font-medium">To:</span> {email.to}
|
for (const part of parts) {
|
||||||
</div>
|
if (!part.trim()) continue;
|
||||||
)}
|
|
||||||
{email.cc && (
|
const [partHeaders, ...partBodyParts] = part.split('\r\n\r\n');
|
||||||
<div className="text-sm text-gray-600">
|
if (!partHeaders || partBodyParts.length === 0) continue;
|
||||||
<span className="font-medium">CC:</span> {email.cc}
|
|
||||||
</div>
|
const partBody = partBodyParts.join('\r\n\r\n');
|
||||||
)}
|
const contentType = extractHeader(partHeaders, 'Content-Type').toLowerCase();
|
||||||
</div>
|
const encoding = extractHeader(partHeaders, 'Content-Transfer-Encoding').toLowerCase();
|
||||||
<div className="text-sm text-gray-500">
|
const charset = extractHeader(partHeaders, 'charset') || 'utf-8';
|
||||||
{new Date(email.date).toLocaleString('fr-FR', {
|
|
||||||
day: 'numeric',
|
try {
|
||||||
month: 'short',
|
let decodedContent = '';
|
||||||
hour: '2-digit',
|
if (encoding === 'base64') {
|
||||||
minute: '2-digit'
|
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(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
|
||||||
|
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
|
||||||
|
.replace(/<meta[^>]*>/gi, '')
|
||||||
|
.replace(/<link[^>]*>/gi, '')
|
||||||
|
.replace(/<base[^>]*>/gi, '')
|
||||||
|
.replace(/<title[^>]*>[\s\S]*?<\/title>/gi, '')
|
||||||
|
.replace(/<head[^>]*>[\s\S]*?<\/head>/gi, '')
|
||||||
|
.replace(/<body[^>]*>/gi, '')
|
||||||
|
.replace(/<\/body>/gi, '')
|
||||||
|
.replace(/<html[^>]*>/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 (
|
||||||
|
<div className="email-content">
|
||||||
|
<div className="prose max-w-none" dangerouslySetInnerHTML={{ __html: htmlContent }} />
|
||||||
|
{attachments.length > 0 && renderAttachments(attachments)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to text content
|
||||||
|
if (textContent) {
|
||||||
|
return (
|
||||||
|
<div className="email-content">
|
||||||
|
<div className="whitespace-pre-wrap font-sans text-base leading-relaxed">
|
||||||
|
{textContent.split('\n').map((line: string, i: number) => (
|
||||||
|
<p key={i} className="mb-2">{line}</p>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
{attachments.length > 0 && renderAttachments(attachments)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} 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(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
|
||||||
|
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
|
||||||
|
.replace(/<meta[^>]*>/gi, '')
|
||||||
|
.replace(/<link[^>]*>/gi, '')
|
||||||
|
.replace(/<base[^>]*>/gi, '')
|
||||||
|
.replace(/<title[^>]*>[\s\S]*?<\/title>/gi, '')
|
||||||
|
.replace(/<head[^>]*>[\s\S]*?<\/head>/gi, '')
|
||||||
|
.replace(/<body[^>]*>/gi, '')
|
||||||
|
.replace(/<\/body>/gi, '')
|
||||||
|
.replace(/<html[^>]*>/gi, '')
|
||||||
|
.replace(/<\/html>/gi, '');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="email-content">
|
||||||
|
<div className="prose max-w-none" dangerouslySetInnerHTML={{ __html: cleanedHtml }} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<div className="email-content">
|
||||||
|
<div className="whitespace-pre-wrap font-sans text-base leading-relaxed">
|
||||||
|
{decodedBody.split('\n').map((line: string, i: number) => (
|
||||||
|
<p key={i} className="mb-2">{line}</p>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
{/* Email Body */}
|
}
|
||||||
<div className="prose max-w-none" dangerouslySetInnerHTML={{ __html: body }} />
|
} catch (decodeError) {
|
||||||
</div>
|
console.error('Error decoding email body:', decodeError);
|
||||||
</div>
|
throw new Error('Failed to decode email body');
|
||||||
);
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error rendering email content:', error);
|
console.error('Error rendering email content:', error);
|
||||||
return <div className="p-4 text-red-500">Error displaying email content</div>;
|
return (
|
||||||
|
<div className="email-content">
|
||||||
|
<div className="text-red-500 mb-4">Error displaying email content: {error instanceof Error ? error.message : 'Unknown error'}</div>
|
||||||
|
<pre className="whitespace-pre-wrap text-sm bg-gray-100 p-4 rounded">
|
||||||
|
{email.body}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user