diff --git a/apps/be/common/src/mail/mail.config.ts b/apps/be/common/src/mail/mail.config.ts index e38cae3..6e7f68f 100644 --- a/apps/be/common/src/mail/mail.config.ts +++ b/apps/be/common/src/mail/mail.config.ts @@ -3,44 +3,78 @@ import { MailerOptionsFactory } from '@nestjs-modules/mailer'; import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter'; import { ConfigService } from '@nestjs/config'; import { Injectable } from '@nestjs/common'; +import { PinoLogger } from 'nestjs-pino'; import { AllConfig } from '~be/app/config'; import { TTransport } from './types/mailer.type'; +import { GMAIL_TRANSPORT, RESEND_TRANSPORT, SENDGRID_TRANSPORT } from './mail.constant'; @Injectable() export class MailerConfig implements MailerOptionsFactory { - constructor(private readonly configService: ConfigService) {} - private readonly DEFAULT_SENDER = this.configService.get('mail.sender', { infer: true, }); - public readonly SendGridTransport: TTransport = { - host: this.configService.getOrThrow('mail.sendgridHost', { infer: true }), - secure: true, - auth: { - user: this.configService.getOrThrow('mail.sendgridUser', { infer: true }), - pass: this.configService.getOrThrow('mail.sendgridPassword', { infer: true }), - }, - }; + constructor( + private readonly configService: ConfigService, + private readonly logger: PinoLogger, + ) {} + + public get MailTransport(): { name: string; config: TTransport }[] { + const transporters: { name: string; config: TTransport }[] = []; + if (this.configService.get('mail.sendgridPassword', { infer: true })) { + transporters.push({ + name: SENDGRID_TRANSPORT, + config: { + host: + this.configService.get('mail.sendgridHost', { infer: true }) ?? + 'smtp.sendgrid.net', + auth: { + user: + this.configService.get('mail.sendgridUser', { infer: true }) ?? + 'apikey', + pass: this.configService.getOrThrow('mail.sendgridPassword', { + infer: true, + }), + }, + port: 2525, + }, + }); + } + + if (this.configService.get('mail.resendApiKey', { infer: true })) { + transporters.push({ + name: RESEND_TRANSPORT, + config: { + host: + this.configService.get('mail.resendHost', { infer: true }) ?? + 'smtp.resend.com', + auth: { + user: + this.configService.get('mail.resendUser', { infer: true }) ?? 'resend', + pass: this.configService.getOrThrow('mail.resendApiKey', { infer: true }), + }, + }, + }); + } - public readonly ResendTransport: TTransport = { - host: this.configService.getOrThrow('mail.resendHost', { infer: true }), - secure: true, - auth: { - user: this.configService.getOrThrow('mail.resendUser', { infer: true }), - pass: this.configService.getOrThrow('mail.resendApiKey', { infer: true }), - }, - }; + if (this.configService.get('mail.gmailPassword', { infer: true })) { + transporters.push({ + name: GMAIL_TRANSPORT, + config: { + host: + this.configService.get('mail.gmailHost', { infer: true }) ?? + 'smtp.gmail.com', + auth: { + user: this.configService.getOrThrow('mail.gmailUser', { infer: true }), + pass: this.configService.getOrThrow('mail.gmailPassword', { infer: true }), + }, + }, + }); + } - public readonly GmailTransport: TTransport = { - host: this.configService.getOrThrow('mail.gmailHost', { infer: true }) ?? 'smtp.gmail.com', - secure: true, - auth: { - user: this.configService.getOrThrow('mail.gmailUser', { infer: true }), - pass: this.configService.getOrThrow('mail.gmailPassword', { infer: true }), - }, - }; + return transporters; + } public buildMailerOptions(transport: TTransport) { return { @@ -64,6 +98,11 @@ export class MailerConfig implements MailerOptionsFactory { } createMailerOptions() { - return this.buildMailerOptions(this.GmailTransport); + if (this.MailTransport?.length === 0) { + this.logger.warn(`No mailer transport configured. Mail will not be sent.`); + return {}; + } + + return this.buildMailerOptions(this.MailTransport[0].config); } } diff --git a/apps/be/common/src/mail/mail.service.ts b/apps/be/common/src/mail/mail.service.ts index f1167f5..ac3c509 100644 --- a/apps/be/common/src/mail/mail.service.ts +++ b/apps/be/common/src/mail/mail.service.ts @@ -7,14 +7,14 @@ import { Attachment } from 'nodemailer/lib/mailer'; import { MaybeType } from '../utils/types'; import { I18nTranslations } from '../i18n'; import { MailerConfig } from './mail.config'; -import { GMAIL_TRANSPORT, RESEND_TRANSPORT, SENDGRID_TRANSPORT } from './mail.constant'; +import { SENDGRID_TRANSPORT } from './mail.constant'; import { ErrorNotificationEnum } from '~be/app/tasks/enums'; @Injectable() export class MailService { - private readonly TRANSPORTERS = [SENDGRID_TRANSPORT, RESEND_TRANSPORT, GMAIL_TRANSPORT]; - private readonly MAX_RETRIES = this.TRANSPORTERS.length; + private readonly TRANSPORTERS: string[] = []; + private readonly MAX_RETRIES: number = 0; private readonly BASE_ATTACHMENT: Attachment[] = []; constructor( @@ -23,9 +23,11 @@ export class MailService { private readonly i18n: I18nService, private readonly mailConfig: MailerConfig, ) { - this.mailerService.addTransporter(SENDGRID_TRANSPORT, this.mailConfig.SendGridTransport); - this.mailerService.addTransporter(RESEND_TRANSPORT, this.mailConfig.ResendTransport); - this.mailerService.addTransporter(GMAIL_TRANSPORT, this.mailConfig.GmailTransport); + for (const transporter of this.mailConfig.MailTransport) { + this.TRANSPORTERS.push(transporter.name); + this.mailerService.addTransporter(transporter.name, transporter.config); + } + this.MAX_RETRIES = this.mailConfig.MailTransport.length; this.logger.setContext(MailService.name); } diff --git a/apps/be/common/src/mail/types/mailer.type.ts b/apps/be/common/src/mail/types/mailer.type.ts index 3305e11..0be4038 100644 --- a/apps/be/common/src/mail/types/mailer.type.ts +++ b/apps/be/common/src/mail/types/mailer.type.ts @@ -1,3 +1,5 @@ +import * as smtpTransport from 'nodemailer/lib/smtp-transport'; + export type TTransport = { host: string; secure?: boolean; @@ -5,4 +7,4 @@ export type TTransport = { user: string; pass: string; }; -}; +} & smtpTransport.Options;