Email Fast Get a sandbox key
Guides

Send email with Express

A POST route, one shared client, and the error handling Express 4 won't do for you.

Facts verified 2026-07-17 — corrections: hello@emailfast.dev

In Express, email lives in a route handler: parse the body, call ef.send, return the id. Create one EmailFast client at module scope and share it across requests — it is stateless and cheap. The only Express-specific work is error propagation, because Express 4 does nothing with a rejected async handler.

npm install @email-fast/nodejs
// server.mjs
import express from "express";
import { EmailFast } from "@email-fast/nodejs";

const app = express();
app.use(express.json());

const ef = new EmailFast({ apiKey: process.env.EMAILFAST_API_KEY, baseUrl: "https://api.emailfast.dev" }); // ef_sandbox_… while testing

app.post("/signup", async (req, res, next) => {
  const { email, name } = req.body;
  try {
    const { id } = await ef.send({
      to: email,
      subject: "Confirm your account",
      html: "<p>Hi {{name}}, confirm your address here.</p>",
      data: { name },
      idempotency_key: `confirm-${email}`, // a double-POST can't double-send
    });
    res.status(202).json({ id });
  } catch (err) {
    next(err); // Express 4 won't catch async throws for you
  }
});

app.use((err, req, res, next) => {
  console.error(err);
  res.status(502).json({ error: "email send failed" });
});

app.listen(3000);

a 202 from the API means the send is committed to a durable, partitioned outbox before we answer — a crash can't lose it, and a retry with the same idempotency key can't double-send.

Gotchas

Next

See it for yourself

Sandbox keys run the real pipeline dry — real validation, real events, a hosted inbox, no email sent. Early access is onboarding now.