panel 2 courier api restore

This commit is contained in:
alma 2025-04-26 10:45:19 +02:00
parent f21f626497
commit 684c0cf4ef
3 changed files with 195 additions and 52 deletions

View File

@ -0,0 +1,89 @@
import { NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/app/api/auth/[...nextauth]/route';
import { getImapConnection } from '@/lib/services/email-service';
import { simpleParser } from 'mailparser';
export async function GET(request: Request) {
// Verify authentication
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
try {
const { searchParams } = new URL(request.url);
const emailId = searchParams.get('id');
const folder = searchParams.get('folder') || 'INBOX';
if (!emailId) {
return NextResponse.json({ error: 'Email ID is required' }, { status: 400 });
}
// Connect to IMAP
const client = await getImapConnection(session.user.id);
try {
await client.mailboxOpen(folder);
// Fetch raw email
const message = await client.fetchOne(emailId, {
source: true,
envelope: true,
flags: true
});
if (!message) {
return NextResponse.json({ error: 'Email not found' }, { status: 404 });
}
// Get raw source content
const { source, envelope } = message;
const rawSource = source.toString();
// Parse the email with multiple options to debug
const parsedEmail = await simpleParser(rawSource, {
skipHtmlToText: true,
keepCidLinks: true
});
// Extract all available data
return NextResponse.json({
id: emailId,
folder,
date: envelope.date,
subject: envelope.subject,
from: envelope.from,
to: envelope.to,
// Raw content (truncated to prevent massive responses)
sourcePreview: rawSource.substring(0, 1000) + (rawSource.length > 1000 ? '...' : ''),
sourceLength: rawSource.length,
// Parsed content
htmlPreview: parsedEmail.html ? parsedEmail.html.substring(0, 1000) + (parsedEmail.html.length > 1000 ? '...' : '') : null,
htmlLength: parsedEmail.html ? parsedEmail.html.length : 0,
textPreview: parsedEmail.text ? parsedEmail.text.substring(0, 1000) + (parsedEmail.text.length > 1000 ? '...' : '') : null,
textLength: parsedEmail.text ? parsedEmail.text.length : 0,
// Detect if there's HTML and what type of content it contains
hasHtml: !!parsedEmail.html,
hasStyleTags: typeof parsedEmail.html === 'string' && parsedEmail.html.includes('<style'),
hasCss: typeof parsedEmail.html === 'string' && parsedEmail.html.includes('style='),
// Headers that might be relevant
contentType: parsedEmail.headers.get('content-type'),
// Attachment count
attachmentCount: parsedEmail.attachments.length
});
} finally {
try {
await client.logout();
} catch (error) {
console.error('Error logging out:', error);
}
}
} catch (error) {
console.error('Error in debug-email route:', error);
return NextResponse.json(
{ error: 'Server error', message: error instanceof Error ? error.message : String(error) },
{ status: 500 }
);
}
}

View File

@ -127,78 +127,124 @@ export default function ComposeEmail({
).join(', ');
};
// Initialize forwarded email with a dead simple approach
// Initialize forwarded email with clear structure and style preservation
const initializeForwardedEmail = async () => {
console.log('Starting initializeForwardedEmail');
if (!initialEmail) {
console.error('No email available for forwarding');
setBody('<div style="color: #666; font-style: italic;">No email available for forwarding</div>');
return;
}
// Debug log to see the structure of the email object
console.log('Forwarding email object:', JSON.stringify({
// Debug the email object structure
console.log('Forwarding email object:', {
id: initialEmail.id,
subject: initialEmail.subject,
fromLength: initialEmail.from?.length,
from: initialEmail.from,
to: initialEmail.to,
date: initialEmail.date,
hasContent: !!initialEmail.content,
hasHTML: !!initialEmail.html,
hasText: !!initialEmail.text,
contentFetched: initialEmail.contentFetched
}, null, 2));
hasContent: Boolean(initialEmail.content),
contentLength: initialEmail.content?.length,
hasHtml: Boolean(initialEmail.html),
htmlLength: initialEmail.html?.length
});
try {
// Format subject with Fwd: prefix if needed
const subject = initialEmail.subject || "(No subject)";
if (!subject.match(/^(Fwd|FW|Forward):/i)) {
setSubject(`Fwd: ${subject}`);
} else {
const subjectBase = initialEmail.subject || '(No subject)';
const subjectRegex = /^(Fwd|FW|Forward):\s*/i;
const subject = subjectRegex.test(subjectBase)
? subjectBase
: `Fwd: ${subjectBase}`;
setSubject(subject);
}
// Get email content - use whatever data we have available
const content = initialEmail.content || initialEmail.html || initialEmail.text || '';
// Format the forwarded message with a well-structured header
const fromString = Array.isArray(initialEmail.from) && initialEmail.from.length > 0
? initialEmail.from.map(addr => addr.name
? `${addr.name} <${addr.address}>`
: addr.address).join(', ')
: 'Unknown';
// Get from info - handle various possible formats
let from = 'Unknown Sender';
if (initialEmail.from) {
if (Array.isArray(initialEmail.from) && initialEmail.from.length > 0) {
from = initialEmail.from[0].address || 'Unknown';
} else if (typeof initialEmail.from === 'string') {
from = initialEmail.from;
}
}
const toString = Array.isArray(initialEmail.to) && initialEmail.to.length > 0
? initialEmail.to.map(addr => addr.name
? `${addr.name} <${addr.address}>`
: addr.address).join(', ')
: '';
// Hard-code a simple format that definitely works
const forwardedContent = `
<div style="border-top: 1px solid #ccc; margin-top: 20px; padding-top: 10px; color: #666;">
<p>---------- Forwarded message ---------</p>
<p><b>From:</b> ${from}</p>
<p><b>Date:</b> ${new Date().toLocaleString()}</p>
<p><b>Subject:</b> ${subject}</p>
<p><b>To:</b> ${Array.isArray(initialEmail.to) && initialEmail.to.length > 0 ? initialEmail.to[0].address : ''}</p>
const dateString = initialEmail.date
? typeof initialEmail.date === 'string'
? new Date(initialEmail.date).toLocaleString()
: initialEmail.date.toLocaleString()
: new Date().toLocaleString();
// Create a clean wrapper that won't interfere with the original email's styling
const headerHtml = `
<div style="border-top: 1px solid #e1e1e1; margin-top: 20px; padding-top: 15px; font-family: Arial, sans-serif; color: #333;">
<div style="margin-bottom: 15px;">
<div style="font-weight: normal; margin-bottom: 10px;">---------- Forwarded message ---------</div>
<div><b>From:</b> ${fromString}</div>
<div><b>Date:</b> ${dateString}</div>
<div><b>Subject:</b> ${subjectBase}</div>
<div><b>To:</b> ${toString}</div>
</div>
</div>
`;
<div style="margin-top: 20px; padding: 10px; border-left: 2px solid #ccc;">
${content ? content : '<p style="color: #666; font-style: italic;">No content available</p>'}
</div>`;
// Get the content with proper fallbacks
let originalContent = '';
// Just set the HTML directly
// First try the html field which should contain the raw HTML
if (initialEmail.html && initialEmail.html.trim()) {
console.log('Using HTML content for forward');
originalContent = initialEmail.html;
}
// Then try the content field
else if (initialEmail.content && initialEmail.content.trim()) {
console.log('Using content field for forward');
originalContent = initialEmail.content;
}
// Fall back to text with styling if available
else if (initialEmail.text && initialEmail.text.trim()) {
console.log('Using text content for forward');
originalContent = `<div style="white-space: pre-wrap; font-family: monospace;">${initialEmail.text}</div>`;
}
// Last resort - no content available
else {
console.log('No content available for forward');
originalContent = '<div style="color: #666; font-style: italic; padding: 10px;">No content available</div>';
}
// Preserve all original structure by wrapping, not modifying the original content
const forwardedContent = `
${headerHtml}
<div class="original-email-content" style="margin-top: 10px; border-left: 2px solid #e1e1e1; padding-left: 15px;">
${originalContent}
</div>
`;
console.log('Setting body with forwarded content');
setBody(forwardedContent);
} catch (error) {
console.error('Error initializing forwarded email:', error);
// Super simple fallback
// Even in error case, provide a usable template
setBody(`
<div style="border-top: 1px solid #ccc; margin-top: 20px; padding-top: 10px;">
<p>---------- Forwarded message ---------</p>
<p><b>From:</b> ${initialEmail.from ? (Array.isArray(initialEmail.from) ? initialEmail.from[0].address : initialEmail.from) : 'Unknown'}</p>
<p><b>Date:</b> ${new Date().toLocaleString()}</p>
<p><b>Subject:</b> ${initialEmail.subject || ''}</p>
<p><b>To:</b> ${initialEmail.to ? (Array.isArray(initialEmail.to) ? initialEmail.to[0].address : initialEmail.to) : ''}</p>
<div style="border-top: 1px solid #e1e1e1; margin-top: 20px; padding-top: 15px; font-family: Arial, sans-serif; color: #333;">
<div style="margin-bottom: 15px;">
<div style="font-weight: normal; margin-bottom: 10px;">---------- Forwarded message ---------</div>
<div><b>From:</b> ${initialEmail.from ? JSON.stringify(initialEmail.from) : 'Unknown'}</div>
<div><b>Date:</b> ${new Date().toLocaleString()}</div>
<div><b>Subject:</b> ${initialEmail.subject || '(No subject)'}</div>
<div><b>To:</b> ${initialEmail.to ? JSON.stringify(initialEmail.to) : ''}</div>
</div>
<p style="color: #666; font-style: italic;">Content could not be displayed</p>`);
</div>
<div style="margin-top: 10px; padding: 10px; color: #d32f2f; font-style: italic;">
Error loading original message content. The original message may still be viewable in your inbox.
</div>
`);
}
};

View File

@ -405,12 +405,18 @@ export async function getEmailContent(
const { source, envelope, flags } = message;
// Parse the email content
const parsedEmail = await simpleParser(source.toString());
// Parse the email content, ensuring all styles and structure are preserved
const parsedEmail = await simpleParser(source.toString(), {
skipHtmlToText: true, // Don't convert HTML to plain text
keepCidLinks: true // Keep Content-ID references for inline images
});
// Convert flags from Set to boolean checks
const flagsArray = Array.from(flags as Set<string>);
// Preserve the raw HTML exactly as it was in the original email
const rawHtml = parsedEmail.html || '';
return {
id: emailId,
messageId: envelope.messageId,
@ -445,9 +451,11 @@ export async function getEmailContent(
contentType: att.contentType,
size: att.size || 0
})),
html: parsedEmail.html || undefined,
// Preserve the exact raw HTML to maintain all styling
html: rawHtml,
text: parsedEmail.text || undefined,
content: parsedEmail.html || parsedEmail.textAsHtml || parsedEmail.text || '',
// For content field, prioritize using the raw HTML to preserve all styling
content: rawHtml || parsedEmail.text || '',
folder,
contentFetched: true
};