Apify Store has a lot of email verifiers. The biggest ones I found had between 400 and 1,400 users in the last 30 days, at about $0.90 per thousand addresses. They answer one question: does this mailbox exist?
None of them answered the question I kept running into: am I allowed to send a first marketing email to it?
That answer depends on the country of the person you are writing to. Germany, Spain and Italy want consent before the first email, even to a company address. The US allows it, but wants a postal address and an opt-out in every message. Sweden protects people and not companies. Slovakia and Slovenia care whether the company published the address itself.
I had already read those laws for 31 countries for a free web checker. This week I turned the same rules into an Apify Actor: Cold Email Law Checker.
What it does
You give it a lead list. It adds a verdict to every row:
-
law_verdict:ok,cond(only in specific cases),consentorunknown -
law_reason: one sentence on why -
law_mustInclude: what the email itself has to contain, such as an opt-out or a postal address -
law_lawSource: a link to the law or the regulator -
law_checked: the date I checked that country
Your own columns stay, so you can filter the dataset and keep only the rows you may email.
Three ways to feed it
-
The output of another Actor run. Pick the dataset of your lead scraper. Nested fields like
location.countryare found automatically. - A CSV link.
- A JSON list of addresses or objects.
It works out which field is the email, which is the country and which says where the address came from. You can name them yourself if it guesses wrong.
Two details that change the verdict
Use the person's country, not the company's. The rules follow the recipient. A German employee of a US company is a German recipient. When a row has both, the checker prefers the person's location.
Say where the address came from. In Canada, Australia, the Netherlands, Slovakia and Slovenia the answer depends on whether the company published the address itself. Add a source column: published, or vendor for anything a tool found or guessed. Values like apollo or hunter count as vendor.
How I checked it
The Actor and the web checker share one rules file, generated from the same data, so they cannot drift apart. The tests run an example export through the Actor and compare every verdict with what the website says for the same rows. Running the example input before launch caught a bug, and now there is a test for it: the Actor looked for the source column only in the first row, so a Slovak address published on the company's own site got the wrong verdict whenever the first lead had no source.
On my laptop it checks 20,000 leads in about four and a half seconds. On Apify the first runs took one to two seconds.
Limits
This is a research summary, not legal advice. It covers the first unsolicited marketing email to a business recipient. GDPR applies on top whenever an address identifies a person. Every verdict links to its source so you can check it, and if you know one of these laws better than I do, open an issue on GitHub and I will fix it.
It is free while I find out whether people use it.
Top comments (7)
"Does it exist" versus "may I write to it" is a distinction most outbound tooling just ignores, so this is a useful angle. The Slovakia and Slovenia detail about whether the company published the address itself is the kind of nuance that's easy to miss. How do you handle addresses where the country of the person and the country of the company's domain disagree, say a German employee at a US-registered company? That seems like the case most people get wrong.
Good question, and you're right that it's the common trap. The Actor treats the recipient's own country as the deciding one, since that's where these laws protect people. So a German employee at a US company with country = DE gets the German rule: consent first. The domain is only a fallback when the list has no country column, and a .com says nothing about country, so that row comes back "Country unknown" instead of a guess. If you know where the person sits, put it in the country column and it wins.
Letting the country column win over the domain makes sense, and "Country unknown" for a bare .com is better than a guess. Do rows where the person's country and the company's country disagree get flagged, so someone can check those by hand?
Existence vs. permission is the distinction the whole verification industry glosses over — a "valid" verdict on an address you'll get fined for emailing is worse than useless, it's liability with confidence. The layer most teams miss: consent isn't a one-time check, it's state. Someone can be legal to email on Monday and illegal on Tuesday after they withdraw consent, which means the checker result has a TTL whether you model it or not. Do you treat the law check as a send-time gate or a list-hygiene pass? The failure modes are completely different.
It's a list-hygiene pass. It answers "may I send a first email to this address at all", which follows from the country and the kind of address and doesn't change day to day. Withdrawn consent and opt-outs are state, so they belong in the sending tool's suppression list, checked at send time. Laws do change, so every verdict carries the date I last checked that country.
Fair — that's a cleaner split than my framing. The hygiene pass answers "may I ever send," the suppression list answers "may I send now," and mixing them is where teams build one mega-check that does neither well. The wrinkle from my side: that date-last-checked on the verdict is a TTL, just a slow one. I run email infra where "accepted" and "delivered" are different events entirely — an SES 200 OK means accepted, and the address can still die silently downstream. So I treat the hygiene verdict the same way you treat the law: cached, dated, re-verified on a schedule, never trusted blindly at send time. How often do you re-check a country's rules — on a timer, or only when something changes?
The person's-country-over-domain rule carries more rows than it looks. On the people records I work with, about one in nine sales-titled people based in Germany or the UK works for a US-headquartered employer: 34k of 297k in Germany, 102k of 931k in the UK, counted this morning, and the Netherlands sits at the same share. A checker keyed on the email domain would hand every one of them the US rule. At that share I would make the country column a required input rather than a fallback, and keep the domain only for the rows that have nothing else.