From eac631d72bafa721d51361821e33bd87ffa57dad Mon Sep 17 00:00:00 2001 From: alma Date: Fri, 25 Apr 2025 17:04:18 +0200 Subject: [PATCH] panel 2 courier api --- app/api/courrier/[id]/route.ts | 9 ++-- app/courrier/page.tsx | 87 +++++++++++++++++++++++++++------- lib/server/email-parser.ts | 25 ++++++++-- 3 files changed, 97 insertions(+), 24 deletions(-) diff --git a/app/api/courrier/[id]/route.ts b/app/api/courrier/[id]/route.ts index 550aa556..e63ece0a 100644 --- a/app/api/courrier/[id]/route.ts +++ b/app/api/courrier/[id]/route.ts @@ -144,9 +144,12 @@ export async function GET( to: foundMessage.envelope.to?.map((addr: any) => addr.address).join(', ') || '', subject: foundMessage.envelope.subject || '(No subject)', date: foundMessage.envelope.date?.toISOString() || new Date().toISOString(), - content: parsedEmail.html || parsedEmail.text || '', - textContent: parsedEmail.text || '', - rawContent: foundMessage.source.toString(), // Include raw content for fallback + content: typeof parsedEmail.html === 'string' ? parsedEmail.html : + typeof parsedEmail.text === 'string' ? parsedEmail.text : '', + textContent: typeof parsedEmail.text === 'string' ? parsedEmail.text : '', + rawContent: typeof foundMessage.source === 'object' ? + foundMessage.source.toString() : + String(foundMessage.source || ''), read: foundMessage.flags.has('\\Seen'), starred: foundMessage.flags.has('\\Flagged'), folder: folder, diff --git a/app/courrier/page.tsx b/app/courrier/page.tsx index 14a2ba3c..1212a36e 100644 --- a/app/courrier/page.tsx +++ b/app/courrier/page.tsx @@ -106,8 +106,10 @@ function EmailContent({ email }: { email: Email }) { console.log("Content details:", { hasContent: Boolean(email.content), contentLength: email.content?.length || 0, + contentType: typeof email.content, hasTextContent: Boolean(email.textContent), textContentLength: email.textContent?.length || 0, + textContentType: typeof email.textContent, hasRawContent: Boolean(email.rawContent), rawContentLength: email.rawContent?.length || 0, hasBody: Boolean(email.body), @@ -117,18 +119,35 @@ function EmailContent({ email }: { email: Email }) { // Use state to track if we've rendered content const [renderedContent, setRenderedContent] = useState(false); + // Special handling for potential nested content structure + const content = typeof email.content === 'object' + ? JSON.stringify(email.content) + : email.content; + + const textContent = typeof email.textContent === 'object' + ? JSON.stringify(email.textContent) + : email.textContent; + + const rawContent = typeof email.rawContent === 'object' + ? JSON.stringify(email.rawContent) + : email.rawContent; + + const body = typeof email.body === 'object' + ? JSON.stringify(email.body) + : email.body; + // Use a more defensive approach with content - const hasContent = email.content !== undefined && email.content !== null && email.content.trim() !== ''; - const hasTextContent = email.textContent !== undefined && email.textContent !== null && email.textContent.trim() !== ''; - const hasRawContent = email.rawContent !== undefined && email.rawContent !== null && email.rawContent.trim() !== ''; - const hasBody = email.body !== undefined && email.body !== null && email.body.trim() !== ''; + const hasContent = content !== undefined && content !== null && content.trim() !== ''; + const hasTextContent = textContent !== undefined && textContent !== null && textContent.trim() !== ''; + const hasRawContent = rawContent !== undefined && rawContent !== null && rawContent.trim() !== ''; + const hasBody = body !== undefined && body !== null && body.trim() !== ''; // If textContent is available, render it directly if (hasTextContent && !renderedContent) { setRenderedContent(true); return (
- {email.textContent || ''} + {textContent}
); } @@ -139,7 +158,7 @@ function EmailContent({ email }: { email: Email }) { return (
); } @@ -150,7 +169,7 @@ function EmailContent({ email }: { email: Email }) { return (
); } @@ -160,7 +179,7 @@ function EmailContent({ email }: { email: Email }) { setRenderedContent(true); return (
- {email.rawContent || ''} + {rawContent}
); } @@ -171,10 +190,10 @@ function EmailContent({ email }: { email: Email }) {

No content available

Content flags:

-

- Has content: {hasContent ? 'Yes' : 'No'}

-

- Has text content: {hasTextContent ? 'Yes' : 'No'}

-

- Has raw content: {hasRawContent ? 'Yes' : 'No'}

-

- Has body: {hasBody ? 'Yes' : 'No'}

+

- Has content: {hasContent ? 'Yes' : 'No'} (type: {typeof email.content})

+

- Has text content: {hasTextContent ? 'Yes' : 'No'} (type: {typeof email.textContent})

+

- Has raw content: {hasRawContent ? 'Yes' : 'No'} (type: {typeof email.rawContent})

+

- Has body: {hasBody ? 'Yes' : 'No'} (type: {typeof email.body})

); @@ -638,8 +657,20 @@ export default function CourrierPage() { return; } - const fullEmail = await response.json(); - console.log("API RESPONSE for email:", JSON.stringify(fullEmail, null, 2)); + // Get the raw JSON string first to log it exactly as received + const rawJsonText = await response.text(); + console.log("Raw API response text:", rawJsonText); + + // Then parse it + let fullEmail; + try { + fullEmail = JSON.parse(rawJsonText); + console.log("Parsed JSON API response:", fullEmail); + } catch (jsonError) { + console.error("Error parsing JSON response:", jsonError); + setSelectEmailLoading(false); + return; + } // Create a clean, processed version of the email ensuring all necessary fields exist const processedEmail = { @@ -658,7 +689,12 @@ export default function CourrierPage() { folder: fullEmail.folder || currentView }; - console.log("Processed email for UI:", processedEmail); + console.log("Processed email for UI:", { + ...processedEmail, + contentLength: processedEmail.content.length, + textContentLength: processedEmail.textContent.length, + rawContentLength: processedEmail.rawContent.length + }); // Set the selected email with complete information setSelectedEmail(processedEmail); @@ -1060,13 +1096,28 @@ export default function CourrierPage() {
Content: {selectedEmail.content - ?
{selectedEmail.content.substring(0, 500)}...
+ ?
+

Type: {typeof selectedEmail.content}

+

Value: {typeof selectedEmail.content === 'object' + ? JSON.stringify(selectedEmail.content) + : selectedEmail.content.substring(0, 500)}...

+
: 'Empty'}
Text Content: {selectedEmail.textContent - ?
{selectedEmail.textContent.substring(0, 500)}...
+ ?
+

Type: {typeof selectedEmail.textContent}

+

Value: {typeof selectedEmail.textContent === 'object' + ? JSON.stringify(selectedEmail.textContent) + : selectedEmail.textContent.substring(0, 500)}...

+
: 'Empty'}
Raw Content: {selectedEmail.rawContent - ?
{selectedEmail.rawContent.substring(0, 500)}...
+ ?
+

Type: {typeof selectedEmail.rawContent}

+

Value: {typeof selectedEmail.rawContent === 'object' + ? JSON.stringify(selectedEmail.rawContent) + : selectedEmail.rawContent.substring(0, 500)}...

+
: 'Empty'}
diff --git a/lib/server/email-parser.ts b/lib/server/email-parser.ts index 587644da..dc9a581e 100644 --- a/lib/server/email-parser.ts +++ b/lib/server/email-parser.ts @@ -1,6 +1,8 @@ import { simpleParser } from 'mailparser'; -function cleanHtml(html: string): string { +function cleanHtml(html: string | null | undefined): string { + if (!html) return ''; + try { // Basic HTML cleaning without DOMPurify return html @@ -17,7 +19,7 @@ function cleanHtml(html: string): string { .trim(); } catch (error) { console.error('Error cleaning HTML:', error); - return html; + return html || ''; } } @@ -31,8 +33,25 @@ function getAddressText(address: any): string | null { export async function parseEmail(emailContent: string) { try { + // Add debug logging for the raw content length + console.log(`Starting to parse email content (length: ${emailContent ? emailContent.length : 0})`); + const parsed = await simpleParser(emailContent); + // Add debug logging for the parsed content + console.log('Parsed email fields:', { + hasSubject: !!parsed.subject, + hasHtml: !!parsed.html, + htmlLength: parsed.html?.length || 0, + hasText: !!parsed.text, + textLength: parsed.text?.length || 0, + attachmentsCount: parsed.attachments?.length || 0, + }); + + // Clean the HTML content if it exists + const cleanedHtml = parsed.html ? cleanHtml(parsed.html) : null; + + // Return a properly structured object with all fields explicitly specified return { subject: parsed.subject || null, from: getAddressText(parsed.from), @@ -40,7 +59,7 @@ export async function parseEmail(emailContent: string) { cc: getAddressText(parsed.cc), bcc: getAddressText(parsed.bcc), date: parsed.date || null, - html: parsed.html ? cleanHtml(parsed.html) : null, + html: cleanedHtml, text: parsed.text || null, attachments: parsed.attachments || [], headers: Object.fromEntries(parsed.headers)