Skip to content

Mailer v4 ​

2026-10-23 · Juan David

@nestjs-modules/mailer v4 is out. It is the biggest release since the module started: typed mail classes, zero-dependency HTTP transports, delivery that survives flaky servers without sending duplicates, a transactional outbox, rules for staging and suppression lists, a real test mailbox, a browser preview, and first-class interop with the official @nestjs/mail. The sendMail() API you know is unchanged.

One principle guided the release: every capability is optional, and you choose how to use the library. Write emails with sendMail(), mail classes or the official Mailer; deliver them through nodemailer, our HTTP transports or @nestjs/mail's; send them directly, through BullMQ or through @nestjs/outbox. → Choose your setup

bash
pnpm add @nestjs-modules/mailer@^4 nodemailer

Mail classes ​

Write an email once, as a typed provider, and send it from anywhere:

typescript
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 } };
  }
}

await mailerService.send(WelcomeMail, { to: 'ada@example.com', data: { name: 'Ada' } });

mailerService.render() gives you the finished email without sending it. The class shape matches @nestjs/mail's, so the same class works with both. → Mail classes

HTTP transports ​

ResendTransport, PostmarkTransport, SendGridTransport, SesTransport (raw MIME, SigV4, no AWS SDK), MailgunTransport and BrevoTransport use Node's fetch and add no dependencies. → HTTP transports

Reliable delivery ​

Transient failures are now retried by default (3 attempts, exponential backoff with jitter), and only transient ones: a rejected recipient fails at once. A timeout or a connection dropped mid-message may already have been delivered, so it is retried only when the email has a stable Message-ID: no duplicates. Add failover: ['backup'] to switch transporters when one is down, an AbortSignal to give up, and an idempotencyKey to give a redelivered email the same Message-ID. Shutdown waits for sends in flight. → Reliability

Typed errors, validation, safe HTML ​

Failures are thrown as typed errors (MailerSmtpError, MailerTimeoutError, MailerProviderError…) with a permanent flag. Malformed addresses and header injections are rejected before sending. The html tag escapes interpolated values, and emails without a text part get one derived from the HTML. → Errors and validation · Sending emails

Transactional outbox ​

MailerOutboxModule records emails in your database transaction through the official @nestjs/outbox and sends them after the commit, with the outbox message id as idempotency key and permanent failures dead-lettered. → Transactional outbox

Delivery rules ​

intercept redirects every non-allowed recipient to a QA inbox in staging. suppress drops bounced, complained or unsubscribed addresses before they hurt your reputation. unsubscribe adds the one-click List-Unsubscribe headers Gmail and Yahoo require from bulk senders. → Delivery rules

Testing and local development ​

MailerTestModule now accepts your real options and provides a TestMailbox:

typescript
const mail = mailbox.assertSent({ to: 'ada@example.com', mail: WelcomeMail });
const token = mail.link('/verify').searchParams.get('token');

FileTransport writes .eml files, LogTransport logs a summary, and MailerPreviewModule serves your emails at /_mailer. → Testing · Dev transports · Email previews

Events, queue and i18n ​

Events gain RETRY, FAILOVER and SUPPRESSED, richer payloads, an RxJS events$ stream and diagnostics_channel publishing, and @nestjs/event-emitter listeners now actually fire. The BullMQ queue fails permanent errors at once, deduplicates redeliveries and can schedule() emails. i18n falls back from es-CO to es. → Events · Queue · i18n

Working with @nestjs/mail ​

The NestJS team recently announced @nestjs/mail, a dependency-free official mail package. We think that is great news, and v4 is designed to work with it rather than against it. The new @nestjs-modules/mailer/nestjs-mail entry point provides:

  • NodemailerMailTransport: any nodemailer transport for @nestjs/mail;
  • MailerServiceTransport: @nestjs/mail delivering through MailerModule, with failover, interception and suppression;
  • TemplateAdapterEngine: Handlebars, Pug, EJS, MJML, Liquid and Nunjucks templates for @nestjs/mail.

→ Interop with @nestjs/mail · Honest comparison

Upgrading ​

Most apps upgrade without code changes. The defaults to know: retries are on (retry: false keeps the v3 behavior), errors are typed (wrapErrors: false), messages are validated (validate: false) and HTML emails get a text part (textFromHtml: false). Event payloads have extra fields, MailerTestModule delivers to a TestMailbox, and timeouts are retried only with a stable Message-ID. → Migration guide

Thanks to everyone who reported issues and sent pull requests. Feedback is welcome on GitHub.

Released under the MIT License.