@haorama/nestjs-mailer
v0.2.0
Published
Nestjs mailer module
Downloads
5
Maintainers
Readme
Nestjs Mailer
Nestjs mailing service based on nodemailer
with additional feature like
- Multi mailer/ driver, you can used multiple driver like mailtrap, SES together
- use your own view adapter like handlebars, nunjucks etc
Installation
npm install --save @haorama/nestjs-mailer nodemailer
npm install --save-dev @types/nodemailer
#or
yarn add @haorama/nestjs-mailer nodemailer
yarn add -D @types/nodemailer
Usage
Import the MailerModule into your Root Module e.g AppModule
.
import { Module } from "@nestjs/common";
import { MailerModule } from "@haorama/nestjs-mailer";
@Module({
imports: [
MailerModule.forRoot({
mailers: {
mailtrap: {
host: process.env.MAIL_HOST,
port: +process.env.MAIL_PORT,
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASSWORD,
},
},
},
default_mailer: "mailtrap"
})
]
})
export class AppModule {}
and somewhere in your service or controller you can use MailerService
and send the email
import { MailerService } from "@haorama/nestjs-mailer";
@Injectable()
export class AuthService {
constructor(private mailerService: MailerService) {}
sendOtp() {
const otp = 123456;
await this.mailerService.send({
to: "[email protected]",
subject: "OTP",
text: `Your Otp is ${otp}`,
html: `<p>Your Otp is ${otp}</p>`,
data: {
otp
},
});
}
}
Async Configuration
you can also use forRootAsync
e.g if you prefer to put all configuration inside your config module file
@Module({
imports: [
MailerModule.forRootAsync({
useFactory: (configService: ConfigService) => {
return configService.get("mail");
},
imports: [ConfigModule],
inject: [ConfigService],
}),
]
})
export class AppModule {}
Amazon SES
you can pass a function and return the Transport
instance from nodemailer
// this import depend on your allowSyntheticDefaultImports on your tsconfig.json
import * as nodemailer from "nodemailer";
import * as aws from "@aws-sdk/client-ses";
const ses = new aws.SES({
region: process.env.AWS_REGION,
credentialDefaultProvider: defaultProvider,
});
@Module({
imports: [
MailerModule.forRoot({
mailers: {
ses: () => nodemailer.createTransport({ SES: { ses, aws } }),
mailtrap: {
host: process.env.MAIL_HOST,
port: +process.env.MAIL_PORT,
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASSWORD,
},
},
},
default_mailer: "ses",
}),
]
})
export class AppModule {}
Template / View Engine
We dont provide default template engine inside MailerModule
but you can create and choose your own template / view engine.
For example we can create a Nunjuck engine by passing template
inside module options.
First create a NunjuckAdapter class and extends our MailEngineAdapter
to it
import { resolve, join } from "path";
import nunjucks from "nunjucks";
import { MailEngineAdapter } from "@hikingness/nestjs-mailer";
export class NunjucksAdapter extends MailEngineAdapter {
root: string;
constructor() {
super();
this.root = resolve("./src/views/html");
}
render(path: string, data?: any) {
const env = new nunjucks.Environment();
const name = process.env.APP_NAME;
nunjucks.configure(this.root, { autoescape: true });
return nunjucks.render(join(this.root, path), {
appName: name,
...data,
});
}
}
the render
method can be anything as long as it return an html, then in the MailerModule
@Module({
imports: [
MailerModule.forRoot({
mailers: {
mailtrap: {
host: process.env.MAIL_HOST,
port: +process.env.MAIL_PORT,
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASSWORD,
},
},
},
default_mailer: "mailtrap",
template: {
engine: new NunjucksAdapter()
}
})
]
})
export class AppModule {}
After that you can use template
options inside send
method
await this.mailerService.send({
to: "[email protected]",
subject: "OTP",
// this path depend on your view configuration on the template / view adapter
template: "/emails/otp.html",
data: {
otp,
},
});
Queueing
By default we dont provide queueing inside MailerService
, but you can create your own mailing Module.
import { MailerModule } from "@hikingness/nestjs-mailer";
import { Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
// we used bull for queueing the email
import { BullModule } from "@nestjs/bull";
import { MailService } from "./mail.service";
import { MailConsumer } from "./mail.consumer";
@Module({
imports: [
MailerModule.forRootAsync({
mailers: {
anyMailerOfYours: "defined your config here",
}
}),
BullModule.registerQueue({
name: "mail",
}),
],
providers: [MailService, MailConsumer],
exports: [MailService],
})
export class MailModule {}
as you can see above we use BullModule
from @nestjs/bull
to make the mailing service queueable, we still need to define MailService
and MailConsumer
mail.service.ts
import { Injectable } from "@nestjs/common";
import { InjectQueue } from "@nestjs/bull";
import { Queue } from "bull";
import { SendMailOptions } from "@haorama/nestjs-mailer";
/**
* This mail service by default send an email in the background using Bull queue
*/
@Injectable()
export class MailService {
constructor(@InjectQueue("mail") private mailQueue: Queue) {}
send(options: SendMailOptions) {
return this.mailQueue.add("send", options);
}
}
mail.consumer.ts
import { MailerService, SendMailOptions } from "@haorama/nestjs-mailer";
import { OnQueueFailed, Process, Processor } from "@nestjs/bull";
import { Job } from "bull";
@Processor("mail")
export class MailConsumer {
constructor(private mailerService: MailerService) {}
@Process("send")
send(job: Job<SendMailOptions>) {
return this.mailerService.send(job.data);
}
@OnQueueFailed({ name: "send" })
onSendFailed(job: string, error: any) {
console.log("Job failed", job, error);
// or send failed report to Sentry etc
}
}
and you can replace the MailerService
with your own service (in this example is MailService
)
import { MailService } from "/your-mail-service-path";
@Injectable()
export class AuthService {
constructor(private mailService: MailService) {}
sendOtp() {
const otp = 123456;
await this.mailService.send({
to: "[email protected]",
subject: "OTP",
template: "/views/otp.html",
data: {
otp
},
});
}
}