courrier multi account restore compose
This commit is contained in:
parent
e2805dca07
commit
266805950e
@ -266,114 +266,84 @@ interface FetchOptions {
|
|||||||
*/
|
*/
|
||||||
export async function getEmails(
|
export async function getEmails(
|
||||||
userId: string,
|
userId: string,
|
||||||
folder: string = 'INBOX',
|
folder: string,
|
||||||
page: number = 1,
|
page: number = 1,
|
||||||
perPage: number = 20,
|
perPage: number = 20,
|
||||||
searchQuery: string = '',
|
|
||||||
accountId?: string
|
accountId?: string
|
||||||
): Promise<EmailListResult> {
|
): Promise<EmailMessage[]> {
|
||||||
console.log(`Fetching emails for user ${userId}${accountId ? ` account ${accountId}` : ''} in folder ${folder}`);
|
|
||||||
|
|
||||||
// Extract the base folder name if it's an account-specific folder
|
|
||||||
const baseFolder = accountId && folder.includes(`-${accountId}`)
|
|
||||||
? folder.split(`-${accountId}`)[0]
|
|
||||||
: folder;
|
|
||||||
|
|
||||||
console.log(`Using base folder name: ${baseFolder} for IMAP operations`);
|
|
||||||
|
|
||||||
// Try to get from cache first
|
|
||||||
const cached = await getCachedEmailList(userId, accountId || 'default', folder, page, perPage);
|
|
||||||
if (cached) {
|
|
||||||
console.log(`Using cached email list for ${userId}${accountId ? ` account ${accountId}` : ''} in folder ${folder}`);
|
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get IMAP connection for the specific account
|
|
||||||
const client = await getImapConnection(userId, accountId);
|
|
||||||
if (!client) {
|
|
||||||
throw new Error('Failed to get IMAP connection');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Open the mailbox using the base folder name
|
// Extract the base folder name by removing the accountId suffix if present
|
||||||
await client.mailboxOpen(baseFolder);
|
const baseFolder = accountId && folder.includes(`-${accountId}`)
|
||||||
|
? folder.split(`-${accountId}`)[0]
|
||||||
|
: folder;
|
||||||
|
|
||||||
// Get total count of messages
|
console.log(`Fetching emails for folder: ${baseFolder} (original: ${folder})`);
|
||||||
const status = await client.status(baseFolder, { messages: true });
|
|
||||||
const totalEmails = status.messages || 0;
|
|
||||||
const totalPages = Math.ceil(totalEmails / perPage);
|
|
||||||
|
|
||||||
// Calculate the range of messages to fetch
|
// Get IMAP connection for the account
|
||||||
const start = (page - 1) * perPage + 1;
|
const imap = await getImapConnection(userId, accountId);
|
||||||
const end = Math.min(start + perPage - 1, totalEmails);
|
if (!imap) {
|
||||||
|
throw new Error('Failed to establish IMAP connection');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the mailbox
|
||||||
|
await imap.mailboxOpen(baseFolder);
|
||||||
|
|
||||||
|
// Calculate message range for pagination
|
||||||
|
const totalMessages = await imap.status(baseFolder, { messages: true });
|
||||||
|
const total = totalMessages.messages || 0;
|
||||||
|
const start = Math.max(1, total - (page * perPage) + 1);
|
||||||
|
const end = Math.max(1, total - ((page - 1) * perPage));
|
||||||
|
|
||||||
|
// Fetch messages
|
||||||
|
const messages = await imap.fetch(`${start}:${end}`, {
|
||||||
|
envelope: true,
|
||||||
|
flags: true,
|
||||||
|
bodyStructure: true,
|
||||||
|
uid: true
|
||||||
|
});
|
||||||
|
|
||||||
const emails: EmailMessage[] = [];
|
const emails: EmailMessage[] = [];
|
||||||
|
|
||||||
if (totalEmails > 0) {
|
for await (const message of messages) {
|
||||||
// Fetch messages in the specified range
|
const email: EmailMessage = {
|
||||||
const messages = await client.fetch(`${start}:${end}`, {
|
id: message.uid.toString(),
|
||||||
envelope: true,
|
from: (message.envelope?.from || []).map(addr => ({
|
||||||
flags: true,
|
name: addr.name || '',
|
||||||
bodyStructure: true,
|
address: addr.address || ''
|
||||||
size: true,
|
})),
|
||||||
bodyParts: ['HEADER']
|
to: (message.envelope?.to || []).map(addr => ({
|
||||||
});
|
name: addr.name || '',
|
||||||
|
address: addr.address || ''
|
||||||
for await (const message of messages) {
|
})),
|
||||||
const email: EmailMessage = {
|
subject: message.envelope?.subject || '',
|
||||||
id: message.uid.toString(),
|
date: message.envelope?.date || new Date(),
|
||||||
from: (message.envelope?.from || []).map(addr => ({
|
flags: {
|
||||||
name: addr.name || '',
|
seen: message.flags.has('\\Seen'),
|
||||||
address: addr.address || ''
|
answered: message.flags.has('\\Answered'),
|
||||||
})),
|
flagged: message.flags.has('\\Flagged'),
|
||||||
to: (message.envelope?.to || []).map(addr => ({
|
draft: message.flags.has('\\Draft'),
|
||||||
name: addr.name || '',
|
deleted: message.flags.has('\\Deleted')
|
||||||
address: addr.address || ''
|
},
|
||||||
})),
|
size: message.size || 0,
|
||||||
subject: message.envelope?.subject || '',
|
hasAttachments: message.bodyStructure?.childNodes?.some(node => node.disposition === 'attachment') || false,
|
||||||
date: message.internalDate || new Date(),
|
folder: folder,
|
||||||
flags: {
|
contentFetched: false,
|
||||||
seen: message.flags.has('\\Seen'),
|
accountId: accountId || '',
|
||||||
answered: message.flags.has('\\Answered'),
|
content: '',
|
||||||
flagged: message.flags.has('\\Flagged'),
|
messageId: message.envelope?.messageId || undefined
|
||||||
draft: message.flags.has('\\Draft'),
|
};
|
||||||
deleted: message.flags.has('\\Deleted')
|
emails.push(email);
|
||||||
},
|
|
||||||
size: message.size || 0,
|
|
||||||
hasAttachments: message.bodyStructure?.childNodes?.some(node => node.disposition === 'attachment') || false,
|
|
||||||
folder: folder, // Use the original folder name with account ID
|
|
||||||
contentFetched: false,
|
|
||||||
accountId: accountId,
|
|
||||||
content: '',
|
|
||||||
messageId: message.envelope?.messageId || undefined
|
|
||||||
};
|
|
||||||
emails.push(email);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const result: EmailListResult = {
|
// Cache the result
|
||||||
emails,
|
if (accountId) {
|
||||||
totalEmails,
|
await cacheEmailList(userId, accountId, folder, page, perPage, emails);
|
||||||
page,
|
}
|
||||||
perPage,
|
|
||||||
totalPages,
|
|
||||||
folder,
|
|
||||||
mailboxes: await getMailboxes(client, accountId) // Pass accountId to getMailboxes
|
|
||||||
};
|
|
||||||
|
|
||||||
// Cache the result with the account-specific folder
|
return emails;
|
||||||
await cacheEmailList(userId, accountId || 'default', folder, page, perPage, result);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Error fetching emails for folder ${baseFolder}:`, error);
|
console.error(`Error fetching emails for folder ${folder}:`, error);
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
await client.mailboxClose();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error closing mailbox:', error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,7 +564,7 @@ export async function getMailboxes(client: ImapFlow, accountId?: string): Promis
|
|||||||
try {
|
try {
|
||||||
const mailboxes = await client.list();
|
const mailboxes = await client.list();
|
||||||
|
|
||||||
// Map special folders to standard names, but keep account-specific paths
|
// Map special folders to standard names
|
||||||
const specialFolders = new Map<string, string>([
|
const specialFolders = new Map<string, string>([
|
||||||
['Sent Messages', 'Sent'],
|
['Sent Messages', 'Sent'],
|
||||||
['Sent Items', 'Sent'],
|
['Sent Items', 'Sent'],
|
||||||
@ -604,31 +574,31 @@ export async function getMailboxes(client: ImapFlow, accountId?: string): Promis
|
|||||||
['Spam', 'Junk']
|
['Spam', 'Junk']
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Process mailboxes and map special folders while preserving account-specific paths
|
// Process mailboxes and map special folders
|
||||||
const processedMailboxes = mailboxes.map(mailbox => {
|
const processedMailboxes = mailboxes.map(mailbox => {
|
||||||
const path = mailbox.path;
|
const path = mailbox.path;
|
||||||
// Check if this is a special folder
|
// Check if this is a special folder
|
||||||
for (const [special, standard] of specialFolders) {
|
for (const [special, standard] of specialFolders) {
|
||||||
if (path.includes(special)) {
|
if (path.includes(special)) {
|
||||||
// Include accountId in the folder name to make it unique per account
|
return standard;
|
||||||
return accountId ? `${standard}-${accountId}` : standard;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Include accountId in the folder name to make it unique per account
|
return path;
|
||||||
return accountId ? `${path}-${accountId}` : path;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ensure we have all standard folders with account-specific names
|
// Ensure we have all standard folders
|
||||||
const standardFolders = accountId
|
const standardFolders = ['INBOX', 'Sent', 'Drafts', 'Trash', 'Junk'];
|
||||||
? ['INBOX', 'Sent', 'Drafts', 'Trash', 'Junk'].map(f => `${f}-${accountId}`)
|
|
||||||
: ['INBOX', 'Sent', 'Drafts', 'Trash', 'Junk'];
|
|
||||||
|
|
||||||
|
// Combine standard folders with custom folders
|
||||||
const uniqueFolders = new Set([...standardFolders, ...processedMailboxes]);
|
const uniqueFolders = new Set([...standardFolders, ...processedMailboxes]);
|
||||||
|
|
||||||
return Array.from(uniqueFolders);
|
// If accountId is provided, append it to each folder name
|
||||||
|
return accountId
|
||||||
|
? Array.from(uniqueFolders).map(f => `${f}-${accountId}`)
|
||||||
|
: Array.from(uniqueFolders);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching mailboxes:', error);
|
console.error('Error fetching mailboxes:', error);
|
||||||
// Return default folders on error, with account-specific names if accountId is provided
|
// Return default folders on error
|
||||||
const defaultFolders = ['INBOX', 'Sent', 'Drafts', 'Trash', 'Junk'];
|
const defaultFolders = ['INBOX', 'Sent', 'Drafts', 'Trash', 'Junk'];
|
||||||
return accountId
|
return accountId
|
||||||
? defaultFolders.map(f => `${f}-${accountId}`)
|
? defaultFolders.map(f => `${f}-${accountId}`)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user