mail page rest dang
This commit is contained in:
parent
fbc1140ccb
commit
784d673063
@ -98,115 +98,160 @@ interface ParsedEmailMetadata {
|
||||
}
|
||||
|
||||
function renderEmailContent(email: Email) {
|
||||
if (!email.body) return null;
|
||||
if (!email.body) {
|
||||
console.warn('No email body provided');
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// Split email into headers and body
|
||||
const [headersPart, ...bodyParts] = email.body.split('\r\n\r\n');
|
||||
if (!headersPart || bodyParts.length === 0) {
|
||||
throw new Error('Invalid email format: missing headers or body');
|
||||
}
|
||||
|
||||
const body = bodyParts.join('\r\n\r\n');
|
||||
|
||||
// Parse headers using our MIME decoder
|
||||
// Parse headers using Infomaniak MIME decoder
|
||||
const headerInfo = parseEmailHeaders(headersPart);
|
||||
const boundary = extractBoundary(headersPart);
|
||||
|
||||
// If it's a multipart email
|
||||
if (boundary) {
|
||||
const parts = body.split(`--${boundary}`);
|
||||
let htmlContent = '';
|
||||
let textContent = '';
|
||||
let attachments: { filename: string; content: string }[] = [];
|
||||
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');
|
||||
const partBody = partBodyParts.join('\r\n\r\n');
|
||||
const partHeaderInfo = parseEmailHeaders(partHeaders);
|
||||
|
||||
if (partHeaderInfo.contentType.includes('text/html')) {
|
||||
htmlContent = decodeQuotedPrintable(partBody, partHeaderInfo.charset);
|
||||
} else if (partHeaderInfo.contentType.includes('text/plain')) {
|
||||
textContent = decodeQuotedPrintable(partBody, partHeaderInfo.charset);
|
||||
} else if (partHeaderInfo.contentType.includes('attachment')) {
|
||||
attachments.push({
|
||||
filename: extractFilename(partHeaders),
|
||||
content: decodeBase64(partBody, partHeaderInfo.charset)
|
||||
});
|
||||
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 partHeaderInfo = parseEmailHeaders(partHeaders);
|
||||
const contentType = extractHeader(partHeaders, 'Content-Type').toLowerCase();
|
||||
const encoding = extractHeader(partHeaders, 'Content-Transfer-Encoding').toLowerCase();
|
||||
const charset = extractHeader(partHeaders, 'charset') || 'utf-8';
|
||||
|
||||
try {
|
||||
if (contentType.includes('text/html')) {
|
||||
const decodedContent = encoding === 'base64'
|
||||
? decodeBase64(partBody, charset)
|
||||
: decodeQuotedPrintable(partBody, charset);
|
||||
htmlContent = cleanHtml(decodedContent);
|
||||
} else if (contentType.includes('text/plain')) {
|
||||
const decodedContent = encoding === 'base64'
|
||||
? decodeBase64(partBody, charset)
|
||||
: decodeQuotedPrintable(partBody, charset);
|
||||
textContent = decodedContent;
|
||||
} else if (contentType.includes('attachment') || extractHeader(partHeaders, 'Content-Disposition').includes('attachment')) {
|
||||
attachments.push({
|
||||
filename: extractFilename(partHeaders) || 'unnamed_attachment',
|
||||
content: encoding === 'base64'
|
||||
? decodeBase64(partBody, charset)
|
||||
: decodeQuotedPrintable(partBody, charset)
|
||||
});
|
||||
}
|
||||
} 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: cleanHtml(htmlContent) }} />
|
||||
{attachments.length > 0 && (
|
||||
<div className="mt-4">
|
||||
<h3 className="text-sm font-medium mb-2">Attachments:</h3>
|
||||
<ul className="space-y-2">
|
||||
{attachments.map((attachment, index) => (
|
||||
<li key={index} className="flex items-center gap-2">
|
||||
<Paperclip className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="text-sm">{attachment.filename}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</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>
|
||||
))}
|
||||
// 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>
|
||||
{attachments.length > 0 && (
|
||||
<div className="mt-4">
|
||||
<h3 className="text-sm font-medium mb-2">Attachments:</h3>
|
||||
<ul className="space-y-2">
|
||||
{attachments.map((attachment, index) => (
|
||||
<li key={index} className="flex items-center gap-2">
|
||||
<Paperclip className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="text-sm">{attachment.filename}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
// 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 decode it
|
||||
const decodedBody = decodeQuotedPrintable(body, headerInfo.charset);
|
||||
const cleanedContent = cleanHtml(decodedBody);
|
||||
// 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';
|
||||
|
||||
return (
|
||||
<div className="email-content">
|
||||
<div className="whitespace-pre-wrap font-sans text-base leading-relaxed">
|
||||
{cleanedContent.split('\n').map((line: string, i: number) => (
|
||||
<p key={i} className="mb-2">{line}</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
try {
|
||||
const decodedBody = encoding === 'base64'
|
||||
? decodeBase64(body, charset)
|
||||
: decodeQuotedPrintable(body, charset);
|
||||
|
||||
if (contentType.includes('text/html')) {
|
||||
const cleanedContent = cleanHtml(decodedBody);
|
||||
return (
|
||||
<div className="email-content">
|
||||
<div className="prose max-w-none" dangerouslySetInnerHTML={{ __html: cleanedContent }} />
|
||||
</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>
|
||||
);
|
||||
}
|
||||
} 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 (
|
||||
<div className="email-content">
|
||||
<pre className="whitespace-pre-wrap text-sm">{email.body}</pre>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to render attachments
|
||||
function renderAttachments(attachments: { filename: string; content: string }[]) {
|
||||
return (
|
||||
<div className="mt-4">
|
||||
<h3 className="text-sm font-medium mb-2">Attachments:</h3>
|
||||
<ul className="space-y-2">
|
||||
{attachments.map((attachment, index) => (
|
||||
<li key={index} className="flex items-center gap-2">
|
||||
<Paperclip className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="text-sm">{attachment.filename}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Define the exact folder names from IMAP
|
||||
type MailFolder = string;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user