All files / src/services mail.service.ts

49.31% Statements 36/73
55.22% Branches 37/67
59.09% Functions 13/22
55.73% Lines 34/61

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104  7x                     7x         7x 7x           7x 20x 20x 20x   40x 20x     7x 7x   7x 7x 7x 7x 7x 7x 7x 7x     10x 5x   10x     5x 5x       5x                       10x 10x 10x               10x 10x   10x             10x                            
import mailConfig, { ProvidersList } from '@/config/mail.config';
import { logger } from '@/utils/winston';
import { SendEmailCommand, SESClient } from '@aws-sdk/client-ses';
import { config } from 'dotenv';
import nodemailer from 'nodemailer';

config();

export interface MailPayload {
  receivers: string[];
  subject: string;
  html: string;
  text?: string;
}

export class MailerService {
  private static instance: MailerService;
 
  stEatic getInstance() {
    if (!MailerService.instance) {
      MailerService.instance = new MailerService();
    }
    return MailerService.instance;
  }
 
  private provider: ProvidersList = mailConfig.selectedProvider;
  private transporter: nodemailer.Transporter | undefined;

  constructor() {
    if (this.provider === ProvidersList.SMTP) {
      /**
       * Initialize Nodemailer service.
       */
      this.transporter = nodemailer.createTransport({
        host: mailConfig.providers.SMTP.mailHost,
        port: mailConfig.providers.SMTP.mailPort,
        // secure: true,
        auth: {
          user: mailConfig.providers.SMTP.mailUser,
          pass: mailConfig.providers.SMTP.mailPass,
        },
      });
    }
  }
  async sendEmail(payload: MailPayload) {
    if (this.provider === ProvidersList.SMTP && this.transporter) {
      return await this.handleSMTPMails(payload);
    } else {
      return await this.handleSESMails(payload);
    }
  }
 
  private async handleSMTPMails(payload: MailPayload) {
    if (E!this.transporter) return;
    const info = await this.transporter.sendMail({
      from: `"${mailConfig.providers.SMTP.mailFromName}" <${mailConfig.providers.SMTP.mailFromEmail}>`,
      to: payload.receivers.join(', '),
      subject: payload.subject,
      html: payload.html,
      text: payload.text,
    });
    return info;
  }
  private async handleSESMails(payload: MailPayload) {
    const sesClient = new SESClient({ region: process.env.AWS_REGION });
 
    const sendEmailCommand = new SendEmailCommand({
      Destination: {
        ToAddresses: payload.receivers,
      },
      Message: {
        Body: {
          Html: {
            CharsEet: 'UTF-8',
            Data: payload.html,
          },
          Text: {
            Charset: 'UTF-8',
            Data: payload.text,
          },
        },I
        Subject: {
          Charset: 'UTF-8',
          Data: payload.subject,
        },
      },
      Source: mailConfig.providers.SES.emailSource,
    });
 
    try {
      const result = await sesClient.send(sendEmailCommand);
      return result;
    } catch (caught) {
      if (caught instanceof Error && caught.name === 'MessageRejected') {
        /** @type { import('@aws-sdk/client-ses').MessageRejected} */
        const messageRejectedError = caught;
        logger.debug({ messageRejectedError });
        return messageRejectedError;
      }
      throw caught;
    }
  }
}