Add mail driver (#3205)
* Add node mailer packages * Init mailer module * Add logger transport * Use env variable to get transport * Revert "Add node mailer packages" This reverts commit 3fb954f0caef94266f96ff5f08de750073ab3491. * Add nodemailer * Use driver pattern * Use logger * Fix yarn install * Code review returns * Add configuration examples for smtp * Fix merge conflict * Add missing packages * Fix ci
This commit is contained in:
@ -0,0 +1,5 @@
|
||||
import { SendMailOptions } from 'nodemailer';
|
||||
|
||||
export interface EmailDriver {
|
||||
send(sendMailOptions: SendMailOptions): Promise<void>;
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
|
||||
import { SendMailOptions } from 'nodemailer';
|
||||
|
||||
import { EmailDriver } from 'src/integrations/email/drivers/interfaces/email-driver.interface';
|
||||
|
||||
export class LoggerDriver implements EmailDriver {
|
||||
private readonly logger = new Logger(LoggerDriver.name);
|
||||
|
||||
async send(sendMailOptions: SendMailOptions): Promise<void> {
|
||||
const info =
|
||||
`Sent email to: ${sendMailOptions.to}\n` +
|
||||
`From: ${sendMailOptions.from}\n` +
|
||||
`Subject: ${sendMailOptions.subject}\n` +
|
||||
`Content Text: ${sendMailOptions.text}\n` +
|
||||
`Content HTML: ${sendMailOptions.html}`;
|
||||
|
||||
this.logger.log(info);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
import { createTransport, Transporter, SendMailOptions } from 'nodemailer';
|
||||
import SMTPConnection from 'nodemailer/lib/smtp-connection';
|
||||
|
||||
import { EmailDriver } from 'src/integrations/email/drivers/interfaces/email-driver.interface';
|
||||
|
||||
export class SmtpDriver implements EmailDriver {
|
||||
private transport: Transporter;
|
||||
|
||||
constructor(options: SMTPConnection.Options) {
|
||||
this.transport = createTransport(options);
|
||||
}
|
||||
|
||||
async send(sendMailOptions: SendMailOptions): Promise<void> {
|
||||
await this.transport.sendMail(sendMailOptions);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
export const EMAIL_DRIVER = Symbol('EMAIL_DRIVER');
|
||||
@ -0,0 +1,40 @@
|
||||
import {
|
||||
EmailDriver,
|
||||
EmailModuleOptions,
|
||||
} from 'src/integrations/email/interfaces/email.interface';
|
||||
|
||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||
|
||||
export const emailModuleFactory = (
|
||||
environmentService: EnvironmentService,
|
||||
): EmailModuleOptions => {
|
||||
const driver = environmentService.getEmailDriver();
|
||||
|
||||
switch (driver) {
|
||||
case EmailDriver.Logger: {
|
||||
return;
|
||||
}
|
||||
case EmailDriver.Smtp: {
|
||||
const host = environmentService.getEmailHost();
|
||||
const port = environmentService.getEmailPort();
|
||||
const user = environmentService.getEmailUser();
|
||||
const pass = environmentService.getEmailPassword();
|
||||
|
||||
if (!(host && port)) {
|
||||
throw new Error(
|
||||
`${driver} email driver requires host: ${host} and port: ${port} to be defined, check your .env file`,
|
||||
);
|
||||
}
|
||||
|
||||
const auth = user && pass ? { user, pass } : undefined;
|
||||
|
||||
if (auth) {
|
||||
return { host, port, auth };
|
||||
}
|
||||
|
||||
return { host, port };
|
||||
}
|
||||
default:
|
||||
throw new Error(`Invalid email driver (${driver}), check your .env file`);
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,29 @@
|
||||
import { DynamicModule, Global } from '@nestjs/common';
|
||||
|
||||
import { EmailModuleAsyncOptions } from 'src/integrations/email/interfaces/email.interface';
|
||||
|
||||
import { EMAIL_DRIVER } from 'src/integrations/email/email.constants';
|
||||
import { LoggerDriver } from 'src/integrations/email/drivers/logger.driver';
|
||||
import { SmtpDriver } from 'src/integrations/email/drivers/smtp.driver';
|
||||
import { EmailService } from 'src/integrations/email/email.service';
|
||||
|
||||
@Global()
|
||||
export class EmailModule {
|
||||
static forRoot(options: EmailModuleAsyncOptions): DynamicModule {
|
||||
const provider = {
|
||||
provide: EMAIL_DRIVER,
|
||||
useFactory: (...args: any[]) => {
|
||||
const config = options.useFactory(...args);
|
||||
|
||||
return config ? new SmtpDriver(config) : new LoggerDriver();
|
||||
},
|
||||
inject: options.inject || [],
|
||||
};
|
||||
|
||||
return {
|
||||
module: EmailModule,
|
||||
providers: [EmailService, provider],
|
||||
exports: [EmailService],
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
|
||||
import { SendMailOptions } from 'nodemailer';
|
||||
|
||||
import { EmailDriver } from 'src/integrations/email/drivers/interfaces/email-driver.interface';
|
||||
|
||||
import { EMAIL_DRIVER } from 'src/integrations/email/email.constants';
|
||||
|
||||
@Injectable()
|
||||
export class EmailService implements EmailDriver {
|
||||
constructor(@Inject(EMAIL_DRIVER) private driver: EmailDriver) {}
|
||||
|
||||
async send(sendMailOptions: SendMailOptions): Promise<void> {
|
||||
await this.driver.send(sendMailOptions);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
import { FactoryProvider, ModuleMetadata } from '@nestjs/common';
|
||||
|
||||
import SMTPConnection from 'nodemailer/lib/smtp-connection';
|
||||
|
||||
export enum EmailDriver {
|
||||
Logger = 'logger',
|
||||
Smtp = 'smtp',
|
||||
}
|
||||
|
||||
export type EmailModuleOptions = SMTPConnection.Options | undefined;
|
||||
|
||||
export type EmailModuleAsyncOptions = {
|
||||
useFactory: (...args: any[]) => EmailModuleOptions;
|
||||
} & Pick<ModuleMetadata, 'imports'> &
|
||||
Pick<FactoryProvider, 'inject'>;
|
||||
@ -2,6 +2,8 @@
|
||||
import { Injectable, LogLevel } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
import { EmailDriver } from 'src/integrations/email/interfaces/email.interface';
|
||||
|
||||
import { LoggerDriverType } from 'src/integrations/logger/interfaces';
|
||||
import { ExceptionHandlerDriver } from 'src/integrations/exception-handler/interfaces';
|
||||
import { StorageDriverType } from 'src/integrations/file-storage/interfaces';
|
||||
@ -170,6 +172,28 @@ export class EnvironmentService {
|
||||
);
|
||||
}
|
||||
|
||||
getEmailDriver(): EmailDriver {
|
||||
return (
|
||||
this.configService.get<EmailDriver>('EMAIL_DRIVER') ?? EmailDriver.Logger
|
||||
);
|
||||
}
|
||||
|
||||
getEmailHost(): string | undefined {
|
||||
return this.configService.get<string>('EMAIL_SMTP_HOST');
|
||||
}
|
||||
|
||||
getEmailPort(): number | undefined {
|
||||
return this.configService.get<number>('EMAIL_SMTP_PORT');
|
||||
}
|
||||
|
||||
getEmailUser(): string | undefined {
|
||||
return this.configService.get<string>('EMAIL_SMTP_USER');
|
||||
}
|
||||
|
||||
getEmailPassword(): string | undefined {
|
||||
return this.configService.get<string>('EMAIL_SMTP_PASSWORD');
|
||||
}
|
||||
|
||||
getSupportDriver(): string {
|
||||
return (
|
||||
this.configService.get<string>('SUPPORT_DRIVER') ?? SupportDriver.None
|
||||
|
||||
@ -6,6 +6,8 @@ import { exceptionHandlerModuleFactory } from 'src/integrations/exception-handle
|
||||
import { fileStorageModuleFactory } from 'src/integrations/file-storage/file-storage.module-factory';
|
||||
import { loggerModuleFactory } from 'src/integrations/logger/logger.module-factory';
|
||||
import { messageQueueModuleFactory } from 'src/integrations/message-queue/message-queue.module-factory';
|
||||
import { emailModuleFactory } from 'src/integrations/email/email.module-factory';
|
||||
import { EmailModule } from 'src/integrations/email/email.module';
|
||||
|
||||
import { EnvironmentModule } from './environment/environment.module';
|
||||
import { EnvironmentService } from './environment/environment.service';
|
||||
@ -32,6 +34,10 @@ import { MessageQueueModule } from './message-queue/message-queue.module';
|
||||
useFactory: exceptionHandlerModuleFactory,
|
||||
inject: [EnvironmentService, HttpAdapterHost],
|
||||
}),
|
||||
EmailModule.forRoot({
|
||||
useFactory: emailModuleFactory,
|
||||
inject: [EnvironmentService],
|
||||
}),
|
||||
],
|
||||
exports: [],
|
||||
providers: [],
|
||||
|
||||
Reference in New Issue
Block a user