B2B data · source yield
The address is the only number that matters in a B2B list
We keep a working file of company domains and count, for every source family, how many rows survive and how many of those rows actually publish an address. The result is uncomfortable for anyone selling lists by the thousand: the intake number and the sendable number are different quantities, and the gap between them is a property of the source, not of the list.
Rows are not contacts
A list of 10,000 rows sounds like 10,000 chances to get a reply. It is not. A row becomes sendable only when the domain is the company's own and the address belongs to that same domain — published by the company, reachable by MX, and not a role mailbox that a filter will quietly bin.
Counting those conditions one source family at a time is what produced the table below. Every row thrown away keeps the reason attached, which is why the reject file is longer than the send file on some sources.
Yield by source family
| Where the domain came from | Domains taken | Live site with product signals | Rows kept | Share that publish an address |
|---|---|---|---|---|
Application marketplaces (vendor-filled external_url) | 3,000 | 1,798 (76%) | 1,538 (65%) | 0% at intake → 56% after walking the site's own contact page |
| Agency directories | 59 hosts per pass | full pass | 492 | ~60% |
Package registries (projectUrl, homepage_uri) | 3,821 | 140 (29%) | 140 | ~15% |
Repository homepage (GitHub repos and organisations) | 2,429 | 553 | 553 | ~11% |
| WordPress.org (plugin homepage, theme author URL) | 9,785 | 600 of 695 (themes) | 486 plugins + 490 theme authors | ~34% for theme authors (166 of 490) |
| Job-description text (boards, “who is hiring” threads) | ~1,100 vacancies | - | 8 of 16 domains confirmed | half the rows never reach the contact step |
Theme authors behave like agencies rather than like open-source projects: 8,695 themes in the WordPress.org directory resolved to 729 unique author domains, 695 of them new to the file, 600 answered with a product site and 490 were kept. A third of those publish an address on their own contact page, against 11% for repository pages.
The address share is the column that decides whether a list is work or decoration. A 10,000-row file at 11% is 1,100 sendable addresses; the same file at 56% is 5,600.
The field the vendor filled beats the field we scraped
Two ways to get a domain: read it out of a text where someone mentioned their company, or read it out of a field the company itself filled in a directory. The second is cleaner by construction. On a job board the domain has to be found inside the vacancy body, and roughly half of those attempts land on the board itself, on a recruiting platform, or on a duplicate of a company already in the file. On an application marketplace or a package registry the domain is a field with a name, filled by the vendor, and the reject rate drops to single digits.
That only fixes the domain. None of these fields contain an address, which is why we stopped treating row count as progress and started walking the sites themselves.
Walking 300 “contactless” rows
We took 300 rows whose source field had no address, opened each company's own site and looked at the pages a company
publishes for contact: the home page, /contact, /about, an imprint page where the law requires
one. Only addresses whose domain matched the company's own domain were kept.
| Step | Result |
|---|---|
| Rows walked | 300 |
| Domains with a published address on their own site | 172 |
| Kept after matching the address to its own domain | 169 |
| Answering MX | 169 of 169 |
| Spot-check of the addresses against the live page | 4 of 4 confirmed |
So a source that looks contactless at intake is more than half contactable if you read the pages the company actually maintains. The three rejected addresses show the other side of the rule: a mis-split address and two tokens that only looked like addresses in raw HTML. They were dropped, not repaired — an address that has to be guessed is not a contact.
How we count, so you can re-run it
- Domain from a filled field. No row enters the file without a domain that belongs to the company and a URL where it was published.
- Live site with product signals. A 200 is not enough: the page has to show pricing, a sign-up, a demo request or integrations. Documentation sites, personal pages and framework homepages are cut here.
- Address matched to its own domain. A role address on a third-party domain is not a contact for that company, however it appeared on the page.
- MX before sending. Every address domain answers MX; the ones that do not are marked, not hidden.
- The reject reason is kept. Rows removed for a duplicate domain, a dead host, a wrong-domain address or a missing MX stay in a reject file with the reason, which is how the tables above can be checked.
Three questions for anyone selling you a list
- What share of the rows publish an address on their own domain — not what share has “a contact field”?
- How many domains answer MX, and what happened to the ones that did not?
- Which addresses came from a field the company filled, and which were assembled by a tool?
A vendor who cannot answer the third question is selling the 0% column of the table above. That is the whole argument for building the file instead of buying it — and it is the first thing we do inside the $900 sprint, before a single email is written.
Where this was written up
The source-by-source counts and the 300-row walk are published as an article on dev.to: Your B2B list is worth its address share, not its row count.