Node.js guide
How to send email with Node.js
Send password resets, receipts and notifications from your Node.js or TypeScript app with one function call. Free for 3,000 emails a month.
Quickstart
Send your first email in three steps.
You need a domain you control and Node.js 20 or later. Setup takes a few minutes, most of it waiting for DNS.
Step 1: Verify your sending domain
Add your domain in the Sendaro dashboard and publish the three DNS records it shows you: DKIM, SPF and DMARC. These prove to Gmail, Outlook and other providers that you are allowed to send as that domain, which keeps your email out of spam. Sendaro checks the records and marks the domain verified.
Step 2: Install the SDK and add your API key
Create an API key with send access, then install the official Node.js and TypeScript SDK. Put the key in your environment, never in client code.
Terminalnpm install sendaro.envSENDARO_API_KEY=rf_your_api_keyStep 3: Send the email
Call
send()with a verifiedfromaddress. Include atextversion next to your HTML: some people read plain-text email, and spam filters like seeing both.send.tsimport { Sendaro } from "sendaro"; const sendaro = new Sendaro(); // reads SENDARO_API_KEY const { id } = await sendaro.send({ from: "Acme <hello@yourdomain.com>", to: "maya@example.com", subject: "Reset your password", html: "<p>Use this link to choose a new password.</p>", text: "Use this link to choose a new password.", }); console.log("Queued email", id);
Without the SDK
Send email from Node.js with fetch.
Prefer no dependencies? The SDK is a thin wrapper over one REST call. Any HTTP client works, and so does any other language.
// Node.js 18+ has fetch built in. No package needed.
const response = await fetch("https://sendaro.email/api/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SENDARO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: "Acme <hello@yourdomain.com>",
to: "maya@example.com",
subject: "Your receipt",
html: "<p>Thanks for your order.</p>",
}),
});
if (!response.ok) throw new Error(`Send failed: ${response.status}`);
const { id } = await response.json(); // 202 AcceptedProduction
Retries, errors and delivery status.
Networks fail and jobs run twice. These are the three things to get right before you ship.
Retry without sending twice
Pass an idempotencyKey built from something stable, like a user ID and a token. If your job retries with the same key and body within 24 hours, Sendaro returns the original email instead of sending a duplicate. A non-2xx response throws a SendaroError.
import { Sendaro, SendaroError } from "sendaro";
const sendaro = new Sendaro();
try {
await sendaro.send(
{
from: "Acme <hello@yourdomain.com>",
to: user.email,
subject: "Confirm your email",
html: `<p><a href="${confirmUrl}">Confirm your email</a></p>`,
},
// Same key, same body within 24 hours: you get the first email back, not a second send.
{ idempotencyKey: `confirm-${user.id}-${token}` },
);
} catch (error) {
if (error instanceof SendaroError) {
// error.status is the HTTP status, error.code is the API error string.
console.error(error.status, error.code);
}
throw error;
}Check what happened
Accepted is not delivered. Every email has a status that moves from queued to sent, and only becomes delivered when the recipient's mail server confirms it. Bounces and complaints go on your suppression list automatically, so you never keep mailing an address that can't receive.
const email = await sendaro.get(id);
console.log(email.status); // "queued" | "sent" | "delivered" | "bounced" | ...Over 60 requests a minute per key you get a 429 with a Retry-After header. Wait, then retry with the same idempotency key. See rate limits.
API or SMTP
Why use an email API instead of Nodemailer and SMTP?
Nodemailer is a good library, but it still needs an SMTP server, credentials and a port your host doesn't block (many cloud hosts block SMTP ports). Once a message leaves, you have no record of whether it arrived.
With an email API you send one HTTPS request. You get an ID back for every message, a status you can query, signed webhooks for each event, and a dashboard that shows your bounce and complaint rates. That is what tells you a password reset never reached a customer before they tell you.
FAQ
Node.js email questions.
202 means the email was accepted and queued, not delivered. Read its status with sendaro.get(id), or set up a signed webhook to get email.delivered and email.bounced events as they happen.Send your first email today.
Free includes 3,000 emails every month. No card needed.