diff --git a/src/email/client.ts b/src/email/client.ts index 45e25ac..e1b7409 100644 --- a/src/email/client.ts +++ b/src/email/client.ts @@ -15,6 +15,7 @@ export enum EmailClientStatus { @Injectable() export class EmailClient { public readonly imapClient: Imap + private readonly mailboxName: string private mailbox?: Imap.Box private status: EmailClientStatus @@ -25,6 +26,7 @@ export class EmailClient { @Inject(ConfigService) private readonly configService: ConfigService, ) { + this.mailboxName = this.configService.getOrThrow('EMAIL_MAILBOX') this.imapClient = new Imap({ host: this.configService.getOrThrow('EMAIL_HOST'), port: this.configService.get('EMAIL_PORT', 993), @@ -90,8 +92,10 @@ export class EmailClient { ) if (newMessages > 0) { - const startingMessage = totalMessages - newMessages + 1 // starting message is inclusive - const emails = await this.fetchMails(`${startingMessage}`, '*') + const emails = await this.fetchMailsFrom( + totalMessages - (numMessages - 1), + ) + this.loggerService.debug(`Fetched ${emails.length} emails`) callback(emails) } } @@ -102,8 +106,7 @@ export class EmailClient { throw new Error('Not ready to listen') } - const mailbox = this.configService.get('EMAIL_MAILBOX', 'INBOX') - this.imapClient.openBox(mailbox, (error, mailbox) => { + this.imapClient.openBox(this.mailboxName, (error, mailbox) => { if (error) { this.loggerService.error('Error opening mailbox', { ...error, @@ -171,17 +174,13 @@ export class EmailClient { }) } - public async fetchMails(startingMessageId: string, endingMessageId: string) { + public async fetchMailsFrom(startingMessageSeqNo: number) { this.loggerService.debug( - `Fetching mails ${startingMessageId}:${endingMessageId}`, - ) - const fetcher = this.imapClient.fetch( - `${startingMessageId}:${endingMessageId}`, - { - bodies: '', - markSeen: true, - }, + `Fetching mails starting from ${startingMessageSeqNo}`, ) + const fetcher = this.imapClient.seq.fetch(`${startingMessageSeqNo}:*`, { + bodies: '', + }) return new Promise((res, rej) => { const generateEmailPromises: Promise[] = [] @@ -198,6 +197,18 @@ export class EmailClient { }) } + public async markMailsSeen(messageIds: string[]) { + this.loggerService.debug('Marking mails as seen', { messageIds }) + return new Promise((res, rej) => { + this.imapClient.addFlags(messageIds.join(','), ['\\Seen'], (error) => { + if (error != null) { + rej(error) + } + res() + }) + }) + } + private setupDefaultListeners() { this.imapClient.on('ready', () => { this.loggerService.debug('email client ready') diff --git a/src/email/provider.ts b/src/email/provider.ts index c3d4480..b1d6d57 100644 --- a/src/email/provider.ts +++ b/src/email/provider.ts @@ -19,7 +19,7 @@ export class EmailProvider { } private async handleReceivedEmails(emails: Email[]) { - this.emailsQueue.addBulk( + await this.emailsQueue.addBulk( emails.map((email) => ({ name: email.id, data: email })), ) } @@ -27,4 +27,8 @@ export class EmailProvider { public registerEmailListener() { this.emailClient.listen((emails) => this.handleReceivedEmails(emails)) } + + public async readEmails(emails: Email[]) { + await this.emailClient.markMailsSeen(emails.map((e) => e.id)) + } } diff --git a/src/waitingList/module.ts b/src/waitingList/module.ts index 83ffcbf..d601996 100644 --- a/src/waitingList/module.ts +++ b/src/waitingList/module.ts @@ -1,5 +1,6 @@ import { BullModule } from '@nestjs/bull' import { Module } from '@nestjs/common' +import { EmailModule } from 'src/email/module' import { ReservationsModule } from 'src/reservations/module' import { EMAILS_QUEUE_NAME } from '../email/config' @@ -13,6 +14,7 @@ import { WaitingListService } from './service' ReservationsModule, BullModule.registerQueue({ name: EMAILS_QUEUE_NAME }), BullModule.registerQueue({ name: RESERVATIONS_QUEUE_NAME }), + EmailModule, ], providers: [WaitingListService], exports: [WaitingListService], diff --git a/src/waitingList/service.ts b/src/waitingList/service.ts index 545a614..cddba33 100644 --- a/src/waitingList/service.ts +++ b/src/waitingList/service.ts @@ -1,6 +1,7 @@ import { InjectQueue, Process, Processor } from '@nestjs/bull' import { Inject } from '@nestjs/common' import { Job, Queue } from 'bull' +import { EmailProvider } from 'src/email/provider' import { ReservationsService } from 'src/reservations/service' import dayjs from '../common/dayjs' @@ -31,6 +32,9 @@ export class WaitingListService { @Inject(ReservationsService) private readonly reservationsService: ReservationsService, + @Inject(EmailProvider) + private readonly emailProvider: EmailProvider, + @Inject(LoggerService) private readonly loggerService: LoggerService, ) {} @@ -46,6 +50,7 @@ export class WaitingListService { if (!this.isRelevantEmail) return + await this.emailProvider.readEmails([email]) await this.handleWaitingListEmail(email) }