Every bulk verification report ends with a number: the share of rows that came back verified. It reads like a pass rate, and it hides the only distinction that matters when you start sending.
The three states
| State | What the mail server actually said | What to do |
|---|---|---|
valid |
The specific mailbox accepted a probe | Send |
invalid |
The mailbox was rejected, or the domain does not take mail | Drop the row and the pattern that made it |
unknown |
The domain is catch-all and accepts everything | Keep it out of your main sends until it is proven |
A report that shows one figure is either turning invalid into a footnote or filing unknown under valid. The second one is worse, because a catch-all address that gets billed as verified still bounces exactly like an address nobody checked.
Catch-all is a property of the domain, not a defect in your list
An accept-all mail server answers the same way for a real employee and for a string you invented. Re-checking does not change that: the answer is a property of how the domain is configured. What a correct verifier can do is name it. unknown is the accurate result, and it is useful — it tells you which rows must not touch your warmed sending domain, and which ones are worth an individual look.
A vendor that reports valid on a catch-all mailbox is reporting the wrong thing rather than a better thing.
The file is moving while you look at it
- 40% of email addresses are dead within two years (NeverBounce)
- 23% of business contacts change jobs every year (ZoomInfo, 2025)
- Fresh collected data beats stored databases by 42% on response (Harvard Business Review, 2024)
So the report is a timestamp, not a property. Verify a 10,000-row file in January, run the campaign in April, and you are sending into a list that has quietly aged — including rows that a quarterly re-check would bill you for all over again.
The arithmetic nobody puts on the invoice
Per-check billing charges the same credit for an unknown row as for a confirmed mailbox. Run a cleaned file of 10,000 rows through a per-check tool and you paid for 10,000 probes; the usable contacts you got are the subset that came back valid, minus the ones time has since taken back.
The honest comparison is cost per usable contact, and it needs the vendor's own split: how many rows landed in each of the three states. If the report will not show it, the denominator is unknown and the price per usable contact cannot be computed from their numbers.
TAPAC prices it per verified contact: $0.10-0.50, 100 free searches, no seat licence, no separate re-check line, no separate enrichment line. Verification happens inside the request that found the address, so a row is not found once and billed twice.
Verifying inside the search
curl -s -X POST https://tapacapi.com/v1/contacts/search \
-H "Authorization: Bearer ***" \
-H "Content-Type: application/json" \
-d '{"industry":"logistics","job_titles":["operations manager"],"company_size":"51-200","location":"netherlands","source":"website","limit":100}'
Each contact comes back with the source the address was found in and the SMTP state of the mailbox, so a large run produces already-verified rows instead of a file to clean later. Single addresses go through POST /v1/contacts/verify. From an agent, the same thing is one tool call — npx -y @tapacapi/mcp, or the hosted endpoint at https://tapacapi.com/mcp, exposing tapac_find_contacts and tapac_status. Without an API key the server returns onboarding instead of an error.
What this does not fix
- A catch-all domain stays
unknown. There is no setting that changes it. - A verified mailbox can be abandoned tomorrow. Verification buys you the send you are about to make, not a permanent state.
- If your list was assembled from pattern guesses against a source that never published the address, verification tells you which guesses were wrong — it does not tell you which of the accepted ones belong to the person you meant.
The point of bulk verification is not a percentage at the top of a report. It is knowing, row by row, which of the three answers you got, so the ones without an answer never reach a warmed sending domain.
Top comments (0)