diff --git a/lib/services/email-service.ts b/lib/services/email-service.ts index 1635f5b8..7a3a742f 100644 --- a/lib/services/email-service.ts +++ b/lib/services/email-service.ts @@ -416,39 +416,56 @@ export async function getEmailContent( throw new Error('Email ID must be a number'); } - // Try to get from cache first - const cachedEmail = await getCachedEmailContent(userId, accountId || folder, emailId); + // Try to get from cache first, using account-specific cache key + const cacheKey = accountId ? `${accountId}:${folder}` : folder; + const cachedEmail = await getCachedEmailContent(userId, cacheKey, emailId); if (cachedEmail) { - console.log(`Using cached email content for ${userId}:${emailId}`); + console.log(`Using cached email content for ${userId}:${accountId}:${emailId}`); return cachedEmail; } - console.log(`Cache miss for email content ${userId}:${emailId}, fetching from IMAP`); + console.log(`Cache miss for email content ${userId}:${accountId}:${emailId}, fetching from IMAP`); const client = await getImapConnection(userId, accountId); try { - // Remove accountId prefix if present + // Remove accountId prefix if present in folder name const actualFolder = folder.includes(':') ? folder.split(':')[1] : folder; - // Log connection details - console.log(`[DEBUG] Fetching email ${emailId} from folder ${actualFolder} for account ${accountId}`); + // Log connection details with account context + console.log(`[DEBUG] Fetching email ${emailId} from folder ${actualFolder} for account ${accountId || 'default'}`); // Open mailbox with error handling const mailbox = await client.mailboxOpen(actualFolder); if (!mailbox || typeof mailbox === 'boolean') { - throw new Error(`Failed to open mailbox: ${actualFolder}`); + throw new Error(`Failed to open mailbox: ${actualFolder} for account ${accountId || 'default'}`); } - // Log mailbox status - console.log(`[DEBUG] Mailbox ${actualFolder} opened, total messages: ${mailbox.exists}`); + // Log mailbox status with account context + console.log(`[DEBUG] Mailbox ${actualFolder} opened for account ${accountId || 'default'}, total messages: ${mailbox.exists}`); + + // Get the UIDVALIDITY and UIDNEXT values + const uidValidity = mailbox.uidValidity; + const uidNext = mailbox.uidNext; + + console.log(`[DEBUG] Mailbox UIDVALIDITY: ${uidValidity}, UIDNEXT: ${uidNext} for account ${accountId || 'default'}`); // Validate UID exists in mailbox - if (numericId > mailbox.uidNext) { - throw new Error(`Email ID ${numericId} is greater than the highest UID in mailbox (${mailbox.uidNext})`); + if (numericId >= uidNext) { + throw new Error(`Email ID ${numericId} is greater than or equal to the highest UID in mailbox (${uidNext}) for account ${accountId || 'default'}`); } - const message = await client.fetchOne(numericId.toString(), { + // First, try to get the sequence number for this UID + const searchResult = await client.search({ uid: numericId.toString() }); + if (!searchResult || searchResult.length === 0) { + throw new Error(`Email with UID ${numericId} not found in folder ${actualFolder} for account ${accountId || 'default'}`); + } + + const sequenceNumber = searchResult[0]; + console.log(`[DEBUG] Found sequence number ${sequenceNumber} for UID ${numericId} in account ${accountId || 'default'}`); + + // Now fetch using the sequence number + const message = await client.fetchOne(sequenceNumber.toString(), { source: true, envelope: true, flags: true, @@ -456,15 +473,15 @@ export async function getEmailContent( }); if (!message) { - throw new Error(`Email not found with ID ${numericId} in folder ${actualFolder}`); + throw new Error(`Email not found with sequence number ${sequenceNumber} in folder ${actualFolder} for account ${accountId || 'default'}`); } const { source, envelope, flags, size } = message; // 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 + skipHtmlToText: true, + keepCidLinks: true }); // Convert flags from Set to boolean checks @@ -513,11 +530,12 @@ export async function getEmailContent( }, folder: actualFolder, contentFetched: true, - size: size || 0 + size: size || 0, + accountId: accountId || 'default' // Add accountId to the email object }; - // Cache the email content - await cacheEmailContent(userId, accountId || folder, emailId, email); + // Cache the email content with account-specific key + await cacheEmailContent(userId, cacheKey, emailId, email); return email; } catch (error) { @@ -526,7 +544,8 @@ export async function getEmailContent( emailId, folder, accountId, - error: error instanceof Error ? error.message : 'Unknown error' + error: error instanceof Error ? error.message : 'Unknown error', + details: error instanceof Error ? error.stack : undefined }); throw error; } finally {