Nodemailer or an email API in Node.js
Updated
Nodemailer is the most popular way to send email from Node.js, and it is good. But it is a message builder and SMTP client, not a delivery service, and that distinction explains most of the problems people have with it.
Nodemailer
npm install nodemailer
import nodemailer from "nodemailer";
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: 587,
secure: false, // STARTTLS on 587; use true with port 465
auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASSWORD },
});
const info = await transporter.sendMail({
from: '"Acme" <hello@yourdomain.com>',
to: "ada@example.com",
subject: "Welcome",
text: "Hi Ada, your account is ready.",
html: "<p>Hi Ada, your account is ready.</p>",
});
console.log(info.messageId);
It handles MIME, attachments, CC and BCC, and streaming well. You still need an SMTP server to send to, and everything about deliverability sits on that server and your domain.
An email API
npm install @inboxili/node
import { Inboxili, InboxiliError } from "@inboxili/node";
const inboxili = new Inboxili({ apiKey: process.env.INBOXILI_API_KEY });
try {
const { messageId } = await inboxili.emails.send({
to: "ada@example.com",
fromEmail: "hello@yourdomain.com", // a sender on a verified domain
subject: "Welcome, {{first_name}}",
htmlBody: "<p>Hi {{first_name}}, your account is ready.</p>",
textBody: "Hi Ada, your account is ready.",
templateData: { first_name: "Ada" },
});
console.log(messageId);
} catch (err) {
if (err instanceof InboxiliError) console.error(err.status, err.code, err.message);
else throw err;
}
Comparison
| | Nodemailer + SMTP | Email API | |---|---|---| | What it is | Library plus an SMTP server | A service with a client | | Attachments, CC, BCC | Yes | Not in the Inboxili API | | Network | Needs SMTP ports | HTTPS only | | Errors | SMTP codes and exceptions | HTTP status and codes | | Delivery tracking | None by itself | Logs and webhooks | | Templates | Bring your own | Optional server-side templates | | Credentials | SMTP username and password | Scoped, revocable API keys | | Serverless friendliness | Connection setup per invocation | One request |
Which to pick
- You need attachments or CC: Nodemailer with an SMTP provider that allows them.
- Verification, reset and receipt emails in an app: the API. You get error codes and delivery events without running anything.
- Serverless functions: the API. An SMTP handshake on every cold invocation is slow, and some platforms block SMTP ports.
- Local development: either. With Nodemailer, use a catch-all test inbox. With the API, use a fake client.
Testing without sending
Inject the sender so tests never touch the network:
export function makeNotifier(sendEmail) {
return {
async welcome(user) {
await sendEmail({ to: user.email, subject: "Welcome", htmlBody: `<p>Hi ${user.firstName}</p>` });
},
};
}
// production
// const notifier = makeNotifier((m) => inboxili.emails.send({ fromEmail: "hello@yourdomain.com", ...m }));
// test
// const sent = []; const notifier = makeNotifier(async (m) => sent.push(m));
The same shape works for Nodemailer's sendMail.
Frequently asked questions
- Is Nodemailer an email service?
- No. Nodemailer is a library that builds messages and sends them through an SMTP server (or another transport) that you provide. It does not deliver mail itself.
- Can Nodemailer use the Inboxili API?
- Not as a built-in transport. Inboxili has no SMTP endpoint, so use the @inboxili/node package instead.
Send from Node.js with Inboxili
Create a workspace, verify a domain, and make your first API call.