diff --git a/app/api/courrier/route.ts b/app/api/courrier/route.ts
index 57c605b7..b3795dfc 100644
--- a/app/api/courrier/route.ts
+++ b/app/api/courrier/route.ts
@@ -41,7 +41,7 @@ export async function GET(request: Request) {
const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId;
// Use the most specific account ID available
- const effectiveAccountId = folderAccountId || accountId || 'default';
+ let effectiveAccountId = folderAccountId || accountId || 'default';
// Normalize folder name by removing account prefix if present
const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder;
diff --git a/components/email/EmailSidebar.tsx b/components/email/EmailSidebar.tsx
index 355ea64a..074da157 100644
--- a/components/email/EmailSidebar.tsx
+++ b/components/email/EmailSidebar.tsx
@@ -190,8 +190,14 @@ export default function EmailSidebar({
variant="ghost"
className={`w-full justify-start text-xs py-1 h-7 ${isSelected ? 'bg-gray-100' : ''}`}
onClick={() => {
- console.log(`Folder button clicked: ${prefixedFolder}`);
- onFolderChange(prefixedFolder, accountId);
+ console.log(`Folder button clicked: folder=${prefixedFolder}, accountId=${accountId}, normalized=${baseFolderName}`);
+
+ // Always ensure the folder name includes the account ID prefix
+ const fullyPrefixedFolder = folder.includes(':') ? folder : `${accountId}:${folder}`;
+
+ // Make sure we pass the EXACT accountId parameter here, not the folder's extracted account ID
+ console.log(`Calling onFolderChange with folder=${fullyPrefixedFolder}, accountId=${accountId}`);
+ onFolderChange(fullyPrefixedFolder, accountId);
}}
>
diff --git a/lib/services/email-service.ts b/lib/services/email-service.ts
index 640214a4..5cb08eaa 100644
--- a/lib/services/email-service.ts
+++ b/lib/services/email-service.ts
@@ -65,10 +65,28 @@ export async function getImapConnection(
): Promise {
console.log(`Getting IMAP connection for user ${userId}${accountId ? ` account ${accountId}` : ''}`);
+ // Special handling for 'default' accountId - find the first available account
+ if (!accountId || accountId === 'default') {
+ console.log(`No specific account provided or 'default' requested, trying to find first account for user ${userId}`);
+
+ // Query to find all accounts for this user
+ const accounts = await prisma.mailCredentials.findMany({
+ where: { userId },
+ orderBy: { createdAt: 'asc' },
+ take: 1
+ });
+
+ if (accounts && accounts.length > 0) {
+ const firstAccount = accounts[0];
+ console.log(`Using first available account: ${firstAccount.id} (${firstAccount.email})`);
+ accountId = firstAccount.id;
+ } else {
+ throw new Error('No email accounts configured for this user');
+ }
+ }
+
// First try to get credentials from Redis cache
- let credentials = accountId
- ? await getCachedEmailCredentials(userId, accountId)
- : await getCachedEmailCredentials(userId, 'default');
+ let credentials = await getCachedEmailCredentials(userId, accountId);
// If not in cache, get from database and cache them
if (!credentials) {
@@ -79,7 +97,7 @@ export async function getImapConnection(
}
// Cache credentials for future use
- await cacheEmailCredentials(userId, accountId || 'default', credentials);
+ await cacheEmailCredentials(userId, accountId, credentials);
}
// Validate credentials
@@ -94,7 +112,7 @@ export async function getImapConnection(
}
// Use accountId in connection key to ensure different accounts get different connections
- const connectionKey = `${userId}:${accountId || 'default'}`;
+ const connectionKey = `${userId}:${accountId}`;
const existingConnection = connectionPool[connectionKey];
// Try to get session data from Redis
@@ -279,127 +297,134 @@ export async function getEmails(
perPage: number = 20,
accountId?: string
): Promise {
- let client: ImapFlow | undefined;
+ // Normalize folder name and handle account ID
+ console.log(`[getEmails] Processing request for folder: ${folder}, normalized to ${folder}, account: ${accountId || 'default'}`);
try {
- // Extract account ID from folder name if present and none was explicitly provided
- const folderAccountId = folder.includes(':') ? folder.split(':')[0] : accountId;
+ // The getImapConnection function already handles 'default' accountId by finding the first available account
+ const client = await getImapConnection(userId, accountId);
- // Use the most specific account ID available
- const effectiveAccountId = folderAccountId || accountId || 'default';
+ // At this point, accountId has been resolved to an actual account ID by getImapConnection
+ // Store the resolved accountId in a variable that is guaranteed to be a string
+ const resolvedAccountId = accountId || 'default';
- // Normalize folder name by removing account prefix if present
- const normalizedFolder = folder.includes(':') ? folder.split(':')[1] : folder;
-
- console.log(`[getEmails] Processing request for folder: ${folder}, normalized to ${normalizedFolder}, account: ${effectiveAccountId}`);
+ // Attempt to select the mailbox
+ try {
+ const mailboxInfo = await client.mailboxOpen(folder);
+ console.log(`Opened mailbox ${folder} with ${mailboxInfo.exists} messages`);
+
+ // Get list of all mailboxes for UI
+ const mailboxes = await getMailboxes(client, resolvedAccountId);
+
+ // Calculate pagination
+ const totalEmails = mailboxInfo.exists || 0;
+ const totalPages = Math.ceil(totalEmails / perPage);
+
+ // Check if mailbox is empty
+ if (totalEmails === 0) {
+ // Cache the empty result
+ const emptyResult = {
+ emails: [],
+ totalEmails: 0,
+ page,
+ perPage,
+ totalPages: 0,
+ folder,
+ mailboxes
+ };
+
+ await cacheEmailList(
+ userId,
+ resolvedAccountId, // Use the guaranteed string account ID
+ folder,
+ page,
+ perPage,
+ emptyResult
+ );
+
+ return emptyResult;
+ }
- // Get IMAP connection using the effective account ID
- client = await getImapConnection(userId, effectiveAccountId);
- if (!client) {
- throw new Error('Failed to establish IMAP connection');
- }
+ // Calculate message range for pagination
+ const start = Math.max(1, totalEmails - (page * perPage) + 1);
+ const end = Math.max(1, totalEmails - ((page - 1) * perPage));
+ console.log(`Fetching messages ${start}:${end} from ${folder} for account ${resolvedAccountId}`);
- // Open mailbox with the normalized folder name
- await client.mailboxOpen(normalizedFolder);
- const mailbox = client.mailbox;
- if (!mailbox || typeof mailbox === 'boolean') {
- throw new Error(`Failed to open mailbox: ${normalizedFolder}`);
- }
+ // Fetch messages
+ const messages = await client.fetch(`${start}:${end}`, {
+ envelope: true,
+ flags: true,
+ bodyStructure: true
+ });
- // Get total messages
- const total = mailbox.exists || 0;
- console.log(`Total messages in ${normalizedFolder} for account ${effectiveAccountId}: ${total}`);
+ const emails: EmailMessage[] = [];
+ for await (const message of messages) {
+ const email: EmailMessage = {
+ id: message.uid.toString(),
+ from: message.envelope.from?.map(addr => ({
+ name: addr.name || '',
+ address: addr.address || ''
+ })) || [],
+ to: message.envelope.to?.map(addr => ({
+ name: addr.name || '',
+ address: addr.address || ''
+ })) || [],
+ subject: message.envelope.subject || '',
+ date: message.envelope.date || new Date(),
+ flags: {
+ seen: message.flags.has('\\Seen'),
+ flagged: message.flags.has('\\Flagged'),
+ answered: message.flags.has('\\Answered'),
+ draft: message.flags.has('\\Draft'),
+ deleted: message.flags.has('\\Deleted')
+ },
+ size: message.size || 0,
+ hasAttachments: message.bodyStructure?.childNodes?.some(node => node.disposition === 'attachment') || false,
+ folder: folder,
+ contentFetched: false,
+ accountId: resolvedAccountId,
+ content: {
+ text: '',
+ html: ''
+ }
+ };
+ emails.push(email);
+ }
- // If no messages, return empty result
- if (total === 0) {
- return {
- emails: [],
- totalEmails: 0,
+ // Cache the result with the effective account ID
+ await cacheEmailList(
+ userId,
+ resolvedAccountId, // Use the guaranteed string account ID
+ folder,
page,
perPage,
- totalPages: 0,
- folder: normalizedFolder,
- mailboxes: []
- };
- }
-
- // Calculate message range for pagination
- const start = Math.max(1, total - (page * perPage) + 1);
- const end = Math.max(1, total - ((page - 1) * perPage));
- console.log(`Fetching messages ${start}:${end} from ${normalizedFolder} for account ${effectiveAccountId}`);
-
- // Fetch messages
- const messages = await client.fetch(`${start}:${end}`, {
- envelope: true,
- flags: true,
- bodyStructure: true
- });
-
- const emails: EmailMessage[] = [];
- for await (const message of messages) {
- const email: EmailMessage = {
- id: message.uid.toString(),
- from: message.envelope.from?.map(addr => ({
- name: addr.name || '',
- address: addr.address || ''
- })) || [],
- to: message.envelope.to?.map(addr => ({
- name: addr.name || '',
- address: addr.address || ''
- })) || [],
- subject: message.envelope.subject || '',
- date: message.envelope.date || new Date(),
- flags: {
- seen: message.flags.has('\\Seen'),
- flagged: message.flags.has('\\Flagged'),
- answered: message.flags.has('\\Answered'),
- draft: message.flags.has('\\Draft'),
- deleted: message.flags.has('\\Deleted')
- },
- size: message.size || 0,
- hasAttachments: message.bodyStructure?.childNodes?.some(node => node.disposition === 'attachment') || false,
- folder: normalizedFolder,
- contentFetched: false,
- accountId: effectiveAccountId,
- content: {
- text: '',
- html: ''
+ {
+ emails,
+ totalEmails: totalEmails,
+ page,
+ perPage,
+ totalPages: Math.ceil(totalEmails / perPage),
+ folder: folder,
+ mailboxes: mailboxes
}
+ );
+
+ return {
+ emails,
+ totalEmails: totalEmails,
+ page,
+ perPage,
+ totalPages: Math.ceil(totalEmails / perPage),
+ folder: folder,
+ mailboxes: mailboxes
};
- emails.push(email);
+ } catch (error) {
+ console.error('Error fetching emails:', error);
+ throw error;
}
-
- // Cache the result with the effective account ID
- await cacheEmailList(userId, effectiveAccountId, normalizedFolder, page, perPage, {
- emails,
- totalEmails: total,
- page,
- perPage,
- totalPages: Math.ceil(total / perPage),
- folder: normalizedFolder,
- mailboxes: []
- });
-
- return {
- emails,
- totalEmails: total,
- page,
- perPage,
- totalPages: Math.ceil(total / perPage),
- folder: normalizedFolder,
- mailboxes: []
- };
} catch (error) {
console.error('Error fetching emails:', error);
throw error;
- } finally {
- if (client) {
- try {
- await client.mailboxClose();
- } catch (error) {
- console.error('Error closing mailbox:', error);
- }
- }
}
}