# Email Finder API - Find Work Email by Name and Domain (`pnda/email-finder`) Actor

No API key required. Email lookup by name + company domain (or company name): find anyone's work email, verified live over SMTP. Hunter alternative: pay only for verified emails, $4.99/1,000. Catch-all guesses free.

- **URL**: https://apify.com/pnda/email-finder.md
- **Developed by:** [PNDA](https://apify.com/pnda) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.99 / 1,000 verified 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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

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

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## 📧 Email Finder: Find Verified Work Emails by Name and Domain

Give a **first name, last name and company domain**. Get back the person's **work email, verified live over SMTP**. You need **no API key**, no Hunter, Snov or Apollo subscription and no credits to buy. You pay **$4.99 per 1,000 emails found**, and only for addresses that were actually verified.

It is a **Hunter alternative** that runs on Apify. Paste a list, click **Run**, and export a cold-email-ready CSV. You can also call it as an **email finder API** from n8n, Make, Zapier, Clay or your own code.

- 🔑 **No API key.** Everything runs inside the Actor. You don't need an account with any other email lookup service.
- ✅ **Verified, not guessed.** Each candidate address is checked against the company's mail server (MX lookup, then SMTP `RCPT TO`). The search stops at the first deliverable mailbox.
- 💸 **You pay only for verified emails.** Not found, unknown and **catch-all** results are **never charged**. There is no start fee.
- 🧠 **Smart patterns.** It tests `first.last`, `first`, `flast`, `firstlast`, `f.last`, `first_last` and more, in order of real-world frequency. It handles accents, compound names and particles (`van der`, `de`).
- 🏢 **No domain? Give the company name.** The Actor deduces the domain (`Acme Labs` → `acmelabs.com`) and keeps it only if it actually receives email.
- 🎁 **Try it free.** On the free Apify plan, the first 10 persons of every run are looked up at no cost.

***

### 💡 Who is it for?

- **Sales and SDR teams** who need to turn a lead list (name + company) into verified work emails before a cold email campaign.
- **Recruiters** who want to reach candidates directly at their work email.
- **Founders and marketers** doing partnership, PR, podcast or investor outreach.
- **RevOps and CRM owners** filling in a missing email column in bulk.
- **Clay, n8n, Make and Zapier users** who need an email lookup step without paying for another seat.
- **Developers** who want a pay-as-you-go email finder API without a monthly plan.

***

### 🧰 Use cases

- **Find an email by name and domain.** `Rand Fishkin` + `sparktoro.com` returns `rand@sparktoro.com`, verified.
- **Bulk email lookup.** Upload thousands of contacts exported from LinkedIn Sales Navigator, a conference attendee list or a CRM.
- **Enrich scraped leads.** Chain it after a Google Maps, LinkedIn or company website scraper to add the decision maker's work email.
- **Clean a list before sending.** Rows marked `catch-all` or `unknown` tell you which addresses are risky, so you can protect your sender reputation.
- **Find the company email pattern.** The `pattern` field (`first.last`, `flast`…) shows you how a company formats its addresses.

***

### ⚙️ How it works

1. **Normalize.** For each person, the name is normalized: accents are removed and titles like `Dr.` are dropped. The domain is cleaned too: `https://www.acme.com/about` becomes `acme.com`.
2. **Build candidates.** Up to 12 candidate addresses are built, from the most common corporate pattern to the least common.
3. **Verify.** Candidates are verified one by one over SMTP. The first **deliverable** address is returned with `status: "found"` and `confidence: "verified"`.
4. **Catch-all domains.** Some domains accept any address, which is common on Google Workspace, so no mailbox can be proven. For these, the most likely pattern is returned with `status: "catch-all"`, **free of charge**. The domain is remembered for the rest of the run, so other people at the same company cost no extra check.

No email is ever sent. The SMTP conversation stops before any message is delivered.

***

### 📥 Input

| Field | Type | Required | Description |
|---|---|---|---|
| `persons` | array | ✅ | One object per person: `{ "firstName", "lastName", "domain" }` or `{ "fullName", "companyDomain" }`. Use `companyName` when you don't know the domain. |
| `maxPatternsPerPerson` | integer | | How many patterns are tested per person, from 1 to 16 (default 12). |
| `concurrency` | integer | | How many persons are looked up in parallel, from 1 to 10 (default 5). |

#### Example input

```json
{
  "persons": [
    { "firstName": "Rand", "lastName": "Fishkin", "domain": "sparktoro.com" },
    { "fullName": "Sahil Lavingia", "companyDomain": "https://gumroad.com" },
    { "firstName": "Jane", "lastName": "Doe", "companyName": "Acme Labs" }
  ]
}
```

URLs and email addresses are accepted as domains, for example `https://www.acme.com/team` or `someone@acme.com`.

***

### 📤 Output

You get one row per input person.

```json
{
  "input": { "firstName": "Rand", "lastName": "Fishkin", "domain": "sparktoro.com" },
  "firstName": "rand",
  "lastName": "fishkin",
  "domain": "sparktoro.com",
  "domainSource": "input",
  "email": "rand@sparktoro.com",
  "status": "found",
  "confidence": "verified",
  "pattern": "first",
  "mxHost": "aspmx.l.google.com",
  "checkedEmails": 2,
  "charged": true
}
```

Here is a row for a catch-all domain:

```json
{
  "domain": "acme.com",
  "email": "jane.doe@acme.com",
  "status": "catch-all",
  "confidence": "catch-all",
  "pattern": "first.last",
  "charged": false
}
```

| `status` | Meaning | Charged? |
|---|---|---|
| `found` | The mailbox was verified over SMTP. | ✅ |
| `catch-all` | The domain accepts every address. You get the best guess, unverified. | ❌ free |
| `not-found` | The mail server rejected every tested pattern. | ❌ |
| `unknown` | The mail server gave no clear answer (greylisting, anti-spam). | ❌ |
| `no-mx` | The domain does not receive email. | ❌ |
| `invalid-input` | The first name or the domain is missing. | ❌ |

A `SUMMARY` record in the key-value store gives the totals by status. You can export the dataset to **CSV, Excel or JSON**, or read it through the API.

***

### 💰 Pricing

The Actor uses **pay per event**, with one event and no start fee:

| Event | What triggers it | Price |
|---|---|---|
| `email-found` | 1 **verified** email found | **$4.99 / 1,000** ($0.00499 each) |

Catch-all guesses, not found, unknown and invalid rows are **free**.

| Example run | Persons | Verified emails | Cost |
|---|---|---|---|
| Quick test | 10 | 4 | ~$0.02 |
| Lead list | 1,000 | 400 | ~$2.00 |
| Big list | 10,000 | 4,000 | ~$19.96 |

- **Free Apify plan:** the first **10 persons of each run** are looked up for free, and nothing is charged. Upgrade to a paid plan to process full lists.
- **Spending cap:** set **Maximum cost per run** in the run options. The Actor never starts a lookup that your limit could not pay for. The persons it skips are counted as `skippedForBudget` in `SUMMARY`.

***

### 🥊 Email finder comparison

The table below compares public prices for finding a work email from a name and a domain, as of October 2026.

| Tool | What you pay for | Price per 1,000 | API key or subscription |
|---|---|---|---|
| **This Actor** | **Verified emails only** | **$4.99** | **None** |
| Hunter.io | Credits (monthly plan) | ~€24.50 (€49 for 2,000) | Subscription |
| Findymail / Prospeo | Credits (monthly plan) | ~$20–25 | Subscription |
| Icypeas | Credits | ~$10–19 | Subscription |
| clearpath/email-finder-api | Every **pattern tested**, plus a start fee | $8 per pattern (several patterns per person) | None |
| automation-lab/email-finder | Every **person searched**, found or not | $5 + start fee | None |
| memo23/email-finder | Email found, plus a start fee | $20 | None |

You only pay when a mailbox is proven to exist. Misses and catch-all guesses cost nothing.

***

### 🔌 Use it as an email finder API

```bash
curl -X POST "https://api.apify.com/v2/acts/pnda~email-finder/run-sync-get-dataset-items" \
  -H "Authorization: Bearer <APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"persons":[{"firstName":"Rand","lastName":"Fishkin","domain":"sparktoro.com"}]}'
```

You can also use the Apify JavaScript and Python clients, the n8n, Make and Zapier integrations, or an HTTP column in Clay.

***

### ❓ FAQ

**Do I need an API key from Hunter, Snov or another provider?**
No. Everything runs inside the Actor. You only need an Apify account.

**How accurate is it?**
An email with status `found` passed a live SMTP check: the company's mail server confirmed that the mailbox exists. On domains that are not catch-all, most lookups end with a verified address.

**What is a catch-all domain?**
It is a mail server that accepts every address, so no mailbox can be proven. You get the most likely pattern for free, flagged `confidence: "catch-all"`. Verify it with your own tools before you send to it.

**Why was an email not found?**
The person may use a nickname or an unusual pattern, or may have left the company. The server may also block verification, which gives `unknown`. You are not charged in any of these cases.

**Does it send any email?**
No. The check stops before any message is sent.

**Can I use it on the free Apify plan?**
Yes. The first 10 persons of each run are free. For larger lists, use a paid Apify plan ([pricing](https://apify.com/pricing)).

**Can I find an email from a LinkedIn profile?**
Yes, if you pass the person's name and the domain of their current company. Chain this Actor after a LinkedIn or company scraper.

**Is it legal?**
It checks professional addresses built from public information. You are responsible for using the results in compliance with the GDPR, CAN-SPAM, the CCPA and any other law that applies to you. That includes having a legitimate interest before you contact anyone.

***

### 🧩 More tools from PNDA

| Actor | What it does |
|---|---|
| 🔍 [Semrush Keyword Scraper](https://apify.com/pnda/semrush-keyword) | Keyword volume, CPC, difficulty and intent, plus domain overview, competitors and backlinks. No Semrush login. |

***

### ▶️ Start now

Paste your names and company domains, click **Run**, and export your verified emails. You pay only for what is found.

# Actor input Schema

## `persons` (type: `array`):

List of people to find. Each item: {"firstName", "lastName", "domain"} or {"fullName", "companyDomain"}. "companyName" is accepted when no domain is known (the domain is then guessed).

## `maxPatternsPerPerson` (type: `integer`):

How many address patterns (first.last, first, flast...) are tested per person, in order of probability.

## `concurrency` (type: `integer`):

How many persons are looked up in parallel.

## `diagnosePort25` (type: `boolean`):

Debug: logs whether this container can open an SMTP connection on port 25.

## Actor input object example

```json
{
  "persons": [
    {
      "firstName": "Patrick",
      "lastName": "Collison",
      "domain": "stripe.com"
    }
  ],
  "maxPatternsPerPerson": 12,
  "concurrency": 5,
  "diagnosePort25": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

All lookups (JSON, CSV, Excel).

# 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 = {
    "persons": [
        {
            "firstName": "Patrick",
            "lastName": "Collison",
            "domain": "stripe.com"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pnda/email-finder").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 = { "persons": [{
            "firstName": "Patrick",
            "lastName": "Collison",
            "domain": "stripe.com",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("pnda/email-finder").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 '{
  "persons": [
    {
      "firstName": "Patrick",
      "lastName": "Collison",
      "domain": "stripe.com"
    }
  ]
}' |
apify call pnda/email-finder --silent --output-dataset

```

## MCP server setup

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

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/ESMZY2I5ruLO0NZ0U/builds/prhXdhukdNtsPvZsQ/openapi.json
