panel 2 courier api restore
This commit is contained in:
parent
f21f626497
commit
684c0cf4ef
89
app/api/debug-email/route.ts
Normal file
89
app/api/debug-email/route.ts
Normal 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 }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -127,78 +127,124 @@ export default function ComposeEmail({
|
|||||||
).join(', ');
|
).join(', ');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize forwarded email with a dead simple approach
|
// Initialize forwarded email with clear structure and style preservation
|
||||||
const initializeForwardedEmail = async () => {
|
const initializeForwardedEmail = async () => {
|
||||||
|
console.log('Starting initializeForwardedEmail');
|
||||||
if (!initialEmail) {
|
if (!initialEmail) {
|
||||||
console.error('No email available for forwarding');
|
console.error('No email available for forwarding');
|
||||||
setBody('<div style="color: #666; font-style: italic;">No email available for forwarding</div>');
|
setBody('<div style="color: #666; font-style: italic;">No email available for forwarding</div>');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug log to see the structure of the email object
|
// Debug the email object structure
|
||||||
console.log('Forwarding email object:', JSON.stringify({
|
console.log('Forwarding email object:', {
|
||||||
id: initialEmail.id,
|
id: initialEmail.id,
|
||||||
subject: initialEmail.subject,
|
subject: initialEmail.subject,
|
||||||
|
fromLength: initialEmail.from?.length,
|
||||||
from: initialEmail.from,
|
from: initialEmail.from,
|
||||||
to: initialEmail.to,
|
to: initialEmail.to,
|
||||||
date: initialEmail.date,
|
date: initialEmail.date,
|
||||||
hasContent: !!initialEmail.content,
|
hasContent: Boolean(initialEmail.content),
|
||||||
hasHTML: !!initialEmail.html,
|
contentLength: initialEmail.content?.length,
|
||||||
hasText: !!initialEmail.text,
|
hasHtml: Boolean(initialEmail.html),
|
||||||
contentFetched: initialEmail.contentFetched
|
htmlLength: initialEmail.html?.length
|
||||||
}, null, 2));
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Format subject with Fwd: prefix if needed
|
// Format subject with Fwd: prefix if needed
|
||||||
const subject = initialEmail.subject || "(No subject)";
|
const subjectBase = initialEmail.subject || '(No subject)';
|
||||||
if (!subject.match(/^(Fwd|FW|Forward):/i)) {
|
const subjectRegex = /^(Fwd|FW|Forward):\s*/i;
|
||||||
setSubject(`Fwd: ${subject}`);
|
const subject = subjectRegex.test(subjectBase)
|
||||||
} else {
|
? subjectBase
|
||||||
|
: `Fwd: ${subjectBase}`;
|
||||||
|
|
||||||
setSubject(subject);
|
setSubject(subject);
|
||||||
}
|
|
||||||
|
|
||||||
// Get email content - use whatever data we have available
|
// Format the forwarded message with a well-structured header
|
||||||
const content = initialEmail.content || initialEmail.html || initialEmail.text || '';
|
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
|
const toString = Array.isArray(initialEmail.to) && initialEmail.to.length > 0
|
||||||
let from = 'Unknown Sender';
|
? initialEmail.to.map(addr => addr.name
|
||||||
if (initialEmail.from) {
|
? `${addr.name} <${addr.address}>`
|
||||||
if (Array.isArray(initialEmail.from) && initialEmail.from.length > 0) {
|
: addr.address).join(', ')
|
||||||
from = initialEmail.from[0].address || 'Unknown';
|
: '';
|
||||||
} else if (typeof initialEmail.from === 'string') {
|
|
||||||
from = initialEmail.from;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hard-code a simple format that definitely works
|
const dateString = initialEmail.date
|
||||||
const forwardedContent = `
|
? typeof initialEmail.date === 'string'
|
||||||
<div style="border-top: 1px solid #ccc; margin-top: 20px; padding-top: 10px; color: #666;">
|
? new Date(initialEmail.date).toLocaleString()
|
||||||
<p>---------- Forwarded message ---------</p>
|
: initialEmail.date.toLocaleString()
|
||||||
<p><b>From:</b> ${from}</p>
|
: new Date().toLocaleString();
|
||||||
<p><b>Date:</b> ${new Date().toLocaleString()}</p>
|
|
||||||
<p><b>Subject:</b> ${subject}</p>
|
// Create a clean wrapper that won't interfere with the original email's styling
|
||||||
<p><b>To:</b> ${Array.isArray(initialEmail.to) && initialEmail.to.length > 0 ? initialEmail.to[0].address : ''}</p>
|
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>
|
||||||
|
`;
|
||||||
|
|
||||||
<div style="margin-top: 20px; padding: 10px; border-left: 2px solid #ccc;">
|
// Get the content with proper fallbacks
|
||||||
${content ? content : '<p style="color: #666; font-style: italic;">No content available</p>'}
|
let originalContent = '';
|
||||||
</div>`;
|
|
||||||
|
|
||||||
// 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);
|
setBody(forwardedContent);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error initializing forwarded email:', error);
|
console.error('Error initializing forwarded email:', error);
|
||||||
// Super simple fallback
|
|
||||||
|
// Even in error case, provide a usable template
|
||||||
setBody(`
|
setBody(`
|
||||||
<div style="border-top: 1px solid #ccc; margin-top: 20px; padding-top: 10px;">
|
<div style="border-top: 1px solid #e1e1e1; margin-top: 20px; padding-top: 15px; font-family: Arial, sans-serif; color: #333;">
|
||||||
<p>---------- Forwarded message ---------</p>
|
<div style="margin-bottom: 15px;">
|
||||||
<p><b>From:</b> ${initialEmail.from ? (Array.isArray(initialEmail.from) ? initialEmail.from[0].address : initialEmail.from) : 'Unknown'}</p>
|
<div style="font-weight: normal; margin-bottom: 10px;">---------- Forwarded message ---------</div>
|
||||||
<p><b>Date:</b> ${new Date().toLocaleString()}</p>
|
<div><b>From:</b> ${initialEmail.from ? JSON.stringify(initialEmail.from) : 'Unknown'}</div>
|
||||||
<p><b>Subject:</b> ${initialEmail.subject || ''}</p>
|
<div><b>Date:</b> ${new Date().toLocaleString()}</div>
|
||||||
<p><b>To:</b> ${initialEmail.to ? (Array.isArray(initialEmail.to) ? initialEmail.to[0].address : initialEmail.to) : ''}</p>
|
<div><b>Subject:</b> ${initialEmail.subject || '(No subject)'}</div>
|
||||||
|
<div><b>To:</b> ${initialEmail.to ? JSON.stringify(initialEmail.to) : ''}</div>
|
||||||
</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>
|
||||||
|
`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -405,12 +405,18 @@ export async function getEmailContent(
|
|||||||
|
|
||||||
const { source, envelope, flags } = message;
|
const { source, envelope, flags } = message;
|
||||||
|
|
||||||
// Parse the email content
|
// Parse the email content, ensuring all styles and structure are preserved
|
||||||
const parsedEmail = await simpleParser(source.toString());
|
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
|
// Convert flags from Set to boolean checks
|
||||||
const flagsArray = Array.from(flags as Set<string>);
|
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 {
|
return {
|
||||||
id: emailId,
|
id: emailId,
|
||||||
messageId: envelope.messageId,
|
messageId: envelope.messageId,
|
||||||
@ -445,9 +451,11 @@ export async function getEmailContent(
|
|||||||
contentType: att.contentType,
|
contentType: att.contentType,
|
||||||
size: att.size || 0
|
size: att.size || 0
|
||||||
})),
|
})),
|
||||||
html: parsedEmail.html || undefined,
|
// Preserve the exact raw HTML to maintain all styling
|
||||||
|
html: rawHtml,
|
||||||
text: parsedEmail.text || undefined,
|
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,
|
folder,
|
||||||
contentFetched: true
|
contentFetched: true
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user