UNPKG

@snehal96/unimail

Version:

Unified email fetching & document extraction layer for modern web apps

71 lines (70 loc) 2.51 kB
import { ImapFlow } from 'imapflow'; import { EmailParserService } from '../services/EmailParserService.js'; export class ImapAdapter { constructor(config) { this.retries = 0; this.maxRetries = 3; this.config = config; this.client = new ImapFlow(config); this.emailParserService = new EmailParserService(); } log(msg, extra) { console.log(`[IMAP] ${msg}`, extra || ''); } async connectWithRetry() { while (this.retries < this.maxRetries) { try { await this.client.connect(); this.log('Connected successfully'); return; } catch (err) { this.retries++; this.log(`Connection failed (attempt ${this.retries})`, err); await new Promise(res => setTimeout(res, 1000 * this.retries)); // exponential backoff } } throw new Error(`Failed to connect after ${this.maxRetries} attempts`); } async fetchEmails({ since, limit = 10, mailbox = 'INBOX' }) { const output = []; await this.connectWithRetry(); try { await this.client.mailboxOpen(mailbox); let counter = 0; let normalized; for await (const msg of this.client.fetch({ since }, { source: true, uid: true })) { normalized = await this.emailParserService.parseEmail(msg.source, msg.uid.toString(), 'imap'); normalized.attachments = normalized.attachments.filter(att => { if (att.contentId && normalized.bodyHtml?.includes(`cid:${att.contentId.replace(/[<>]/g, '')}`)) { // This is likely an inline image referenced in the HTML return false; } return true; }); output.push(normalized); counter++; if (counter >= limit) break; } this.log(`Fetched ${output.length} email(s)`); return output; } catch (err) { this.log('Error during fetchEmails', err); throw err; } finally { await this.close(); } } async close() { try { await this.client.logout(); this.log('Disconnected cleanly'); } catch (err) { this.log('Error during logout', err); } } }