OXYGENOxygen/ Docs
Providers

Email verification

Check whether addresses you already have are safe to send to, including catch-all domains.

Verification grades an address you already have: is it safe to send to? Finding an address you don't have is a different chain — see Waterfalls.

One verifier chain serves every surface — the verify_email enrichment column, oxygen verify email, the oxygen_verify_email MCP tool, and POST /api/cli/verify/run — so the same address cannot get a different verdict, or a different price, depending on where you asked. The chain's current members are listed under Waterfall defaults.

Verdicts

VerdictMeaningSend to it?
validA verifier confirmed the mailbox exists.Yes
invalidThe mailbox does not exist, or the address is disposable, a spam trap, or do-not-mail.No
catch_allThe domain accepts mail for every address, so no verifier can confirm this specific mailbox.Judgement call — see below
unknownNo verifier could answer. This is an absent answer, not a bad address.Don't drop these; re-run

The two that get misread are catch_all and unknown. Filtering "everything that isn't valid" throws away good contacts: unknown usually means a verifier had a bad moment, and catch_all is extremely common on well-run corporate domains.

Catch-all domains

A catch-all (or "accept-all") domain answers yes to every address, so probing anything@company.com succeeds whether or not the mailbox is real. A generalist verifier can only flag this.

When that happens, Oxygen automatically escalates the address to a catch-all specialist that resolves a large share of them, including addresses behind secure email gateways. You do not configure this; it is the default chain.

Two rules keep the cost sane:

  • Escalation fires only on a catch_all verdict — never speculatively, and never on unknown (an inconclusive cheap pass is not evidence of a catch-all domain).
  • If the specialist cannot resolve it either, the address keeps catch_all. Oxygen never upgrades a catch-all to verified because the escalation was unavailable.

For addresses that stay catch_all, the honest play is to send a small watched batch first, or confirm the person independently — verification alone cannot clear them.

Cost, and sizing the ceiling

Cost is not flat per address. Every address pays the first pass; only catch-all addresses additionally pay the escalation, which is several times more. A ceiling sized as "N addresses × first pass" runs out as soon as a few turn out to be catch-all.

Run the free preview first. It returns real numbers:

oxygen verify email a@acme.com b@acme.com --json
{
  "estimate": {
    "first_pass_credits_per_email": 2.245,
    "catch_all_escalation_credits_per_email": 17,
    "min_credits": 4.49,
    "max_credits": 38.49,
    "recommended_max_credits": 38.49
  }
}

Pass recommended_max_credits (the estimate's worst case: every verifier plus an escalation on every address) as --max-credits. It is a ceiling, not a charge — you are billed for what actually runs, so over-reserving costs nothing.

oxygen verify email a@acme.com b@acme.com --mode live --max-credits 38.49 --json

If the ceiling runs out mid-batch, verification does not fail. The remaining catch-all addresses come back unescalated with escalation_skipped: budget_exhausted — a budget signal, not a provider outage. Re-run those with a higher ceiling.

escalation_skippedCauseFix
budget_exhaustedRemaining ceiling could not cover an escalation, so it was never dialled.Re-run with recommended_max_credits.
escalation_unavailableThe call was attempted and failed (no credential, or a provider error).Check the connection, then retry.
not_configuredEscalation was explicitly disabled.Nothing, if intended.

Verifying a whole table

Add an Email verification column pointed at the column holding your addresses. It runs the same chain, including the automatic catch-all escalation, and writes the verdict into the cell so you can filter and segment on it.

In the app, open a table and click + Add columnEmail verification. It sits with Work email, Mobile phone, and LinkedIn URL. If your table has a column named email or work_email, Oxygen maps it automatically; otherwise pick it in the column editor.

From the CLI, preview for free first — the preview returns recommended_max_credits, which is the number to pass:

oxygen enrich-column preview <table> --capability verify_email --json
oxygen enrich-column run <table> --capability verify_email \
  --max-credits <recommended> --approved --json

--email-column <key> names the source column explicitly when auto-detection picks the wrong one.

Do not hand-build a single-provider action column for this — that skips the escalation, so every catch-all row comes back unresolved. If you searched the column picker for a verifier and found a provider operation, that is the shape this warning is about: use the Email verification column instead.

  • Runs — per-cell provenance and attempt traces
  • Columns — adding the verify_email enrichment column

On this page