Node.js email API: send and receive (free)
Send and receive email in Node.js with a free HTTP API — no Nodemailer, no SMTP. The send call with fetch, how to receive replies, and why it beats SMTP.
Sending email from Node usually means Nodemailer plus an SMTP transport you have to configure and babysit — and it can only send. A free HTTP email API is one fetch call, and it can read the reply too.
Send with fetch
const API = "https://login.ollastack.com";
const TOKEN = process.env.OLLASTACK_API_TOKEN;
const h = { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" };
// create a mailbox once
const mbx = await fetch(`${API}/api/mailboxes`, {
method: "POST", headers: h,
body: JSON.stringify({ name: "node", mode: "agent", handle: "node" }),
}).then((r) => r.json());
// send
await fetch(`${API}/api/mailboxes/${mbx.id}/send`, {
method: "POST", headers: h,
body: JSON.stringify({ to: "user@example.com", subject: "Hi", text: "Sent from Node." }),
});
No transport config, no port 587 — native fetch (Node 18+).
Receive a reply
const msg = await fetch(
`${API}/api/mailboxes/${mbx.id}/wait?timeout=60`,
{ headers: { Authorization: `Bearer ${TOKEN}` } },
).then((r) => r.json());
console.log(msg.subject, msg.codes); // OTP already extracted
That’s the part Nodemailer can’t do — read inbound mail and pull the code without scraping.
Why an API beats SMTP from Node
Nodemailer owns the transport: host, port, auth, pooling, and every connection error. The API is one fetch that returns a msg_… id or a structured error — and it also receives. Less to configure, more it can do.
Poll an inbox in a loop
Because wait long-polls and returns as soon as a message lands, you can drain an inbox in a simple loop — each call blocks until the next message or the timeout, so there’s no manual back-off:
async function drain(mbxId, onMessage) {
while (true) {
const res = await fetch(
`${API}/api/mailboxes/${mbxId}/wait?timeout=60`,
{ headers: { Authorization: `Bearer ${TOKEN}` } },
);
if (res.status === 204) continue; // nothing within the window — poll again
if (!res.ok) throw new Error(`wait failed: ${res.status}`);
onMessage(await res.json()); // { from, subject, codes, links }
}
}
For production, give the mailbox a webhook_url instead and let inbound mail POST to your endpoint (HMAC-signed, retried) — push beats polling once you’re past a quick script.
Error handling
Check res.ok and read the structured error body on failure rather than assuming the send went through — the API returns a code and message you can log and act on, unlike a thrown SMTP socket error.
See the email API overview, free API to send email, and the Python version.
Get a free token — send and receive from Node, no card.
Frequently asked questions
How do I send email in Node.js without SMTP?
Use fetch to POST to the send endpoint with a Bearer token and a JSON body (to, subject, text/html). No Nodemailer, no SMTP host or credentials — one HTTPS call that returns a message id.
Can Node.js receive email too?
Yes. fetch the wait endpoint with the same token to long-poll for the next inbound message, then read msg.codes or msg.text. SMTP-based libraries can only send; an inbox API receives as well.
Why use an API instead of Nodemailer?
Nodemailer needs an SMTP transport — host, port, auth — and only sends. An HTTP API is one fetch call, returns structured errors, and can also receive mail.
Is it free?
The free tier sends and receives with no credit card.
Last updated June 21, 2026. Spotted something out of date? Email hello@ollastack.com.