diff --git a/app/api/parse-email/route.ts b/app/api/parse-email/route.ts
index c23e3059..ad03828d 100644
--- a/app/api/parse-email/route.ts
+++ b/app/api/parse-email/route.ts
@@ -11,81 +11,38 @@ function getEmailAddress(address: AddressObject | AddressObject[] | undefined):
export async function POST(request: Request) {
try {
- console.log('[DEBUG] Parse-email API called');
-
const body = await request.json();
- const emailContent = body.email || body.emailContent;
+ const { email } = body;
- if (!emailContent || typeof emailContent !== 'string') {
- console.error('[DEBUG] Parse-email API error: Invalid email content');
+ if (!email || typeof email !== 'string') {
return NextResponse.json(
{ error: 'Invalid email content' },
{ status: 400 }
);
}
- console.log('[DEBUG] Parse-email API processing email content, length:', emailContent.length);
- console.log('[DEBUG] Content sample:', emailContent.substring(0, 100) + '...');
+ const parsed = await simpleParser(email);
- try {
- const parsed = await simpleParser(emailContent);
-
- console.log('[DEBUG] Parse-email API successfully parsed email:', {
- hasSubject: !!parsed.subject,
- hasHtml: !!parsed.html,
- hasText: !!parsed.text,
- hasTextAsHtml: !!parsed.textAsHtml,
- fromCount: parsed.from ? (Array.isArray(parsed.from) ? parsed.from.length : 1) : 0,
- attachmentCount: parsed.attachments?.length || 0
- });
-
- return NextResponse.json({
- subject: parsed.subject || null,
- from: getEmailAddress(parsed.from),
- to: getEmailAddress(parsed.to),
- cc: getEmailAddress(parsed.cc),
- bcc: getEmailAddress(parsed.bcc),
- date: parsed.date || null,
- html: parsed.html || parsed.textAsHtml || null,
- text: parsed.text || null,
- attachments: parsed.attachments?.map(att => ({
- filename: att.filename,
- contentType: att.contentType,
- size: att.size
- })) || [],
- headers: parsed.headers || {}
- });
- } catch (parseError) {
- console.error('[DEBUG] Parse-email API error parsing email:', parseError);
-
- // Try simpler parsing method for more resilience
- try {
- console.log('[DEBUG] Attempting fallback parsing method');
- const resultObj: any = { text: emailContent, html: null };
-
- // Simple check if it might be HTML
- if (emailContent.includes('
/g, '>')
- .replace(/\n/g, '
');
- }
-
- console.log('[DEBUG] Fallback parsing generated simple result');
- return NextResponse.json(resultObj);
- } catch (fallbackError) {
- console.error('[DEBUG] Even fallback parsing failed:', fallbackError);
- throw parseError; // Throw the original error
- }
- }
+ return NextResponse.json({
+ subject: parsed.subject || null,
+ from: getEmailAddress(parsed.from),
+ to: getEmailAddress(parsed.to),
+ cc: getEmailAddress(parsed.cc),
+ bcc: getEmailAddress(parsed.bcc),
+ date: parsed.date || null,
+ html: parsed.html || null,
+ text: parsed.textAsHtml || parsed.text || null,
+ attachments: parsed.attachments?.map(att => ({
+ filename: att.filename,
+ contentType: att.contentType,
+ size: att.size
+ })) || [],
+ headers: parsed.headers || {}
+ });
} catch (error) {
- console.error('[DEBUG] Parse-email API unhandled error:', error);
+ console.error('Error parsing email:', error);
return NextResponse.json(
- { error: 'Failed to parse email', details: error instanceof Error ? error.message : 'Unknown error' },
+ { error: 'Failed to parse email' },
{ status: 500 }
);
}
diff --git a/components/ComposeEmail.tsx b/components/ComposeEmail.tsx
index a008d984..447a4fbc 100644
--- a/components/ComposeEmail.tsx
+++ b/components/ComposeEmail.tsx
@@ -125,7 +125,7 @@ export default function ComposeEmail({
return;
}
- // Check if we need to fetch full content first - same as panel 3
+ // Check if we need to fetch full content first
if (!emailToProcess.content || emailToProcess.content.length === 0) {
console.log('[DEBUG] Need to fetch content before composing reply/forward');
@@ -156,144 +156,78 @@ export default function ComposeEmail({
}
}
- // Now proceed with the usual decoding
- const type = replyTo ? 'reply' : 'forward';
+ // Parse the original email using the API
+ const response = await fetch('/api/parse-email', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ email: emailToProcess.content }),
+ });
+
+ if (!response.ok) {
+ throw new Error(`Failed to parse email: ${response.status}`);
+ }
- // DIRECTLY MATCH PANEL 3 IMPLEMENTATION
- try {
- const decoded = await decodeEmail(emailToProcess.content);
- console.log('[DEBUG] Decoded email for compose:', {
- hasHtml: !!decoded.html,
- hasText: !!decoded.text,
- from: decoded.from,
- subject: decoded.subject
- });
-
- // Create the email container with header information
- let emailHeader = '';
- if (type === 'forward') {
- emailHeader = `
-
-
---------- Forwarded message ---------
-
From: ${decoded.from || ''}
-
Date: ${formatDate(decoded.date ? new Date(decoded.date) : null)}
-
Subject: ${decoded.subject || ''}
-
To: ${decoded.to || ''}
-
- `;
- } else {
- emailHeader = `
-
-
On ${formatDate(decoded.date ? new Date(decoded.date) : null)}, ${decoded.from || ''} wrote:
-
- `;
+ const data = await response.json();
+ console.log('[DEBUG] Parsed email data:', {
+ hasHtml: !!data.html,
+ hasText: !!data.text,
+ from: data.from,
+ subject: data.subject
+ });
+
+ const emailContent = data.html || data.text || '';
+
+ // Format the reply/forward content
+ const quotedContent = forwardFrom ? `
+
+ ---------- Forwarded message ---------
+ From: ${emailToProcess.from}
+ Date: ${new Date(emailToProcess.date).toLocaleString()}
+ Subject: ${emailToProcess.subject}
+ To: ${emailToProcess.to}
+ ${emailToProcess.cc ? `Cc: ${emailToProcess.cc}
` : ''}
+
+
+ ${emailContent}
+
+ ` : `
+
+ On ${new Date(emailToProcess.date).toLocaleString()}, ${emailToProcess.from} wrote:
+
+
+ ${emailContent}
+
+ `;
+
+ // Set the content in the compose area with proper structure
+ const formattedContent = `
+
+ `;
+
+ if (composeBodyRef.current) {
+ composeBodyRef.current.innerHTML = formattedContent;
+
+ // Place cursor at the beginning before the quoted content
+ const selection = window.getSelection();
+ const range = document.createRange();
+ const firstDiv = composeBodyRef.current.querySelector('div[style*="min-height: 20px;"]');
+ if (firstDiv) {
+ range.setStart(firstDiv, 0);
+ range.collapse(true);
+ selection?.removeAllRanges();
+ selection?.addRange(range);
+ (firstDiv as HTMLElement).focus();
}
-
- // Get the proper content with minimal sanitization to preserve structure
- let emailContent = '';
- if (decoded.html) {
- // Allow ALL HTML elements and attributes to fully preserve formatting
- emailContent = DOMPurify.sanitize(decoded.html, {
- ADD_TAGS: ['style', 'meta', 'link', 'script'],
- ADD_ATTR: ['*', 'style', 'class', 'id', 'src', 'href', 'target', 'rel', 'align', 'valign', 'border', 'cellpadding', 'cellspacing', 'bgcolor', 'width', 'height'],
- ALLOW_UNKNOWN_PROTOCOLS: true,
- WHOLE_DOCUMENT: true,
- RETURN_DOM: false,
- KEEP_CONTENT: true
- });
- } else if (decoded.text) {
- emailContent = `${decoded.text}`;
- } else {
- emailContent = 'No content available
';
- }
-
- // Set the content in the compose area with proper structure
- const wrappedContent = `
-
-
- ${emailHeader}
-
- ${emailContent}
-
-
- `;
- if (composeBodyRef.current) {
- composeBodyRef.current.innerHTML = wrappedContent;
-
- // Place cursor at the beginning before the quoted content
- const selection = window.getSelection();
- const range = document.createRange();
- const firstDiv = composeBodyRef.current.querySelector('.cursor-position');
- if (firstDiv) {
- range.setStart(firstDiv, 0);
- range.collapse(true);
- selection?.removeAllRanges();
- selection?.addRange(range);
- (firstDiv as HTMLElement).focus();
- }
-
- // After setting the HTML content, add event listeners for scrolling
- const messageContents = composeBodyRef.current.querySelectorAll('.email-content');
- messageContents.forEach(container => {
- // Make sure the container is properly styled for scrolling
- (container as HTMLElement).style.maxHeight = '400px';
- (container as HTMLElement).style.overflowY = 'auto';
- (container as HTMLElement).style.border = '1px solid #e5e7eb';
- (container as HTMLElement).style.borderRadius = '4px';
- (container as HTMLElement).style.padding = '15px';
-
- // Ensure wheel events are properly handled
- if (!(container as HTMLElement).hasAttribute('data-scroll-handler-attached')) {
- container.addEventListener('wheel', (e: Event) => {
- const wheelEvent = e as WheelEvent;
- const target = e.currentTarget as HTMLElement;
-
- // Check if we're at the boundary of the scrollable area
- const isAtBottom = target.scrollHeight - target.scrollTop <= target.clientHeight + 1;
- const isAtTop = target.scrollTop <= 0;
-
- // Only prevent default if we're not at the boundaries in the direction of scrolling
- if ((wheelEvent.deltaY > 0 && !isAtBottom) || (wheelEvent.deltaY < 0 && !isAtTop)) {
- e.stopPropagation();
- e.preventDefault(); // Prevent the parent container from scrolling
- }
- }, { passive: false });
-
- // Mark this element as having a scroll handler attached
- (container as HTMLElement).setAttribute('data-scroll-handler-attached', 'true');
- }
- });
-
- // Update compose state
- setComposeBody(wrappedContent);
- setLocalContent(wrappedContent);
- console.log('[DEBUG] Successfully set compose content with scrollable message area');
- }
- } catch (error) {
- console.error('[DEBUG] Error parsing email for compose:', error);
-
- // Fallback to basic content display
- const errorContent = `
-
-
-
- ---------- Original Message ---------
- ${emailToProcess.subject ? `Subject: ${emailToProcess.subject}
` : ''}
- ${emailToProcess.from ? `From: ${emailToProcess.from}
` : ''}
- ${emailToProcess.date ? `Date: ${new Date(emailToProcess.date).toLocaleString()}
` : ''}
-
-
- ${emailToProcess.preview || 'No content available'}
-
-
- `;
-
- if (composeBodyRef.current) {
- composeBodyRef.current.innerHTML = errorContent;
- setComposeBody(errorContent);
- setLocalContent(errorContent);
- }
+ // Update compose state
+ setComposeBody(formattedContent);
+ setLocalContent(formattedContent);
+ console.log('[DEBUG] Successfully set compose content');
}
} catch (error) {
console.error('[DEBUG] Error initializing compose content:', error);
diff --git a/lib/compose-mime-decoder.ts b/lib/compose-mime-decoder.ts
index 04bc1fd5..b5309f8f 100644
--- a/lib/compose-mime-decoder.ts
+++ b/lib/compose-mime-decoder.ts
@@ -19,7 +19,7 @@ export async function decodeComposeContent(content: string): Promise