Express · TypeScript

Block disposable email in Express

Express middleware calls Piisend on POST /signup (or your auth route) before passport or custom user creation runs.

The code

// middleware/disposableEmail.ts
import type { Request, Response, NextFunction } from "express";

const PIISEND_URL = "https://api.piisend.com/api/v1/intelligence/email";

export async function blockDisposableEmail(req: Request, res: Response, next: NextFunction) {
  const email = req.body?.email;
  if (!email) return next();

  try {
    const r = await fetch(PIISEND_URL, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.PIISEND_API_KEY!}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ email }),
    });
    if (r.ok && (await r.json()).signals?.disposable) {
      return res.status(400).json({ error: "Please use a permanent email address." });
    }
  } catch {
    // fail open
  }
  next();
}

// app.ts
import express from "express";
import { blockDisposableEmail } from "./middleware/disposableEmail";

const app = express();
app.use(express.json());
app.post("/signup", blockDisposableEmail, signupHandler);

API key

Use `dotenv` in development; inject `PIISEND_API_KEY` via your host's secret store in production.

Fail-open vs fail-closed

Middleware calls `next()` on errors — swap for 503 if you need fail-closed.

Pair with verification

Place middleware before passport-local or your ORM user-create handler.

Send verification email with Piisend

After blocking disposable addresses, send OTP and verification mail through the same Piisend account. One API key for intelligence checks and transactional sends.