diff --git a/app/api/mail/[id]/route.ts b/app/api/mail/[id]/route.ts new file mode 100644 index 00000000..08a57256 --- /dev/null +++ b/app/api/mail/[id]/route.ts @@ -0,0 +1,99 @@ +import { NextResponse } from 'next/server'; +import { ImapFlow } from 'imapflow'; +import { getServerSession } from 'next-auth'; +import { authOptions } from '@/app/api/auth/[...nextauth]/route'; +import { prisma } from '@/lib/prisma'; + +export async function GET(request: Request, { params }: { params: { id: string } }) { + try { + const session = await getServerSession(authOptions); + if (!session?.user?.id) { + return NextResponse.json( + { error: 'Unauthorized' }, + { status: 401 } + ); + } + + // Get credentials from database + const credentials = await prisma.mailCredentials.findUnique({ + where: { + userId: session.user.id + } + }); + + if (!credentials) { + return NextResponse.json( + { error: 'No mail credentials found. Please configure your email account.' }, + { status: 401 } + ); + } + + // Get the current folder from the request URL + const url = new URL(request.url); + const folder = url.searchParams.get('folder') || 'INBOX'; + + // Connect to IMAP server + const client = new ImapFlow({ + host: credentials.host, + port: credentials.port, + secure: true, + auth: { + user: credentials.email, + pass: credentials.password, + }, + logger: false, + emitLogs: false, + tls: { + rejectUnauthorized: false + } + }); + + try { + await client.connect(); + await client.mailboxOpen(folder); + + // Fetch the full email content + const message = await client.fetchOne(params.id, { + source: true, + envelope: true, + flags: true + }); + + if (!message) { + return NextResponse.json( + { error: 'Email not found' }, + { status: 404 } + ); + } + + // Extract email content + const result = { + id: message.uid.toString(), + from: message.envelope.from[0].address, + subject: message.envelope.subject || '(No subject)', + date: message.envelope.date.toISOString(), + read: message.flags.has('\\Seen'), + starred: message.flags.has('\\Flagged'), + folder: folder, + body: message.source.toString(), + to: message.envelope.to?.map(addr => addr.address).join(', ') || '', + cc: message.envelope.cc?.map(addr => addr.address).join(', ') || '', + bcc: message.envelope.bcc?.map(addr => addr.address).join(', ') || '', + }; + + return NextResponse.json(result); + } finally { + try { + await client.logout(); + } catch (e) { + console.error('Error during logout:', e); + } + } + } catch (error) { + console.error('Error fetching email:', error); + return NextResponse.json( + { error: 'An unexpected error occurred' }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/app/courrier/page.tsx b/app/courrier/page.tsx index cda5d66f..9dfcbd8b 100644 --- a/app/courrier/page.tsx +++ b/app/courrier/page.tsx @@ -40,7 +40,7 @@ interface Email { id: number; accountId: number; from: string; - fromName?: string; + fromName: string; to: string; subject: string; body: string; @@ -484,16 +484,21 @@ function renderEmailContent(email: Email) { }); // If parsing failed, try direct content extraction - let content = null; + let content = ''; + let isHtml = false; + if (parsed.html) { content = parsed.html; + isHtml = true; } else if (parsed.text) { content = parsed.text; + isHtml = false; } else { // Try to extract content directly from body const htmlMatch = email.body.match(/]*>[\s\S]*?<\/html>/i); if (htmlMatch) { content = htmlMatch[0]; + isHtml = true; } else { content = email.body .replace(/<[^>]+>/g, '') @@ -507,6 +512,7 @@ function renderEmailContent(email: Email) { .replace(/=3D/g, '=') .replace(/=09/g, '\t') .trim(); + isHtml = false; } } @@ -527,7 +533,11 @@ function renderEmailContent(email: Email) { return (