GTM Engineering
Your Enrichment Vendor Is Wrong 30% of the Time
Vendors self-report 95 to 98 percent accuracy. Run an independent SMTP test and roughly half of what they found bounces, because B2B contact data decays about 30 percent a year. Here is the verify-before-trust build that measures today, not ingest day.
· 14 min read
B2B contact data decays about 30 percent a year (ZoomInfo’s own churn figures), which means a record your vendor scraped 12 months ago has a roughly one-in-three chance of being wrong today, and the accuracy slide never says so. For years the enrichment decision ended at the match rate: the vendor reported 95 to 98 percent accurate, you signed, and you routed deals and sent email on the strength of that number. The number was real. It answered a question you do not care about. Every time I have run my own SMTP verification against the emails a vendor returned, valid-of-found lands closer to half. Both numbers are true, they measure different things, and the gap between them is where your outbound quietly dies.
Nobody spot-audits their provider. You pay the invoice, you trust the accuracy claim on the deck, and you send on data that is wrong often enough to matter. I found this the hard way on a name-enrichment job: 464K corporate records missing usable names, and after building a real verification layer I recovered about 329K of them. The other 135K were not recoverable at any accuracy I would stand behind, so I left them empty rather than ship guesses. A vendor would have “filled” most of that 135K and reported high coverage. Coverage is not accuracy. Watch what happens to a contact’s validity as the record ages, because this curve is the reason the deck and your inbox disagree.
Self-reported accuracy measures the wrong thing
When a vendor says 97 percent accurate, they mean: of the records where we returned an answer, 97 percent matched our reference set at the time we ingested it. That sentence hides two holes.
First, “of the records where we returned an answer” excludes everything they could not find. Coverage and accuracy are different axes, and vendors only ever advertise the flattering one. ZoomInfo’s US email find rate is about 65 percent and its global rate about 35 percent (ZoomInfo), so a third to two-thirds of your list never entered the accuracy denominator at all.
Second, “at the time we ingested it” ages badly, and the decay curve above is exactly how badly. People change jobs. An email that was valid when the vendor scraped it 14 months ago is a hard bounce today, and it still counts as a correct record in their accuracy math because it was correct once. The curve does not care about the deck. At 12 months it has already given back roughly 30 percent of what was true at ingest.
Your SMTP test measures the thing you care about: does this email accept mail right now. That is why an independent verification pass on a vendor’s own output routinely lands near half valid. You are measuring today’s deliverability; they measured historical match. The deck reports the y value at age zero. Your inbox lives somewhere out on the curve, wherever the record happens to sit.
The verify-before-trust build
The fix is not a better vendor. It is a stage the vendor cannot sell you, because it grades their homework. Build it bottom to top, and note that every rung exists to move you off the deck number and onto the curve. Read the ladder, then I will show the code and the worked example under it.
- L5Refuse to fill what you cannot verifyleave empty
When a chunk of records cannot be recovered at an accuracy you would stand behind (the unrecoverable 135K on that name job), leave them empty and say so. An empty field is honest; a guessed field routes a deal into the wrong queue and never tells you.
- L4Re-verify on a schedule, not once~30% / yr
Validity decays about 30 percent a year (ZoomInfo), so a January verify is a January fact. Re-run the SMTP pass on the addresses you still send to, on a cadence, or the curve rots your list while the dashboard stays green.
- L3Break out catch-all per segment20-30%
Catch-all runs under 10 percent overall but 20 to 30 percent at large enterprises. Report valid-of-found per segment or your enterprise deliverability hides behind a green SMB average.
- L2Classify into four buckets, not two4 buckets
Valid, invalid, catch-all, and unverified. The two-way valid-or-invalid split is what inflates the number. Only one of the four buckets earns a send, and catch-all gets its own row so it cannot hide inside "valid."
- L1Own the SMTP check, not the provider scoreyou measure
Run an SMTP validation you control against every address the waterfall produced, regardless of which provider found it. The provider grading its own homework is how you got here. This is the only accuracy number you should trust, because you measured it.
So the last stage of any waterfall is always independent verification. Take every email the chain produced and run it through an SMTP validation you control, not the provider’s own confidence score. What survives that pass is what you route and send on. What does not survive gets marked unverified and stays out of the send list. If you have not built the chain that feeds this stage yet, start with the enrichment waterfall and treat this as the rung that goes on the end.
# The verify stage: never trust the provider's own confidence flag.
# Classify into four buckets, not two. Only "valid" earns a send.
def classify(email, smtp_result, mx_is_catch_all):
if smtp_result == "hard_bounce" or "@" not in email:
return "invalid" # drop from send list
if mx_is_catch_all:
return "catch_all" # its OWN bucket, do not count as valid
if smtp_result == "accepted":
return "valid" # the only bucket you send on
return "unverified" # provider said yes, SMTP could not confirm
The mistake almost everyone makes is the two-way split. The catch-all bucket is the one that lies, and it needs its own row. So does the unverified bucket: an address the provider returned that your SMTP check can neither confirm nor reject is not the same as a confirmed-good address, and folding it into “valid” is how the two-bucket world inflates its own numbers. Four buckets, and only one earns a send.
Run the verification on a schedule, not once. An email you confirmed valid in January is a data point about January. On the books I have watched, job changes chew through a couple of percent of a contact list every month, which is the monthly slope of the 30 percent annual curve above, so a list you verified six months ago has quietly rotted into the low double digits while you treated it as clean. The provider will not tell you, because to their accuracy math it was correct at ingest. The only way you know is to re-run your own SMTP pass against the addresses you still send to, and the only way that is affordable is that you built the verify stage as a repeatable step rather than a one-time cleanup.
Catch-all inflation is the hidden tax
Here is the mechanism most people miss. A catch-all domain accepts mail to every address, valid or not, so it never bounces at the SMTP check. On the lists I have audited, catch-all runs under 10 percent of domains overall and climbs to somewhere between a fifth and a third at large enterprises, because their mail security is configured to swallow everything.
That means your verification passes an address that will never reach a human. The vendor counts it valid. Your SMTP test counts it valid. Your rep sends to it and hears nothing, forever, and it looks like a cold prospect instead of a dead address. Flag catch-all as its own category or your enterprise segment’s real deliverability is 20 to 30 points worse than the dashboard claims.
View as table
| Item | Value |
|---|---|
| Vendor "valid" | 970 |
| Passed SMTP | 760 |
| Not catch-all | 510 |
| Truly sendable | 510 |
A worked example that reconciles to the curve
Take 1,000 vendor emails from a mixed list where the average record is about 12 months old, so the decay curve puts fresh validity near 64 percent before you even test. Run them down the verify stack and the four buckets fall out like this.
| Bucket | Count | Share | Earns a send? |
|---|---|---|---|
| Valid, not catch-all | 510 | 51% | Yes |
| Catch-all | 250 | 25% | No, its own row |
| Stale / hard bounce | 210 | 21% | No, invalid |
| Unverified | 30 | 3% | No, held back |
| Vendor reported “valid” | 970 | 97% | The deck number |
The vendor’s 97 percent is the bottom row: 970 of 1,000 returned an answer that matched at ingest. Your real sendable set is the top row: 510, or 51 percent, which is the roughly-half valid-of-found in the first stat tile. The 250 catch-alls are the hidden tax the SMTP check alone would have passed as valid, and the 210 stale rows are the decay curve cashing in, close to the 30-percent-a-year figure once you account for a list that averages a year old. The gap between 970 and 510 is not a rounding error. It is 460 emails that will never reach a human, sitting in a send list that looks full.
The cost lands in routing, not just bounces
Bad emails bounce and you notice. Bad firmographics route silently and you do not.
Employee-count bands are the worst offender. You route a company into the “mid-market, assign an AE” band because the vendor said 340 employees. The real number is 55. That deal now sits with an AE carrying an enterprise quota who will never prioritize a 55-person account, while the SMB team that would have worked it fast never sees it. No bounce, no error, no alert. A deal dies in the wrong queue because you trusted an employee count nobody verified. This is the same failure that routing is latency describes from the other end: the routing rule fired instantly and correctly on data that was wrong.
| Field | Vendor said | Truth | Silent cost |
|---|---|---|---|
| valid | catch-all | Rep sends, hears nothing, marks “cold” | |
| Employee count | 340 | 55 | Enterprise AE deprioritizes; SMB never sees it |
| Industry | ”Software” | Staffing agency | Wrong sequence, wrong messaging, no reply |
| Seniority | ”VP” | left 8 months ago | Bounce, or worse, reaches their replacement cold |
Multiply that across a routing rule that fires on every inbound lead and the vendor’s error rate becomes a structural leak in your funnel, and it never shows up as an error in any log. Firmographic errors cost more than email errors because they fail silently and compound. A bounced email tells you it bounced; the feedback loop is same-day and loud. A miscategorized employee count produces a deal that sits in the wrong queue, gets the wrong sequence, and dies of neglect over weeks, and the post-mortem blames the rep or the segment, never the field. Because nothing errored, nobody traces it back to the enrichment, so the same wrong band keeps routing the same kind of deal into the same dead queue quarter after quarter.
| What the deck claims | What the 100-row audit finds | |
|---|---|---|
| Email accuracy | 97% accurate | ~50% valid-of-found, 25% catch-all |
| Coverage vs accuracy | Reported as one number | Two axes, both measured |
| Freshness | Silent, assumed current | ~30% a year gone (ZoomInfo) |
| Firmographic routing | Assumed correct | Hand-checked band by band |
| Who graded it | The vendor | You, on your data, today |
Run a 100-row spot audit this week
- 1
Pull 100 records your vendor recently enriched
Random sample across your real segments, not the cleanest 100. Weight it toward the segment you route the most deals through.
- 2
Run the emails through an SMTP validation you control
Not the provider score. Mark hard-bounce as invalid. Flag catch-all as its own bucket, never as valid.
- 3
Hand-check firmographics against the source
Employee count and industry against the company site or LinkedIn, on the same 100. Ask whether the band would route where a human would pick.
- 4
Count three numbers
Valid-and-not-catch-all emails, employee bands that route correctly, and records the vendor filled versus got right. These are your real accuracy figures.
- 5
Bring both numbers to the renewal
Put your valid-of-found next to their 97 percent on the deck. The gap is the leverage, and it is the only accuracy figure you should trust, because you measured it.
One more thing the audit buys you: a defensible refusal to fill, which is L5 of the stack. When a chunk of your records cannot be recovered at an accuracy you would stand behind (the unrecoverable 135K on that name job), the disciplined move is to leave them empty and say so, not to let a vendor guess and call it coverage. An empty field is honest; a wrong field routes a deal into the wrong queue and never tells you. The vendor is incentivized to fill, because coverage is what the deck sells. You are incentivized to be right.
You can also model what an honest waterfall costs per verified record before you sign anything. Move the hit rates to what your own audit found, not the deck, and watch the blended cost move:
per verified record
Order matters. Put the cheap high-hit provider first and blended cost drops, because the expensive one only ever touches the records nobody else could find.
per verified record: $0.024
The 97 percent on the renewal deck is not a lie. It is an answer to a question you do not care about, measured at a point on the curve you never send from. The question you care about is how many of these emails reach a human this week, and the only person who can answer it is you, with an SMTP test and an afternoon. Run the 100 rows before the renewal call, not after.
Keep reading
One email. Every week.
One email a week: a system I built or broke, with the config, the numbers, and what I would change. No roundups, no theory, unsubscribe whenever it stops being useful.
The newsletter opens soon.
Connect a provider in src/config.ts