A mailer module for NestJS using Nodemailer
Every capability is optional: pick what you need.
- Write emails your way:
sendMail()with inline options, typed mail classes (send(WelcomeMail, { to, data })), or the official@nestjs/mailMailerover our bridges. - Any transport: SMTP and every nodemailer transport, or zero-dependency HTTP transports for Resend, Postmark, SendGrid, SES, Mailgun and Brevo.
- Send when it suits you: directly, in the background with BullMQ (with scheduling), or after your transaction commits through the official
@nestjs/outbox. - Template engines: Handlebars, Pug, EJS, Liquid, Nunjucks or MJML, with CSS inlining and i18n; or the escaping
htmltag. Plain-text parts are derived from the HTML. - Reliable delivery: retries with backoff for transient failures, never at the risk of a duplicate; failover between transporters,
AbortSignal, idempotency keys, graceful shutdown. - Typed errors and validation:
MailerSmtpError,MailerTimeoutError,MailerProviderError… with apermanentflag; malformed addresses and header injections rejected before sending. - Delivery rules: redirect recipients in staging, suppression lists, one-click unsubscribe (RFC 8058).
- Testing and development:
TestMailboxassertions,FileTransport/LogTransport, browser previews at/_mailer. - Operations: events (RxJS,
@nestjs/event-emitter,diagnostics_channel), batch sending, health checks.
Full documentation is available at nest-modules.github.io/mailer: Getting started · Mail classes · Reliability · Delivery rules · HTTP transports · Transactional outbox · Errors · Testing · Interop with @nestjs/mail · Comparison · Migrating to v4
Older versions: v3 docs · v2 docs · Versions & upgrading
pnpm add @nestjs-modules/mailer nodemailerInstall a template engine of your choice (they are optional peer dependencies and are not installed automatically):
pnpm add handlebars
# or: pug, ejs, liquidjs, nunjucks, mjml@nestjs-modules/mailer |
NestJS | nodemailer | Node.js |
|---|---|---|---|
| 4.x | 11 – 12 | >= 8 | NestJS 12 requires Node.js >= 20.19 (or >= 22.12) |
| 2.x / 3.x | 7 – 12 |
NestJS 12 is published as ES modules. This package is CommonJS and loads it through Node.js' native require(esm) support, so no extra configuration is needed in your application. If you run Jest on a NestJS 12 project, use Node.js >= 24.9 with NODE_OPTIONS=--experimental-vm-modules.
Upgrading from v3? Retries, typed errors, validation and plain-text parts are now on by default; each can be turned off with one option (retry: false, wrapErrors: false, validate: false, textFromHtml: false). See the migration guide.
// app.module.ts
import { Module } from '@nestjs/common';
import { MailerModule } from '@nestjs-modules/mailer';
import { HandlebarsAdapter } from '@nestjs-modules/mailer/adapters/handlebars.adapter';
import { join } from 'node:path';
@Module({
imports: [
MailerModule.forRoot({
transport: {
host: 'smtp.example.com',
port: 587,
auth: { user: 'username', pass: 'password' },
},
defaults: { from: '"No Reply" <noreply@example.com>' },
template: {
dir: join(__dirname, 'templates'),
adapter: new HandlebarsAdapter(),
},
}),
],
})
export class AppModule {}// welcome.mail.ts
import { Injectable } from '@nestjs/common';
import { Mailable } from '@nestjs-modules/mailer';
@Injectable()
export class WelcomeMail implements Mailable<{ name: string }> {
render({ name }: { name: string }) {
return { subject: `Welcome, ${name}!`, template: 'welcome', context: { name } };
}
}// users.service.ts
import { Injectable } from '@nestjs/common';
import { MailerService } from '@nestjs-modules/mailer';
import { WelcomeMail } from './welcome.mail';
@Injectable()
export class UsersService {
constructor(private readonly mailerService: MailerService) {}
async welcome(email: string, name: string) {
await this.mailerService.send(WelcomeMail, { to: email, data: { name } });
// Or without a mail class
await this.mailerService.sendMail({
to: email,
subject: 'Hello',
template: 'welcome',
context: { name },
});
}
}Prefer an HTTP API over SMTP? Swap the transport, nothing else changes:
import { ResendTransport } from '@nestjs-modules/mailer';
MailerModule.forRoot({
transport: new ResendTransport({ apiKey: process.env.RESEND_API_KEY! }),
defaults: { from: 'App <app@example.com>' },
});Use the official @nestjs/mail API with any nodemailer transport, this module's templates, or MailerService delivery (failover, interception, suppression):
import { Module } from '@nestjs/common';
import { MailModule } from '@nestjs/mail';
import { HandlebarsAdapter } from '@nestjs-modules/mailer/adapters/handlebars.adapter';
import { NodemailerMailTransport, TemplateAdapterEngine } from '@nestjs-modules/mailer/nestjs-mail';
import { join } from 'node:path';
@Module({
imports: [
MailModule.forRoot({
transport: new NodemailerMailTransport({ host: 'smtp.example.com', port: 587 }),
templates: new TemplateAdapterEngine({
adapter: new HandlebarsAdapter(),
dir: join(__dirname, 'templates'),
}),
from: 'App <app@example.com>',
}),
],
})
export class AppModule {}See Interop with @nestjs/mail for MailerServiceTransport and an honest comparison of both packages.
Contributions are welcome! See the documentation for details on the monorepo structure and development commands.
- Cristiam Diaz
- Eduardo Leal
- Juan Echeverry
- Pat McGowan
- Paweł Partyka
- Wasutan Kitijerapat
- Alexandre Titeux
MIT