Decision-Maker Email Finder
Pricing
from $20.00 / 1,000 email founds
Decision-Maker Email Finder
Find real, named contact emails for any company straight from their own website — not generic info@ addresses. Crawls team/about pages, generates verified patterns, checks MX validity, and scores confidence transparently.
Pricing
from $20.00 / 1,000 email founds
Rating
0.0
(0)
Developer
CANCAP
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
17 days ago
Last modified
Categories
Share
Finds real, named contact emails for a company by crawling only that company's own public website — no LinkedIn, no login-walled platforms, no paid third-party email-verification APIs.
What it does
- Takes a list of companies (domain + optional name and target job titles).
- Crawls a small set of likely pages on the company's own website: homepage,
/about,/team,/contact, etc. - Extracts:
- Emails already on the page (mailto: links, visible text)
- Names + job titles from team/about sections (best-effort heuristic — real-world HTML varies)
- If no email is found directly but a named person is, generates likely email patterns (
first.last@domain,flast@domain, etc.) — pure logic, no API. - Optionally verifies candidate emails for free:
- MX lookup (DNS) — confirms the domain can receive mail at all
- SMTP handshake probe (
RCPT TOcheck, no message ever sent) — estimates deliverability
- Falls back to generic addresses (
info@,contact@) only if nothing better was found, or if explicitly requested. - Outputs one row per candidate email with a transparent 0–100 confidence score.
Why "zero cost to the builder"
Every step uses either:
- The user's own Apify compute (billed to whoever runs the actor, via Apify's usual platform-usage billing), or
- A free, no-account-needed mechanism (DNS MX lookup, raw SMTP socket connection, regex/HTML parsing).
No step calls a paid API (no Hunter.io, NeverBounce, ZeroBounce, Clearbit, etc.) and no step requires you, the actor's author, to hold any third-party API key or pay for any external service.
Changelog
v0.1.1 — fixes from real-world testing on Windows
A user ran this on a real Windows machine against apify.com and caught two real bugs:
mxValidincorrectly returnedfalsefor a domain with valid MX records. Root cause: DNS resolution can intermittently fail on some Windows/VPN/corporate network setups (no error was being surfaced, just a silent failure treated as "no MX records"). Fixed by adding a retry and explicit error logging inmxCheck.js, so failures are now diagnosable in the run log instead of silently miscategorized.- A project showcase block was misidentified as a person. Apify's homepage features community projects (e.g. a tool with "Founder" in its description), and the original heuristic loosely matched any short Title-Case heading near the word "founder" as a person + job title — producing garbage like
personName: "Hlidac Shopu"with a run-on sentence as the job title. Fixed by makingextractPeople()inpageExtract.jsrequire the "title" to come from a genuinely separate sibling element, be short (≤60 chars), and not contain sentence punctuation — rejecting description blurbs while still matching real<h3>Jane Doe</h3><p>CEO</p>-style team cards.
Both fixes were verified with targeted unit tests (one positive case, one reproducing the exact false-positive pattern) plus a full end-to-end re-run. See git history / ask the author for the before/after test output if you want to verify yourself.
ECONNREFUSEDon MX lookup, specifically on a Windows machine using a mobile hotspot. The OS-level resolver (Windowsnslookup) worked fine for MX queries on that same network, but Node's built-in DNS resolver (c-ares) failed to even reach a DNS server. This is a known class of issue where Node's resolver path behaves differently from the OS's own resolver on certain Windows network setups (VPNs, hotspots, some routers). Fixed by explicitly setting public DNS servers (dns.setServers([...])— Google + Cloudflare) instead of relying on whatever the OS hands Node by default. This makes MX lookups more robust across the wide range of networks real users will run this actor from, not just the one we debugged.
Honest limitations (please read before publishing)
- SMTP verification is a signal, not a guarantee. Gmail, Microsoft 365, and many providers accept all
RCPT TOrequests at the SMTP layer and only bounce later — sosmtpCheck: "accepted"means "didn't reject it immediately," not "100% confirmed deliverable." This is documented in the output schema description on purpose, so users aren't misled. - Some networks block outbound port 25 entirely. When that happens,
smtpCheckreturns"unknown"rather than a false negative. This is expected and handled gracefully — it will NOT crash the run. - Name/title extraction is heuristic. Team page HTML varies enormously across the web. It will work well on many sites and miss on others. This is a best-effort layer, not a guarantee — the confidence score reflects that (pattern-generated emails always score lower than found-on-page emails).
- This does not scrape LinkedIn or any login-walled site. That's intentional — it keeps the actor legally and technically simple, and avoids account-ban risk entirely.
What I tested before handing this to you, and what I could NOT fully test
I ran this in a sandboxed environment with restricted outbound networking (only a fixed domain allowlist), so I was able to fully verify:
- ✅ All JSON config files parse correctly (
actor.json,input_schema.json,dataset_schema.json,package.json) - ✅
npm installcompletes cleanly with no errors - ✅ Email pattern generation logic (unit tested directly)
- ✅ Confidence scoring logic (unit tested directly)
- ✅ MX/DNS lookups against a real domain (
apify.com— returned real Google MX records) - ✅ Page extraction (emails + people) against sample HTML, including correctly rejecting an image filename like
logo@2x.png - ✅ Full end-to-end run via
npm startagainst a real live website (github.com), producing clean, correctly-shaped output rows with sensible fallback behavior
What I could not fully verify from my sandbox:
- ⚠️ SMTP probing (
smtpProbe.js) against a real mail server. My sandbox's network blocks outbound port 25 entirely (confirmed directly — connections toaspmx.l.google.com:25silently time out with no error, even via rawcurl). The code handles this failure gracefully and returns"unknown"rather than crashing, which I confirmed. But I could not confirm it returns"accepted"/"rejected"correctly against a live mail server, because my network can't reach port 25 at all.
When you run this on real Apify infrastructure, please specifically check:
- Run with
verifyEmails: trueagainst a domain where you know a real email exists, and confirmsmtpCheckreturns"accepted"(not always"unknown"). - Run against a domain you know does NOT have a particular address, and confirm
smtpCheckreturns"rejected"rather than always defaulting to"unknown". - If
smtpCheckis always"unknown"no matter what, that means Apify's network also restricts outbound port 25 for your account/plan — in that case, tell me and I'll adjust the actor to make SMTP verification optional-with-a-clear-warning rather than a default-on feature.
Local testing
npm install# Edit storage/key_value_stores/default/INPUT.json with your test input (see input_schema.json for shape)APIFY_LOCAL_STORAGE_DIR=./storage npm start# Check storage/datasets/default/*.json for output
Deploying to Apify
npm install -g apify-cliapify loginapify push
Then open the actor in the Apify Console, set your input, click Start, and check the Output tab.
Pricing suggestion
Set this up as Pay Per Event (PPE) with an event like email-found (charged only when email is non-null and source is not "none"). This way users only pay for results, which builds trust faster than charging per page crawled.