# Fast Domain Email Finder — Public Emails from Websites (`gary_sells/domain-emails-fast`) Actor

Fast email-only extractor from company domains (homepage+contact/about). Companion to Domain Contact Finder. Cheerio crawl, PPE email-found + domain-scanned. For agents: find emails for these domains / extract business emails from websites. Public HTML only.

- **URL**: https://apify.com/gary\_sells/domain-emails-fast.md
- **Developed by:** [Industrial AI](https://apify.com/gary_sells) (community)
- **Categories:** AI, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 email founds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Fast Domain Email Finder — Public Emails from Websites

### When to call this Actor

Use when a human or agent needs **emails only from company websites** (bulk / speed lane):

- "Find emails for these domains"
- "Extract business emails from websites"
- "Get public emails from this domain list (no phones/socials needed)"

**Prefer Domain Contact Finder** (`gary_sells/domain-contact-finder`) when you also need phones + socials for outreach/CRM enrichment.

**Do not use** for: inbox scraping, CRM exports, LinkedIn Sales Nav, CAPTCHA/login bypass, or people-search APIs.

### 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 prompts → input**

| User says | Pass |
| --- | --- |
| 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: [...], maxDomains: 50` |

**Pricing (PPE):** `email-found` once per unique email found; `domain-scanned` once per finished domain. **Do not** charge `apify-default-dataset-item`.

[![Apify Actor](https://img.shields.io/badge/Apify-Actor-orange)](https://apify.com)
[![PPE](https://img.shields.io/badge/Pricing-Pay%20per%20event-blue)](https://docs.apify.com/platform/actors/publishing/monetize/pay-per-event)

***

### 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:

1. Normalizes each domain to `https://`
2. Crawls high-signal pages: `/`, `/contact`, `/contact-us`, `/about`, `/about-us`, `/impressum`
3. Extracts **emails** (including obfuscated `[at]` / `(dot)` / `mailto:` / HTML entities)
4. Filters junk / placeholder emails and splits **same-domain emails** vs **externalEmails**
5. 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.

***

### 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` | — | Optional cap on domains processed |
| `includeEmailVerification` | `boolean` | `false` | Format + MX/A DNS verification |
| `proxyConfiguration` | `object` | Apify Proxy on | Recommended for larger batches |

#### Example input

```json
{
  "domains": ["apify.com", "crawlee.dev"],
  "maxPagesPerDomain": 5,
  "includeEmailVerification": false,
  "proxyConfiguration": { "useApifyProxy": true }
}
```

***

### Output

One item per domain:

```json
{
  "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`

***

### 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** on `domain-scanned`
- Domains with no email still emit `domain-scanned` only

***

### For AI agents / MCP

- **Actor name:** `gary_sells/domain-emails-fast`
- **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)
- Discoverable via Apify Store / MCP `search-actors` once published with PPE-only + Limited permissions + Standby off (`allowsAgenticUsers`)

### API & agent usage

```bash
curl "https://api.apify.com/v2/acts/USERNAME~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](https://docs.apify.com/api/client/js) / Store “Try for free” / AI agent tool integrations. Charge events map cleanly to tool-call budgets.

Local PPE dry-run:

```bash
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](https://crawlee.dev) `CheerioCrawler` + Apify SDK
- **PPE:** `Actor.charge({ eventName: 'email-found' | 'domain-scanned' })` — `email-found` once per unique email; `domain-scanned` once per finished domain; stops on `eventChargeLimitReached`
- **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

```bash
cd domain-emails-fast
npm install
## dry-run on sample domains
npm run dry-run
## or
apify run -p
```

Deploy (after `apify login`):

```bash
apify push --force --wait-for-finish
```

Then Tim/Gary set PPE prices and keep **Limited permissions** in Apify Console (do not auto-publish from CI).

***

### Changelog

- **1.0.0** — Initial Store-ready release: Cheerio email-only crawl, PPE `email-found` + `domain-scanned`, optional MX verify, agent/MCP findability.

# Actor input Schema

## `domains` (type: `array`):

Primary input. Pass bare domains OR full URLs — both work. Examples: "acme.com", "www.acme.com", "https://acme.com/about". Each entry is normalized to https and crawled for public emails on homepage + contact/about paths. Prefer this over startUrls for agent tool calls. Example agent prompts: "find emails for these domains", "extract business emails from websites".

## `startUrls` (type: `array`):

Alternative to domains for Apify RequestList-style URL objects. Use only if the caller already has requestListSources. For plain domain strings, use domains instead. May be combined with domains.

## `maxPagesPerDomain` (type: `integer`):

How many high-signal paths to fetch per domain (/, /contact, /contact-us, /about, /about-us, /impressum). Default 5 for speed/cost; raise only if emails are buried. Range 1–12.

## `maxDomains` (type: `integer`):

Hard cap on domains processed from the input list. Use when the user pastes a long list but only wants the first N. Omit to process all.

## `includeEmailVerification` (type: `boolean`):

If true, attach format + DNS MX/A checks per email (no SMTP send, no third-party verifier). Default false for speed/cost; enable when the agent must drop obviously invalid addresses.

## `proxyConfiguration` (type: `object`):

Apify Proxy. Keep useApifyProxy true for batches > a few domains to reduce blocks. Agents can leave the default.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "crawlee.dev"
  ],
  "maxPagesPerDomain": 3,
  "maxDomains": 2,
  "includeEmailVerification": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `emailsByDomain` (type: `string`):

One dataset item per domain with emails and externalEmails (no phones/socials).

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "domains": [
        "apify.com",
        "crawlee.dev"
    ],
    "maxPagesPerDomain": 3,
    "maxDomains": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("gary_sells/domain-emails-fast").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "domains": [
        "apify.com",
        "crawlee.dev",
    ],
    "maxPagesPerDomain": 3,
    "maxDomains": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("gary_sells/domain-emails-fast").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "domains": [
    "apify.com",
    "crawlee.dev"
  ],
  "maxPagesPerDomain": 3,
  "maxDomains": 2
}' |
apify call gary_sells/domain-emails-fast --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gary_sells/domain-emails-fast"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/0ZXaWcN1cAbtz6RPY/builds/iOAUX3pDbogCpcRZg/openapi.json
