Email Fast Get a sandbox key
Guides

Send email with Fastify

Schema-validated body in, message id out — the Fastify way.

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

Fastify's schema validation is the right front door for email: declare the body shape once and malformed requests never reach your send call. Handlers are async by default — return the JSON, throw on failure — so the send is three honest lines with @email-fast/nodejs.

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

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

app.post(
  "/invite",
  {
    schema: {
      body: {
        type: "object",
        required: ["email", "team"],
        properties: {
          email: { type: "string" },
          team: { type: "string" },
        },
      },
    },
  },
  async (req, reply) => {
    const { email, team } = req.body;
    const { id } = await ef.send({
      to: email,
      subject: "You're invited",
      html: "<p>Join {{team}} here.</p>",
      data: { team },
      idempotency_key: `invite-${team}-${email}`, // a retried request can't double-invite
    });
    reply.code(202);
    return { id };
  },
);

app.setErrorHandler((err, req, reply) => {
  req.log.error(err);
  reply.code(err.validation ? 400 : 502).send({ error: err.message });
});

await app.listen({ port: 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.