All posts
Guide·Jul 4, 2026·6 min read

How to Send Email from JavaScript: SMTP, fetch, and the Email API Way

You can't send email from browser JavaScript directly. Here's how to use a send email API in JavaScript, nodemailer over SMTP, or a plain fetch call.

Dvir Atias

Dvir Atias

Founder

You cannot send email from browser JavaScript directly, because browsers have no SMTP client and any credentials you shipped to the page would be public. To send email with JavaScript you either run SMTP from a Node.js backend (nodemailer) or, more commonly in 2026, call a send email API from JavaScript over HTTP - which works the same in Node, edge functions, and serverless. This guide shows all three, with working code and a comparison table.

Can JavaScript send email directly?

Not from the browser. There are two hard reasons:

  1. No SMTP in the browser. Sending email means speaking SMTP to a mail server on port 25, 465, or 587. The browser sandbox only lets JavaScript make HTTP(S), WebSocket, and a few other requests. There is no raw socket, so there is no way to talk to an SMTP server from client-side code.
  2. Credentials would leak. Even if you could open a socket, you would need to embed your SMTP username and password (or an API key) in code that ships to every visitor. Anyone could open dev tools and read it, then send mail as you.

So this kind of thing does not work and should never be attempted:

// Anti-pattern: there is no SMTP client in the browser, and this
// would expose your credentials to every visitor who views source.
import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({
  host: "smtp.example.com",
  auth: { user: "me@example.com", pass: "hunter2" }, // now public
});

The fix is always the same: the browser sends a normal HTTP request to code you control (a backend route, an edge function, or a serverless handler), and that code does the actual sending with a secret that never leaves the server.

The three ways to send email from JavaScript

Once you accept that sending happens server-side, you have three practical options:

  1. Node.js + nodemailer over SMTP - classic, self-managed, you bring your own SMTP server or provider credentials.
  2. An HTTP email API with plain fetch - one POST request, runs anywhere JavaScript runs, no SMTP knowledge required.
  3. An official SDK - a thin wrapper over that same HTTP API with types and helpers.

Let's walk through each.

How do you send email with Node.js and nodemailer?

nodemailer is the long-standing Node.js library for sending mail over SMTP. Install it, create a transport with your SMTP credentials, then call sendMail.

import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({
  host: "smtp.your-provider.com",
  port: 587,          // 465 for implicit TLS, 587 for STARTTLS
  secure: false,      // true for port 465, false for 587
  auth: {
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS,
  },
});

await transporter.sendMail({
  from: "notifier@yourdomain.com",
  to: "customer@example.com",
  subject: "Your order shipped",
  text: "Tracking number: 1Z999AA10123456784",
  html: "<p>Tracking number: <b>1Z999AA10123456784</b></p>",
});

This works, but note what it does not do: nodemailer is only the SMTP client. It does not host a mail server, warm up sending IPs, sign messages with DKIM, or handle bounces and complaints for you. You still need an SMTP provider behind it, and deliverability is your problem. nodemailer also depends on Node's net/tls sockets, so it does not run in the browser or in most edge runtimes.

How do you send email with fetch?

If you would rather not manage SMTP at all, call an HTTP email API. Because it is just an HTTP request, the exact same code runs in Node.js, in a Cloudflare Worker or Vercel edge function, and in any serverless handler. Here it is with AgenticEmail, using nothing but the built-in fetch.

First, create an inbox to send from (you do this once, then reuse the inbox id):

const inboxRes = await fetch("https://api.agenticemail.dev/v1/inboxes", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AGENTICEMAIL_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ username: "notifier" }),
});

const inbox = await inboxRes.json();
// inbox.address -> notifier@inbox.agenticemail.dev

Then send a message from that inbox:

const sendRes = await fetch(
  `https://api.agenticemail.dev/v1/inboxes/${inbox.id}/messages/send`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.AGENTICEMAIL_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      to: "customer@example.com",
      subject: "Your order shipped",
      text: "Tracking number: 1Z999AA10123456784",
      // html, cc, bcc, and attachments are all supported
      client_id: "order-4821-shipped", // optional idempotency key
    }),
  },
);

const message = await sendRes.json();
console.log(message.id);

No SMTP ports, no TLS config, no MIME encoding. The client_id field is an optional idempotency key: if your function retries, passing the same value stops a duplicate email from going out. The provider handles DKIM signing, IP reputation, and delivery.

How do you send email with an SDK?

The SDK is the same HTTP API with types and less boilerplate. Install it and you get autocomplete for every field.

npm install agenticemail
import { AgenticEmail } from "agenticemail";

const client = new AgenticEmail({ apiKey: process.env.AGENTICEMAIL_API_KEY });

const inbox = await client.inboxes.create({ username: "notifier" });

const message = await client.messages.send({
  inboxId: inbox.id,
  to: "customer@example.com",
  subject: "Your order shipped",
  text: "Tracking number: 1Z999AA10123456784",
});

console.log(message.id);

Because sending is asynchronous, you often want to know what happened after the fact. Register a webhook and the API will POST delivery events back to your app:

await fetch("https://api.agenticemail.dev/v1/webhooks", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AGENTICEMAIL_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://your-app.com/hooks/email",
    event_types: ["message.delivered", "message.bounced"],
  }),
});

Comparison: which approach should you use?

ApproachWhere it runsDeliverabilityEffort
Browser JavaScriptNowhere - blocked by designN/AImpossible
nodemailer over SMTPNode.js onlyYou manage IPs, DKIM, bouncesHigh
HTTP API with fetchNode, edge, serverless, anywhereHandled by the providerLow
Official SDKNode, edge, serverlessHandled by the providerLowest

For a script running on a server you already control with a mail provider you trust, nodemailer is fine. For anything that needs to run on the edge, in a serverless function, or across an agent that creates addresses on the fly, the HTTP API or SDK is the shorter path. See the full quickstart in the docs and the free-tier limits on the pricing page to size it for your project.

Frequently asked questions

Can I send email from the browser with JavaScript?

No. The browser has no SMTP client and cannot open the raw sockets email requires, and embedding credentials in client-side code would expose them to everyone. Have the browser call your own backend, edge function, or serverless endpoint, and send from there with a secret that stays on the server.

Is there a free email API for JavaScript?

Yes. AgenticEmail has a free tier you can start on without a card - see pricing. You get an API key, create an inbox, and send with fetch or the agenticemail SDK. Most transactional email APIs offer a free monthly allowance for low volume.

Do I need a backend to send email?

You need server-side code, but not necessarily a traditional always-on backend. An edge function or a serverless handler counts, and both can call an HTTP email API with plain fetch. The only rule is that the sending credential never ships to the browser.

Should I use SMTP or an HTTP email API?

Use SMTP with nodemailer if you already run a mail server or need SMTP for legacy reasons. Use an HTTP email API if you want it to run on edge and serverless runtimes, skip MIME and TLS plumbing, and let the provider own deliverability. For a deeper comparison see our guides on the best email API and transactional email API.

How do I send email from a Gmail address in JavaScript?

That requires the Gmail API with OAuth, which is heavier than a general email API. We cover it in Gmail API: send email. For most app and agent use cases, a dedicated email API is simpler and gives you an address you provision by code.

How do agents send email with JavaScript?

The same way: an agent calls the HTTP API or SDK to create an inbox and send from it, and can receive replies over webhooks or WebSockets. Creating an addressable inbox per agent at runtime is the pattern we describe in giving your agent an inbox.

Talk to a real person