# Public B2B Email Finder & MX Verifier (`fetch_cat/email-finder-api-scraper`) Actor

Find person-bound business emails visibly published on company websites and verify syntax and public MX routing.

- **URL**: https://apify.com/fetch\_cat/email-finder-api-scraper.md
- **Developed by:** [Hanna Nosova](https://apify.com/fetch_cat) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.07 / 1,000 item processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## B2B Email Finder & Public MX Verifier

Find business emails only when a company has visibly published an address beside the requested person's name on its own public website. Every result preserves the public evidence page and checks syntax plus public DNS MX routing.

This is an evidence-first alternative to guessed address patterns. It is designed for B2B research where a buyer needs to review the source before contacting anyone.

### Who is it for

- Sales and partnership researchers checking published business contacts.
- Compliance teams that require a source URL and name context.
- Agencies enriching a known list of people and company domains.
- AI agents that need a conservative, auditable public-contact lookup.

### What you get

For each requested person and company domain, the Actor returns one outcome row. A found email must be publicly visible on that company domain in bounded context with the requested full name.

- Public source URL and short evidence snippets.
- Normalized email and conservative role/disposable classification.
- Syntax validation and public MX routing result.
- Explicit `NOT_FOUND` or `BLOCKED_OR_UNAVAILABLE` outcomes instead of generated alternatives.

### Input recipe

Use a small, specific batch first. Domains must be company website domains, without paths.

```json
{
  "people": [
    {
      "firstName": "Jane",
      "lastName": "Smith",
      "domain": "company.com"
    }
  ],
  "maxPagesPerDomain": 4
}
```

### Input settings

| Input | Type | Default | Description |
| --- | --- | ---: | --- |
| `people` | array | required | One to 100 person and company-domain targets. Duplicate targets are merged. |
| `people[].firstName` | string | required | Requested person's first name. |
| `people[].lastName` | string | required | Requested person's last name. |
| `people[].domain` | string | required | Company website domain, without a path. |
| `maxPagesPerDomain` | integer | 8 | One to 20 root, team, leadership, contact, and sitemap-discovered pages to inspect. |

### Output example

```json
{
  "firstName": "Jane",
  "lastName": "Smith",
  "fullName": "Jane Smith",
  "companyDomain": "company.com",
  "email": "jane.smith@company.com",
  "normalizedEmail": "jane.smith@company.com",
  "status": "PUBLIC_EVIDENCE_MX_READY",
  "emailSourceUrl": "https://company.com/team",
  "emailEvidence": "Contact Jane Smith at jane.smith@company.com",
  "identityEvidence": "Jane Smith, Partnerships",
  "validSyntax": true,
  "mxFound": true,
  "mxRecords": ["mail.company.com"],
  "isDisposable": false,
  "isRoleAccount": false,
  "verificationScope": "Public syntax and DNS MX routing only; no SMTP mailbox probe.",
  "checkedAt": "2026-08-29T00:00:00.000Z"
}
```

### Output fields

| Field | Meaning |
| --- | --- |
| `firstName`, `lastName`, `fullName` | Requested and normalized person context. |
| `companyDomain` | Requested company website domain. |
| `email`, `normalizedEmail` | Public person-bound email, or `null` when none was found. |
| `status` | `PUBLIC_EVIDENCE_MX_READY`, `PUBLIC_EVIDENCE_NO_MX`, `NOT_FOUND`, or `BLOCKED_OR_UNAVAILABLE`. |
| `emailSourceUrl` | Company page that visibly published the matching email. |
| `emailEvidence`, `identityEvidence` | Short same-page public context for the address and requested name. |
| `validSyntax` | Whether the returned value has valid email syntax. |
| `mxFound`, `mxRecords` | Public DNS mail-routing result; this is not mailbox deliverability. |
| `isDisposable`, `isRoleAccount` | Conservative local classifications of a returned address. |
| `verificationScope` | Boundaries of this verification result. |
| `checkedAt` | ISO timestamp for the lookup. |

### Pricing

The Actor charges a small one-time **Start** event per run and an **Item processed** event for each dataset row produced. The per-item price has volume discounts by Apify plan; see the [live Pricing tab](https://apify.com/fetch_cat/email-finder-api-scraper/pricing) for current rates. A row is produced for every requested target, including an explicit no-result outcome.

### Input recipes

#### Check a single public contact

Use the input recipe above with `maxPagesPerDomain: 4` for a quick evidence-first lookup.

#### Enrich a research batch

Provide multiple people from known company domains. Start with four pages per domain, then increase the page limit only where the company uses a large public team directory.

```json
{
  "people": [
    {"firstName":"Jane","lastName":"Smith","domain":"company.com"},
    {"firstName":"Alex","lastName":"Lee","domain":"example.org"}
  ],
  "maxPagesPerDomain": 8
}
```

### API usage

#### Node.js

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('fetch_cat/email-finder-api-scraper').call({
  people: [{ firstName: 'Jane', lastName: 'Smith', domain: 'company.com' }],
  maxPagesPerDomain: 4,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("fetch_cat/email-finder-api-scraper").call(run_input={
    "people": [{"firstName": "Jane", "lastName": "Smith", "domain": "company.com"}],
    "maxPagesPerDomain": 4,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/fetch_cat~email-finder-api-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"people":[{"firstName":"Jane","lastName":"Smith","domain":"company.com"}],"maxPagesPerDomain":4}'
```

### MCP and AI agents

Add Apify MCP to Claude Code, then ask for source-cited public contact research.

```bash
claude mcp add apify -- npx -y @apify/mcp-server
```

```json
{
  "mcpServers": {
    "apify": {
      "command": "npx",
      "args": ["-y", "@apify/mcp-server"],
      "env": {"APIFY_TOKEN": "YOUR_APIFY_TOKEN"}
    }
  }
}
```

Example prompt: “Run `fetch_cat/email-finder-api-scraper` for Jane Smith at company.com and return only rows with source URLs and MX status.”

Use the hosted MCP tool catalog at [Apify MCP](https://mcp.apify.com?tools=fetch_cat/email-finder-api-scraper) when your client supports it.

### Tips

- Use the legal company domain, not a social profile or a URL path.
- Keep names specific; initials reduce reliable same-page identity matching.
- Begin with four pages per domain to control run scope.
- Filter exports by `status` and retain `emailSourceUrl` for review.

### Limits and responsible use

The Actor checks only public company-web content. It does not generate email patterns, use people databases, sign in, bypass access controls, or test SMTP recipients. MX routing indicates that a domain advertises mail routing; it does not prove a mailbox exists, accepts mail, or grants permission to contact a person.

Respect applicable privacy, marketing, and data-protection obligations before using any contact data.

### FAQ

#### Why is `email` empty?

The inspected public pages did not visibly contain both the requested full name and a same-domain email in the required bounded context.

#### Does MX verification mean an address is deliverable?

No. It only checks public DNS mail-routing records for the email domain. It does not perform SMTP recipient verification.

#### Why did I receive `BLOCKED_OR_UNAVAILABLE`?

The company site could not be inspected reliably within the configured scope. Keep the source URL/status in your workflow and retry later if appropriate.

#### Can I use a larger batch?

Yes, up to 100 targets. Start with a smaller representative batch so you can review source evidence and output statuses first.

### Related Actors

- [Decision Maker Email Finder](https://apify.com/fetch_cat/decision-maker-email-finder) for public company-site contact discovery.
- [Website Contact Finder](https://apify.com/fetch_cat/website-contact-finder) for domain-level public contact extraction.
- [Company Website Scraper](https://apify.com/fetch_cat/website-content-crawler) for source-page collection.
- [Email MX Deliverability Checker](https://apify.com/fetch_cat/email-mx-deliverability) for domain routing checks.
- [Sitemap URL Extractor](https://apify.com/fetch_cat/sitemap-url-extractor) for public site URL discovery.

### Support

For help, include the target domain, returned `status`, and `emailSourceUrl` when present. Do not send credentials or private contact lists in a support request.

# Actor input Schema

## `people` (type: `array`):

One or more person targets. The actor never guesses addresses.

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

Maximum root, team, leadership, contact, and sitemap-discovered company pages to inspect.

## Actor input object example

```json
{
  "people": [
    {
      "firstName": "John",
      "lastName": "Doe",
      "domain": "example.com"
    }
  ],
  "maxPagesPerDomain": 4
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# 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 = {
    "people": [
        {
            "firstName": "John",
            "lastName": "Doe",
            "domain": "example.com"
        }
    ],
    "maxPagesPerDomain": 4
};

// Run the Actor and wait for it to finish
const run = await client.actor("fetch_cat/email-finder-api-scraper").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 = {
    "people": [{
            "firstName": "John",
            "lastName": "Doe",
            "domain": "example.com",
        }],
    "maxPagesPerDomain": 4,
}

# Run the Actor and wait for it to finish
run = client.actor("fetch_cat/email-finder-api-scraper").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 '{
  "people": [
    {
      "firstName": "John",
      "lastName": "Doe",
      "domain": "example.com"
    }
  ],
  "maxPagesPerDomain": 4
}' |
apify call fetch_cat/email-finder-api-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fetch_cat/email-finder-api-scraper"
        }
    }
}

```

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/keOfNQ5mdqCRY1PGu/builds/aK9i5lkfX66gyCgDr/openapi.json
