Pre-Black Friday: 20% off, for as long as you stayEARLYBFon Solo and AgencyEnds Nov 28Start free

How-to guide

How to verify catch-all emails (accept-all domains)

No tool can prove a mailbox exists on an accept-all domain. Here is how to split the risk, size it for free and send in the right order.

Get your free API key →Free to start. No credit card. 1,000 records to spend whenever you like.

You cannot verify a single address on a catch-all domain. The server says yes to every name, so a probe proves nothing. What you can do is label the risk, size it before you spend, and send in order: verified first, catch-all last.

TL;DR

  • Catch-all domains accept mail for any name, so SMTP probes return "valid" for fake addresses. Treat the result as a risk band, not a yes or no.
  • Time: about 20 minutes. Sizing costs 0 records. A 25-person test page costs 25.
  • LeadOcean labels each email (verified, catch_all_valid, catch_all, risky, and more) so you can filter by band in the query.

Prerequisites

  • A LeadOcean API key, exported as $LEADOCEAN_API_KEY. The Free plan gives 1,000 records for life, no card, 5 requests a second.
  • curl and jq.
  • A target audience in mind (title, country, function).

Step 1: Know what you are dealing with

Send a probe to a made-up name on the domain. If it is accepted, the domain is accept-all.

bash
dig +short MX acme.com
nc -v mx.acme.com 25   # run on a domain you control or may test
RCPT TO:<zz-not-a-real-name-91827@acme.com>
250 means accept-all. 550 means the server rejects unknown users.

A 250 on a fake name means any real name will also get a 250. Background: what is a catch-all email and catch-all emails explained.

Do not do this per lead. It is slow, many servers rate-limit or greylist probes, and it still cannot tell you if Jane is real.

Some accept-all domains are not truly open. Some servers accept the message and bounce it later, which a probe cannot see. Others silently drop it. In both cases the probe says "valid" and the mail never lands, so a clean probe on an accept-all domain is weak evidence.

Step 2: Pull the status with the email, not after it

LeadOcean stores an emailStatus on each person. These are the values that matter:

StatusMeaning for sending
verifiedMailbox confirmed. Send.
catch_all_validAccept-all domain, but LeadOcean confirmed the mailbox through the provider's identity check (Microsoft 365 managed tenants and Google Workspace only). Send second.
catch_allAccept-all domain, no signal. Send last, in small batches.
risky, unknown, untested, role, derivedSkip, or test first.
invalid, disposable, spam_trap, abuseExclude.

Filter values are exact strings. Check them first.

bash
curl -s "https://api.leadocean.io/v1/enums/email_status" -H "x-api-key: $LEADOCEAN_API_KEY" | jq '.'

In an AI client with the LeadOcean MCP server connected, ask for leadocean_list_enum_values with name: "email_status" instead. Both are free.

One trap: as a filter, catch_all also matches catch_all_valid. Filter on catch_all_valid alone for the confirmed set (API reference, October 2026).

Step 3: Size each band for free

Count the audience once per band. A count spends no records. Filters are arrays, and the count is a query parameter on search with limit=1:

bash
for s in verified catch_all_valid catch_all; do
  echo -n "$s: "
  curl -s "https://api.leadocean.io/v1/people/search?count=true&limit=1" \
    -H "x-api-key: $LEADOCEAN_API_KEY" -H "Content-Type: application/json" \
    -d "{\"jobLevel\":[\"VP\"],\"jobFunction\":[\"Sales & Business Development\"],\"country\":[\"CA\"],\"emailStatus\":[\"$s\"]}" \
  | jq -r '.meta.total'
done

The same count through MCP is leadocean_count_leads with the same filters. It also returns distinctCompanies, which tells you how many domains the band spans.

Step 4: Pull and send in order

Pull the verified band first, with a small page to test.

bash
curl -s "https://api.leadocean.io/v1/people/search" \
  -H "x-api-key: $LEADOCEAN_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "jobLevel": ["VP"],
    "jobFunction": ["Sales & Business Development"],
    "country": ["CA"],
    "emailStatus": ["verified"],
    "limit": 25
  }' | jq '.meta'

Then follow a simple send plan:

  1. Send the verified band at normal volume.
  2. Send catch_all_valid next, at about half your normal daily volume.
  3. Send catch_all last, in batches of 50 to 100, and watch bounces for two days before the next batch.
  4. Suppress every hard bounce. LeadOcean does not refund records for bounced emails, so read the status before you send.

Pull more with the cursor from the previous page. One search pages to 10,000 rows. Narrow the filters if you hit meta.depthCapped. For files over a few thousand rows, use POST /v1/exports (up to 50,000 rows a request, 500,000 a day, not on Free). The CSV carries email_1_address and email_1_status, so you can split bands in a spreadsheet.

Step 5: Do the same from an AI client

With the LeadOcean MCP server connected (https://api.leadocean.io/mcp, OAuth sign-in, no key pasted), you can run the sizing in plain language. Paste this prompt:

code
Using leadocean_count_leads, count VPs in Sales & Business Development in
Canada three times: emailStatus verified, catch_all_valid, catch_all.
Pass facets=false. Report total and distinctCompanies for each, and tell
me which band is largest. Do not call any tool that spends records.

The count tool is free, so the model can try several filter sets without touching your 1,000 Free records. Ask it to spend records only after you pick a band.

What you get

Counts from leadocean_count_leads, run 2026-10-21. Filters: jobLevel VP, jobFunction Sales & Business Development, country CA. One emailStatus per row.

emailStatusPeopleDistinct companies
verified1,8541,392
catch_all_valid00
catch_all3,7202,567

On this slice, the catch-all band is about twice the verified band. None of it is labelled catch_all_valid.

Filter to verified only and you drop roughly two thirds of the reachable list. Send to all of it blind and about two in three emails go to domains that cannot confirm the mailbox. Use bands.

These are counts by email status, one status each, not mailable totals. Your numbers will differ with other filters.

Export column names, from the API reference:

code
email_1_address,email_1_status,email_2_address,email_2_status
jane.doe@acme.com,verified,,

This is the export header from the API reference, with a placeholder row.

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-keyRe-copy the key from app.leadocean.io and export $LEADOCEAN_API_KEY
429Above your plan's rate limit (5 a second on Free, 200 on Agency)Honour Retry-After, or move to a plan with a higher limit
402Free records spentMove to Solo or Agency. The Free 1,000 records do not refill
200 with empty data and meta.total 0Wrong enum string, such as Catch-All instead of catch_allCheck strings with GET /v1/enums or leadocean_list_enum_values
Count looks like a count, but data is emptyYou sent count=true, so data is empty by designDrop count=true to get rows
Export refusedOver 50,000 rows a request, 500,000 a day, or you are on FreeSplit the export by band or country; bulk CSV needs a paid plan

FAQ

Can any tool verify a catch-all email for certain?

No. A catch-all server accepts every name, so no outside check can prove the mailbox. Tools can only add signals and label the risk. Compare how vendors label it in best catch-all email verifiers.

Should I send to catch-all addresses at all?

Yes, in order and in small batches. On the slice above, skipping them would drop most of the list. Send them last and stop if bounces climb.

What bounce rate should I tolerate?

Set your own threshold with your sender's guidance. Pause the batch when it breaks, then suppress the bounced addresses before the next one.

Does sizing cost records?

No. Counts, enum lookups and filter lookups are free. Records are spent only when a person is returned. See pricing.

Size your catch-all risk before you send

Free to start. No credit card. 1,000 records to spend whenever you like.

Get your free API key →