Private betaMailbeam is in private beta — the public API isn't live yet.Join the waitlist

Migrate from Emailable

This guide shows how to replace Emailable's verification calls with Mailbeam. Most migrations take 30–60 minutes: the work is swapping one request and mapping Emailable's state string onto Mailbeam's boolean plus score.

Why developers switch

  • EU data residency: Emailable processes on US infrastructure, so EU companies need Standard Contractual Clauses; Mailbeam processes in Frankfurt with a DPA on every plan
  • Built for forms: Emailable's single-address latency is around 250ms, slow for validating inline while someone is still typing
  • Graded catch-all: Emailable returns accept-all domains as risky or unknown with nothing to threshold on; Mailbeam adds a 0–100 score and a reason
  • Pricing you can isolate: credit bundles plus separately priced deliverability add-ons make the cost of verification itself hard to read
  • Sandbox mode: a deterministic test mode for CI, rather than calling production

One thing genuinely favours Emailable: it offers seed and inbox-placement testing and ongoing deliverability monitoring, which Mailbeam deliberately does not. Teams that need those often keep Emailable for deliverability and move only verification.

Endpoint mapping

EmailableMailbeamNotes
GET /v1/verify?email=&api_key=POST /v1/verifySingle verification
POST /v1/batchPOST /v1/verify/batchUp to 500,000 addresses per job
GET /v1/batch?id=GET /v1/jobs/{id}Batch status

Authentication

Emailable passes the API key as a URL query parameter, which means it ends up in access logs, browser history and proxy traces. Mailbeam takes a Bearer token in the header, so the credential stays out of the URL.

Emailable (old):

curl "https://api.emailable.com/v1/verify?email=user@example.com&api_key=YOUR_KEY"

Mailbeam (new):

curl -X POST https://api.mailbeam.dev/v1/verify \
  -H "Authorization: Bearer $MAILBEAM_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com"}'

Response mapping

Emailable reports a single state string. Mailbeam splits the same information into a boolean you can branch on and a score you can threshold.

Emailable fieldMailbeam equivalent
state: "deliverable"valid: true, score >= 70
state: "undeliverable"valid: false
state: "risky"valid: true, score 30–69
state: "unknown"status: "unknown"
reasonreason (machine-readable code)
disposabledisposable
rolerole
accept_allcatchAll plus a graded score

Migrating the call

Emailable (old):

const res = await fetch(
  `https://api.emailable.com/v1/verify?email=${email}&api_key=${apiKey}`
);
const { state } = await res.json();
if (state !== "deliverable") return 422;

Mailbeam (new):

// No SDK to install — see /docs/quickstart for this 12-line wrapper.
import { verifyEmail } from "./lib/mailbeam.js";

const { valid, score, reason } = await verifyEmail(email);
if (!valid || score < 60) return 422;

Note what the old branch was doing: state !== "deliverable" rejects risky and unknown along with genuine failures. If your signup funnel was quietly dropping accept-all corporate addresses, this is where it was happening.

What to check first: risky and unknown

Emailable collapses two different situations into strings you have to interpret. An accept-all domain and a server that refused to answer both arrive as something other than deliverable, and most integrations reject both. Mailbeam separates them, so you can decide once and for each case:

const { valid, status, catchAll, score, reason } = await verifyEmail(email);

if (status === "unknown") {
  // The server would not answer — greylisting, timeout, temporary refusal.
  // This is not evidence the mailbox is bad. Accept and re-verify later.
  return acceptPendingReverification();
}

if (catchAll) {
  return score >= 70 ? accept() : challenge({ reason });
}

return valid ? accept() : reject({ reason });

Next steps