diff --git a/app/api/mail/route.ts b/app/api/mail/route.ts index acfbab8..0d48998 100644 --- a/app/api/mail/route.ts +++ b/app/api/mail/route.ts @@ -91,7 +91,7 @@ function getStoredCredentials(): StoredCredentials | null { } } -export async function GET() { +export async function GET(request: Request) { try { const credentials = getStoredCredentials(); if (!credentials) { @@ -101,8 +101,10 @@ export async function GET() { ); } - const availableMailboxes: string[] = []; - const emailsByFolder: { [key: string]: any[] } = {}; + // Get the current folder from the URL + const url = new URL(request.url); + const folder = url.searchParams.get('folder') || 'INBOX'; + const limit = 50; // Limit number of emails per folder return new Promise((resolve) => { const imap = new Imap({ @@ -116,7 +118,6 @@ export async function GET() { connTimeout: 30000 }); - // Add a timeout to prevent hanging const timeout = setTimeout(() => { console.error('IMAP connection timeout'); imap.end(); @@ -124,7 +125,7 @@ export async function GET() { emails: [], error: 'Connection timeout' })); - }, 60000); + }, 30000); imap.once('error', (err: Error) => { console.error('IMAP error:', err); @@ -145,133 +146,111 @@ export async function GET() { return; } - // Process mailboxes - Object.keys(boxes).forEach((box) => { - availableMailboxes.push(box); - }); - + const availableMailboxes = Object.keys(boxes); console.log('Available mailboxes:', availableMailboxes); - // Process each mailbox - const foldersToProcess = availableMailboxes; - let processedFolders = 0; - let activeFetches = 0; - - function checkCompletion() { - processedFolders++; - if (processedFolders === foldersToProcess.length && activeFetches === 0) { + // Only process the requested folder + imap.openBox(folder, false, (err, box) => { + if (err) { + console.error(`Error opening box ${folder}:`, err); clearTimeout(timeout); - finishProcessing(); + imap.end(); + resolve(NextResponse.json({ emails: [], error: `Failed to open folder ${folder}` })); + return; } - } - function finishProcessing() { - // Combine all emails from all folders - const allEmails = Object.entries(emailsByFolder).flatMap(([folder, emails]) => emails); - - console.log('Emails by folder:', Object.fromEntries( - Object.entries(emailsByFolder).map(([folder, emails]) => [folder, emails.length]) - )); - console.log('All folders processed, total emails:', allEmails.length); - - const response = { - emails: allEmails, - folders: availableMailboxes, - mailUrl: process.env.NEXTCLOUD_URL ? `${process.env.NEXTCLOUD_URL}/apps/mail/` : null - }; - imap.end(); - resolve(NextResponse.json(response)); - } - - foldersToProcess.forEach((folderName) => { - // Initialize array for this folder - emailsByFolder[folderName] = []; - - imap.openBox(folderName, false, (err, box) => { + // Search for emails in this folder, limited to the most recent ones + imap.search(['ALL'], (err, results) => { if (err) { - console.error(`Error opening box ${folderName}:`, err); - checkCompletion(); + console.error(`Error searching in ${folder}:`, err); + clearTimeout(timeout); + imap.end(); + resolve(NextResponse.json({ emails: [], error: `Failed to search in ${folder}` })); return; } - // Search for all emails in this folder - imap.search(['ALL'], (err, results) => { - if (err) { - console.error(`Error searching in ${folderName}:`, err); - checkCompletion(); - return; - } + if (!results || results.length === 0) { + clearTimeout(timeout); + imap.end(); + resolve(NextResponse.json({ + emails: [], + folders: availableMailboxes, + mailUrl: process.env.NEXTCLOUD_URL ? `${process.env.NEXTCLOUD_URL}/apps/mail/` : null + })); + return; + } - if (!results || results.length === 0) { - checkCompletion(); - return; - } + // Take only the most recent emails up to the limit + const recentResults = results.slice(-limit); + const emails: any[] = []; - activeFetches++; - // Fetch emails - const fetch = imap.fetch(results, { - bodies: ['HEADER', 'TEXT'], - struct: true + const fetch = imap.fetch(recentResults, { + bodies: ['HEADER', 'TEXT'], + struct: true + }); + + fetch.on('message', (msg) => { + let header = ''; + let text = ''; + let messageId: number | null = null; + let messageFlags: string[] = []; + + msg.once('attributes', (attrs) => { + messageId = attrs.uid; + messageFlags = attrs.flags || []; }); - fetch.on('message', (msg) => { - let header = ''; - let text = ''; - let messageId: number | null = null; - let messageFlags: string[] = []; - - // Handle attributes first - msg.once('attributes', (attrs) => { - messageId = attrs.uid; - messageFlags = attrs.flags || []; + msg.on('body', (stream, info) => { + let buffer = ''; + stream.on('data', (chunk) => { + buffer += chunk.toString('utf8'); }); - - msg.on('body', (stream, info) => { - let buffer = ''; - stream.on('data', (chunk) => { - buffer += chunk.toString('utf8'); - }); - stream.on('end', () => { - if (info.which === 'HEADER') { - header = buffer; - } else if (info.which === 'TEXT') { - text = buffer; - } - }); - }); - - msg.on('end', () => { - if (!messageId) { - console.error('No message ID found for email'); - return; + stream.on('end', () => { + if (info.which === 'HEADER') { + header = buffer; + } else if (info.which === 'TEXT') { + text = buffer; } - - const parsedHeader = Imap.parseHeader(header); - const email = { - id: messageId, - from: parsedHeader.from?.[0] || '', - to: parsedHeader.to?.[0] || '', - subject: parsedHeader.subject?.[0] || '(No subject)', - date: parsedHeader.date?.[0] || new Date().toISOString(), - body: text, - folder: folderName, - flags: messageFlags - }; - emailsByFolder[folderName].push(email); }); }); - fetch.on('error', (err) => { - console.error(`Error fetching emails from ${folderName}:`, err); - activeFetches--; - checkCompletion(); - }); + msg.on('end', () => { + if (!messageId) { + console.error('No message ID found for email'); + return; + } - fetch.on('end', () => { - activeFetches--; - checkCompletion(); + const parsedHeader = Imap.parseHeader(header); + const email = { + id: messageId, + from: parsedHeader.from?.[0] || '', + to: parsedHeader.to?.[0] || '', + subject: parsedHeader.subject?.[0] || '(No subject)', + date: parsedHeader.date?.[0] || new Date().toISOString(), + body: text, + folder: folder, + flags: messageFlags + }; + emails.push(email); }); }); + + fetch.on('error', (err) => { + console.error(`Error fetching emails from ${folder}:`, err); + clearTimeout(timeout); + imap.end(); + resolve(NextResponse.json({ emails: [], error: `Failed to fetch emails from ${folder}` })); + }); + + fetch.on('end', () => { + clearTimeout(timeout); + imap.end(); + resolve(NextResponse.json({ + emails: emails, + folders: availableMailboxes, + mailUrl: process.env.NEXTCLOUD_URL ? `${process.env.NEXTCLOUD_URL}/apps/mail/` : null + })); + }); }); }); }); diff --git a/app/mail/page.tsx b/app/mail/page.tsx index 52ea7f2..771e58d 100644 --- a/app/mail/page.tsx +++ b/app/mail/page.tsx @@ -540,7 +540,7 @@ export default function MailPage() { setLoading(true); setError(null); - const response = await fetch('/api/mail'); + const response = await fetch(`/api/mail?folder=${currentView}`); if (!response.ok) { throw new Error('Failed to load emails'); }