Express email verification

Verify emails in Express with Verifly

Add a live email verification step to any Express app with a route or middleware that proxies Verifly. It is an API-first, pay-as-you-go service — call it server-side with fetch, keep your key out of the browser, and reject disposable or dead mailboxes before you create the account.

Verification middleware in ExpressAPI
import express from 'express'

const app = express()
app.use(express.json())
const KEY = process.env.VERIFLY_KEY // server-side only, never in the browser

async function verifyEmail(req, res, next) {
  const { email } = req.body
  const url = `https://verifly.email/api/v1/verify?email=${encodeURIComponent(email)}`
  const r = await fetch(url, { headers: { Authorization: `Bearer ${KEY}` } })
  const data = await r.json()
  if (data.result === 'undeliverable' || data.disposable) {
    return res.status(400).json({ error: 'Please use a valid, permanent email' })
  }
  next()
}

app.post('/register', verifyEmail, (req, res) => {
  // create user here — email already screened
  res.status(201).json({ ok: true })
})

Real-time SMTP mailbox checks

Single, batch, and async bulk verification

Disposable, role account, and catch-all detection

Pay-as-you-go credits with no subscription lock-in

Search fit

Built for Express email verification

Use Verifly when you need a simple API, predictable pricing, and clean JSON results before emails hit your product, CRM, or campaign tool.

Gate a POST /register route with verification middleware
Proxy verification so the browser never sees your API key
Clean an imported list from an admin endpoint
Validate a contact form before queuing an email

Verify in Express, keep the key on the server

Express is the layer where you own the request before it becomes a user, so it is the right place to screen an email. A regex or a library like validator.js only confirms user@dead-domain.com is well-formed; it cannot tell you the mailbox bounces. Verifly runs a live SMTP probe over one HTTPS call and returns a JSON verdict with a result field of deliverable, undeliverable, or risky plus flags for disposable, role, catch_all, and smtp.

The critical rule is that the check runs server-side. Your Verifly key is a Bearer secret read from process.env — it must never ship to the browser or appear in a client bundle. Model the check as Express middleware: a small verifyEmail function that fetches Verifly, and mount it in front of any route that accepts an address. If you have a frontend that wants a live check, expose your own thin endpoint that proxies Verifly, so the browser talks to your server and your server holds the key.

Pricing suits a Node service well — no seat, just credits from $2 per 1,000 checks down to $0.60 per 1,000 at volume. Self-register for 100 free credits with no card at the autonomous register endpoint, put the key in your environment, and you are calling in minutes.

A proxy endpoint for your frontend

When a React or plain-JS frontend wants to check an address as the user types, do not hand it the key. Instead, expose a minimal proxy route on your Express server. The browser calls /api/check-email, your server calls Verifly with the secret key, and only the safe verdict comes back. Fail open on errors so a Verifly hiccup never breaks your form, and consider a short debounce on the client to avoid spending credits on every keystroke.

A key-safe proxy route
app.get('/api/check-email', async (req, res) => {
  const email = String(req.query.email || '')
  try {
    const url = `https://verifly.email/api/v1/verify?email=${encodeURIComponent(email)}`
    const r = await fetch(url, {
      headers: { Authorization: `Bearer ${process.env.VERIFLY_KEY}` },
      signal: AbortSignal.timeout(8000),
    })
    const data = await r.json()
    // only return what the browser needs — never the key
    res.json({ result: data.result, disposable: !!data.disposable })
  } catch {
    res.json({ result: 'unknown' }) // fail open: don't break the form
  }
})

Batch-verify a list from an admin route

For cleaning a list rather than a single signup — an admin import, a CSV upload, or rows from your own database — do not loop the single endpoint. POST them together to /api/v1/verify/batch, which takes a JSON body with an emails array and returns a results array in the same order. Map it back against your source rows and keep only the deliverable addresses.

Batch verification with fetch
app.post('/admin/clean', async (req, res) => {
  const { emails } = req.body // e.g. ['a@x.com', 'b@y.com', ...]
  const r = await fetch('https://verifly.email/api/v1/verify/batch', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.VERIFLY_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ emails }),
  })
  const { results } = await r.json()
  const kept = results
    .filter((x) => x.result === 'deliverable' && !x.disposable && !x.role)
    .map((x) => x.email)
  res.json({ kept, total: results.length })
})

FAQ

Frequently asked questions

Can I call Verifly directly from the browser in an Express app?

No. Your Verifly key is a Bearer secret. Call it from your Express server — either as middleware in front of a route or through a thin proxy endpoint — so the key stays in process.env and never reaches the client bundle.

How do I make verification a reusable middleware?

Write a small async function that reads req.body.email, fetches /api/v1/verify with the Bearer key, and either calls next() or responds 400. Mount it in the route chain before your handler, e.g. app.post('/register', verifyEmail, createUser).

My frontend needs a live check — how without leaking the key?

Expose a proxy route like GET /api/check-email that the browser calls. Your server forwards to Verifly with the secret key and returns only the verdict fields. Debounce on the client so you do not spend a credit per keystroke.

How do I verify a whole list of contacts?

POST them to /api/v1/verify/batch as a JSON emails array and read the results array back, filtering on the result field. Batching is faster and cheaper than looping the single endpoint in Node.

What fields come back from the API?

Each result has result (deliverable, undeliverable, or risky), is_valid, and boolean flags disposable, role, catch_all, and smtp. Branch on result and use the flags to strip throwaway or generic role addresses.

What does Express email verification cost?

Pricing is pay-as-you-go from $2 per 1,000 checks down to $0.60 per 1,000 at volume, with 100 free credits when you self-register. There is no subscription, so a low-traffic register route costs only the credits it spends.