This middleware intercepts a signup request, verifies the email, and only calls next() if the address passes your bar for acceptable risk.

Requirements

npm install node-fetch

(Skip the install if you’re on Node 18+, which has fetch built in.)

The middleware

// middleware/verifyEmail.js
const API_KEY = process.env.ROCKETVERIFIER_API_KEY; // rv_live_... or rv_test_...
const BASE_URL = 'https://api.rocketverifier.com';

async function verifyEmail(req, res, next) {
  const { email } = req.body;
  if (!email) {
    return res.status(400).json({ error: 'Email is required' });
  }

  try {
    const response = await fetch(`${BASE_URL}/v1/verify`, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ email }),
    });

    if (!response.ok) {
      // Fail open on a RocketVerifier outage rather than blocking all signups.
      console.error('RocketVerifier request failed:', response.status);
      return next();
    }

    const { data } = await response.json();
    req.emailVerification = data;

    if (data.status === 'undeliverable') {
      return res.status(422).json({ error: 'This email address does not appear to be deliverable.' });
    }

    if (data.domain.disposable) {
      return res.status(422).json({ error: 'Disposable email addresses are not allowed for signup.' });
    }

    // Risky/unknown (often catch-all domains) pass through with a flag for later review.
    next();
  } catch (err) {
    console.error('Email verification error:', err);
    next(); // Fail open rather than blocking signups on a network error.
  }
}

module.exports = verifyEmail;

Wiring it into a signup route

const express = require('express');
const verifyEmail = require('./middleware/verifyEmail');
const router = express.Router();

router.post('/signup', verifyEmail, async (req, res) => {
  // req.emailVerification is available here if you want to store the
  // verification score/status alongside the new user record.
  const user = await createUser(req.body, req.emailVerification);
  res.status(201).json({ user });
});

module.exports = router;

Testing against the sandbox

export ROCKETVERIFIER_API_KEY=rv_test_your_sandbox_key
curl -X POST http://localhost:3000/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "test@sandbox.rocketverifier.com"}'

Sandbox addresses exercise the full response shape without spending real credits, so you can confirm your route handles deliverable, undeliverable, and risky statuses correctly before going live.

Why “fail open” on errors

The middleware intentionally calls next() (allowing signup to proceed) if the RocketVerifier request itself fails or times out, rather than blocking every signup during a verification-service outage. This is a deliberate tradeoff — letting a few bad addresses through during rare outages is usually preferable to blocking all new signups.