Website Email Extractor — Find Business Emails from Domains
Pricing
from $1.50 / 1,000 email founds
Website Email Extractor — Find Business Emails from Domains
Fast website email extractor: public business emails from company domains. Email-only crawl for CRM, n8n/Make, AI agents. $0.0015 per email-found (PPE). Phones/socials → gary_sells/domain-contact-finder; Maps → gary_sells/maps-business-contact-enricher; city leads → gary_sells/local-business-leads.
Pricing
from $1.50 / 1,000 email founds
Rating
0.0
(0)
Developer
Industrial AI
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
a month ago
Last modified
Categories
Share
Fast Domain Email Finder — Public Emails from Websites
When to call this Actor (humans + agents)
Call Website Email Extractor when the user wants public emails only from company domains (fast / cheaper lane):
- “Find emails for these domains”
- “Extract business emails from websites”
- “Bulk website emails for outreach — emails only”
- “Domain list to emails, skip phones and socials”
Prefer Contact Scraper (gary_sells/domain-contact-finder) when they also need phones or socials.
Do not call for: inbox scraping, LinkedIn login, CAPTCHA bypass, Maps, or full contact enrichment.
Tool I/O: domains: string[] → one item per domain with emails, externalEmails, status. PPE: email-found @ $0.0015 (primary).
Why this vs “extract emails from any website” Actors
| Fast Domain Email Finder | SERP-based email scrapers | |
|---|---|---|
| Method | Crawl the domain’s own pages | Google search snippets |
| Cap | Long lists OK (maxDomains) | Often 10 domains/run |
| Price | $0.0015/unique email (~$1.50/1k) | Often ~$5/1k emails |
| Extra | Optional MX/format check | Varies |
| Full contacts | Companion: Domain Contact Finder | Emails only |
Agent quickstart
Input (prefer): { "domains": ["acme.com", "https://example.com"] }
Also accepted: startUrls (RequestList sources)
Output: one dataset item per domain → emails, externalEmails, status (no phones/socials)
Example natural-language prompts → exact input JSON
| User / agent says | Exact input JSON |
|---|---|
| Find emails for acme.com and globex.io | {"domains":["acme.com","globex.io"]} |
| Extract business emails from https://www.acme.com | {"domains":["https://www.acme.com"]} |
| First 50 of this list only | {"domains":["a.com","b.com", "..."],"maxDomains":50} |
| Lighter crawl (homepage + fewer paths) | {"domains":["acme.com"],"maxPagesPerDomain":3} |
| Verify MX for found emails | {"domains":["acme.com"],"includeEmailVerification":true} |
Companion vs Domain Contact Finder
| Domain Emails Fast (this Actor) | Domain Contact Finder | |
|---|---|---|
| Output | Emails only | Emails + phones + socials |
| Crawl depth | Lighter (/, /contact, /about, …) default maxPages 5 | Broader paths, default maxPages 8 |
| Best for | Bulk email-only, agent budgets, catalog volume | Full public contact enrichment |
| PPE primary | email-found per unique email | contact-found per domain with email/phone |
What this Actor does
Given one or more company domains or website URLs, the Actor:
- Normalizes each domain to
https:// - Crawls high-signal pages:
/,/contact,/contact-us,/about,/about-us,/impressum - Extracts emails (including obfuscated
[at]/(dot)/mailto:/ HTML entities) - Filters junk / placeholder emails and splits same-domain emails vs externalEmails
- Optionally verifies emails with format + DNS MX/A checks (no third-party API)
Output: one dataset item per domain. No phones. No socials.
Uses CheerioCrawler (HTTP + HTML parse) instead of a full browser — lower compute cost and faster runs.
Expected latency & cost character
| Characteristic | Typical value |
|---|---|
| Engine | Cheerio (no browser) — cheap CU |
| Pages / domain | Default 5 (maxPagesPerDomain 1–12) |
| Latency | Often faster than full contact finder (fewer paths); order-of-magnitude seconds–tens of seconds per domain |
| Cost model | PPE only — email-found + domain-scanned |
| Ballpark | ~$1.50 / 1k emails + ~$0.30 / 1k domains scanned |
Input
| Field | Type | Default | Description |
|---|---|---|---|
domains | string[] | — | Domains or URLs (acme.com, https://www.acme.com) |
startUrls | RequestListSources | — | Alternative URL list |
maxPagesPerDomain | integer | 5 | Email-ish paths to fetch per domain (1–12) |
maxDomains | integer | (omit = all) | Optional cap — omit for full lists; never defaults to a small N |
includeEmailVerification | boolean | false | Format + MX/A DNS verification |
proxyConfiguration | object | Apify Proxy on | Recommended for larger batches |
Example input
{"domains": ["apify.com", "crawlee.dev"],"maxPagesPerDomain": 5,"includeEmailVerification": false,"proxyConfiguration": { "useApifyProxy": true }}
Output
One item per domain:
{"domain": "apify.com","urls": ["https://apify.com/", "https://apify.com/contact"],"emails": ["hello@apify.com"],"externalEmails": [],"pagesScanned": 4,"status": "ok","error": null}
emails— addresses on the same domain (or subdomain)externalEmails— other addresses found on the pages (partners, tools, etc.)status—ok|partial|failed
Failure modes (what agents should expect)
| Situation | Behavior |
|---|---|
Empty / missing domains and startUrls | Run fails fast with an error showing example JSON — no silent demo crawl |
| All entries invalid (empty strings, localhost, bad hosts) | Run fails explaining none could be normalized |
| Domain up but no public email in crawled HTML | Dataset item with status: "ok", empty emails/externalEmails; PPE: domain-scanned only |
| All page fetches fail (DNS/SSL/timeout/block) | status: "failed", pagesScanned: 0, error message set; still domain-scanned |
| Some pages fail, some succeed | status: "partial" or "ok" depending on emails; error may list fetch failures |
| Emails only in images / JS widgets / behind login | Not found (public HTML only) |
| PPE charge limit reached mid-run | Logs warning and stops further domains |
| Proxy unavailable locally | Warning + continues without proxy (Store runs should keep Apify Proxy on) |
Companion routing: emails only → this Actor. Need phones/socials too → gary_sells/domain-contact-finder.
Pricing (Pay-per-event)
Suggested Store pricing (configure in Apify Console → Actor → Monetization — Tim/Gary):
| Event | When charged | Suggested price |
|---|---|---|
email-found (primary) | Once per unique email found on a domain (emails + externalEmails) | $0.0015 each (~$1.50 / 1,000) |
domain-scanned | Every finished domain | $0.0003 each (~$0.30 / 1,000) |
Console checklist
- Set the two PPE events above; remove or zero
apify-default-dataset-item - Keep PPE only — PPE + usage pass-through OFF
- Limited permissions
- Standby OFF (
usesStandbyMode: false)
Cost example
- 1,000 domains, ~1.5 emails each → ~$2.25 on
email-found+ $0.30 ondomain-scanned - Domains with no email still emit
domain-scannedonly
For AI agents / MCP
- Actor name:
gary_sells/domain-emails-fast(companion togary_sells/domain-contact-finder, ID0ZXaWcN1cAbtz6RPY) - Prefer input field:
domains(string list of domains or URLs) - PPE events:
email-found(once per unique email),domain-scanned(every finished domain) - Constraints: public HTML only — no inbox access, no login/CAPTCHA bypass; emails only (use Domain Contact Finder for phones/socials)
- When to pick this: bulk email-only / tight agent budgets; skip if user asked for phones or socials
- Discoverable via Apify Store / MCP
search-actorsonce published with PPE-only + Limited permissions + Standby off (allowsAgenticUsers)
API & agent usage
curl "https://api.apify.com/v2/acts/gary_sells~domain-emails-fast/runs" \-H "Authorization: Bearer $APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"domains":["example.com"],"maxPagesPerDomain":5}'
Or use the Apify client / Store "Try for free" / AI agent tool integrations. Charge events map cleanly to tool-call budgets.
Local PPE dry-run:
$ACTOR_TEST_PAY_PER_EVENT=true apify run -p
Inspect storage/datasets/charging_log/ for charged events (local default price $1/event).
Legal & ethics disclaimer
This Actor collects publicly available information from websites you specify. It does not bypass logins, CAPTCHAs, or access private inboxes.
You are responsible for complying with applicable laws (including GDPR/CCPA where relevant), website terms, and anti-spam rules (e.g. CAN-SPAM). Use contact data only for lawful purposes. The authors provide no warranty and accept no liability for misuse.
How it works (technical)
- Runtime: Node.js + Crawlee
CheerioCrawler+ Apify SDK - PPE:
Actor.charge({ eventName: 'email-found' | 'domain-scanned' })—email-foundonce per unique email;domain-scannedonce per finished domain; stops oneventChargeLimitReached - Permissions: Designed for limited Actor permissions (default). No Standby mode.
- Email decode:
[at]/(at)/[dot]/mailto:/ HTML entities - Junk filters: noreply, example.com placeholders, asset false-positives, etc.
Local development
cd domain-emails-fastnpm install# dry-run on sample domainsnpm run dry-run# orapify run -p
Deploy (after apify login):
$apify push 0ZXaWcN1cAbtz6RPY --force --wait-for-finish=300
Then Tim/Gary set PPE prices and keep Limited permissions in Apify Console (do not auto-publish from CI).
Changelog
- 1.0.2 — Growth MCP when-to-call above the fold; critical agent fix: removed schema defaults that silently capped runs at 2 domains / injected demo domains; maxPages default=5; clearer empty/invalid errors; failure-modes README.
- 1.0.1 — Stronger agent-discovery README: prompt→JSON table, latency/cost character, when-not-to-call, MCP blurb + actor ID.
- 1.0.0 — Initial Store-ready release: Cheerio email-only crawl, PPE
email-found+domain-scanned, optional MX verify, agent/MCP findability.