nodemailer-mock
nodemailer-mock replaces Nodemailer in tests so you can inspect message options and exercise send failures without delivering email. It exposes familiar createTransport() and sendMail() methods, plus a mock helper object for sent messages, queued outcomes, and resets. Use the shared default export for a small suite or create independent factories when tests need separate state. The package supports callbacks and Promises, with CommonJS and ESM entry points. Its results describe mocked sends, which makes it useful for testing notification code while keeping delivery checks in a separate integration test.
How a mocked send reaches an assertion
Create the mock
Use the default module or getMockFor(nodemailer) for independent state. Pass the actual Nodemailer module when your runner replaces that dependency.
Replace the application dependency
Register the replacement before importing application code that loads Nodemailer. Use the mechanism supported by your test runner and module format.
Send and record
Application code creates a transport and calls sendMail(). Successful sends enter the mock history; configured failures reject Promises or reach callbacks.
Assert and reset
Read mock.getSentMail() to check recipient and content options. Reset state between tests so earlier messages and failure settings do not affect later assertions.
Install alongside Nodemailer
Nodemailer is a peer dependency. Keep the version your application already uses and add nodemailer-mock as a development dependency. A new test project can install both with the command below. Supported Nodemailer majors are 6 through 10; use a Node.js version supported by the Nodemailer release you install.
npm install --save-dev nodemailer nodemailer-mockAssert a message and a queued failure
A factory keeps this example independent of the shared default mock. The first assertion checks recorded content; the second checks the Promise rejection from a queued outcome.
import assert from 'node:assert/strict';
import nodemailer from 'nodemailer';
import { getMockFor } from 'nodemailer-mock';
const mailer = getMockFor(nodemailer);
const transport = mailer.createTransport();
await transport.sendMail({
to: '[email protected]', subject: 'Weekly report', text: 'Total: 42',
});
assert.equal(mailer.mock.getSentMail()[0].subject, 'Weekly report');
mailer.mock.queueResult({ error: new Error('Temporary failure') });
await assert.rejects(transport.sendMail({ text: 'Retry me' }), /Temporary failure/);
mailer.mock.reset();Choose assertions that match the mock
The example exercises an independent mock directly. To test your application, arrange dependency replacement first, then call the application function. A CommonJS loader hook does not replace native ESM imports. Nodemailer 10 also resolves its ESM and CommonJS entry points separately. Follow the repository example for your runner. Sent-mail history contains successful message options with applied defaults and plugin changes. User plugins registered with use() require setUnmockedUsePlugins(true) to execute; reset() disables that setting again.
Keep simulation results in context
Legacy info fields contain placeholders. Opt into responseMode: realistic when assertions need an envelope derived from the message, and supply messageIdGenerator for deterministic IDs. Neither mode proves recipient delivery. verify() and close() are mocked by default. Delegating verify() to a real underlying transport can contact its server. Ordinary reset preserves created transporters; reset({ clearTransporters: true }) also clears their registry and listeners without closing real transports.
Keep building
Find more DoubleSharp packages for application development, testing, and operations.