# Email Finder by Name & Domain - Verified Work Emails (`sandy_yclept/work-email-finder`) Actor

Email finder by name and domain: a person's verified work email from their first name, last name and company domain. Published on the company's website or confirmed by its mail server - never a guess. Bulk email lookup for lead lists and CRMs. Pay only per email found.

- **URL**: https://apify.com/sandy_yclept/work-email-finder.md
- **Developed by:** [Rafal Sav](https://apify.com/sandy_yclept) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 4 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 verified work emails

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?

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

### What does Email Finder by Name & Domain do?

**Email Finder by Name & Domain** takes a list of **people — first name, last name and the company's domain** — and returns each person's **work email**: the address the company **publishes on its own website**, or the one the company's **mail server confirms** exists. An address is **never guessed**: when the mail server accepts every address, or does not answer, the row says so, shows the likeliest address as unverified, and costs nothing.

Give it a CSV, a JSON list or the dataset of another Actor — a LinkedIn, Google Maps or decision-maker scrape — and get back a verified email per person, with where it came from.

You **pay only per email found**. It runs on the [Apify platform](https://apify.com): API access, scheduling, integrations (Make, Zapier, n8n, Google Sheets) and run monitoring included.

### Why use it?

- **Verified or free.** An email in the `email` column is either printed on the company's website (`published`) or exists according to the company's own mail server (`confirmed`). Nothing else goes into that column, and nothing else is charged.
- **The company's own pattern first.** Each company's website is read before its mail server is asked. An address it prints costs no check, and the pattern its other addresses follow — `j.doe@`, `doe@`, `jane.doe@` — makes the first question the right one in **30 of 32** cases in our test. Finders that try only the four American patterns miss every German `nachname@` and `v.nachname@` company.
- **A catch-all server fools nobody.** One company in six accepts every address. Each domain is first asked for a mailbox that cannot exist, and only a server that refuses it is believed. Tools that skip this sold the wrong `first.last@` as "found" for 14 of 15 such people in our test.
- **German names the German way.** `Müller` is `mueller@` in a German mailbox, not `muller@`. On October 4, 2026 we asked German mail servers about 18 people with an umlaut in their name, in both spellings: 6 had a mailbox only as `ae`/`oe`/`ue`, none only with the mark dropped. On `.de`, `.at` and `.ch` domains that is the spelling asked for.
- **A mailbox two people could own is nobody's.** `apelt@` of a clinic with two Apelts, `daniel@` of a company with two Daniels, is not assigned to either.
- **Every row says where the address came from**: the page that prints it, or `mail server of <domain>` — and how many addresses were checked to get it.
- **Cheap to run.** About 2.5 mail-server checks per person, at $0.00089 each, plus the price per email found.

### Use cases

- **Lead lists** — names and companies from an event, a directory or a scrape, turned into addresses you can write to.
- **CRM enrichment** — the contacts you already have, with their current work email.
- **After a LinkedIn or decision-maker scrape** — feed the dataset in; the names come back with emails.
- **Email patterns** — `company_pattern` and `pattern_source` tell you how each company spells its mailboxes, with the evidence.

### How to use it

1. Paste your **People** as JSON objects — `{"firstName": "Jane", "lastName": "Doe", "domain": "acme.com"}` — or plain lines like `Jane Doe, acme.com`. Field names from common exports are recognized (`first_name`, `surname`, `name`, `website`, `url` …). Or give the **dataset ID** of another Actor's run.
2. Leave **Confirm unpublished emails** on to have the mail servers asked, or turn it off to get only the emails the websites publish.
3. Leave **Read the company websites first** on: it is where the published addresses and the company's pattern come from.
4. Click **Start**. Download the results as JSON, CSV, Excel or HTML.

### Input

| Field | What it does |
|---|---|
| People to find emails for | One object per person: a first name, a last name and the company's domain or website. Also accepted: a `name` with the whole name, `surname`, `website`/`url` instead of `domain`, plain strings `"Jane Doe, acme.com"`. Titles before a name (Dr., Herr) and letters after it (MD, CPA) are dropped. |
| Or a dataset of people | The ID of an Apify dataset whose items carry a name and a company domain — read after the people listed above. |
| Confirm unpublished emails | Ask the company's mail server which of a person's usual mailboxes exists (default on). Runs [bounceverify's email verifier](https://apify.com/bounceverify/bounceverify-email-verifier) in a separate run on your account, which bills $0.00089 per address checked. |
| Read the company websites first | Read each company's website for published addresses and its email pattern before asking its mail server (default on). |
| Max contact and about subpages | How many contact-like pages to read per website (default 5). Up to 4 team pages and 8 pages of single people are read on top. |
| Proxy configuration, Retry refused sites | As in our other Actors: websites that refuse a cloud address are retried through Apify Proxy. |

### Output

One row per person. The values below are invented:

```json
{
  "first_name": "Jane",
  "last_name": "Doe",
  "name": "Jane Doe",
  "domain": "acme.com",
  "email": "j.doe@acme.com",
  "email_status": "confirmed",
  "email_source": "mail server of acme.com",
  "likely_email": null,
  "company_pattern": "f.last",
  "pattern_source": "r.roe@acme.com",
  "checks": 1,
  "website": "https://www.acme.com/",
  "website_status": "ok",
  "company": "Acme GmbH",
  "company_email": "info@acme.com",
  "company_phones": ["+493012345678"],
  "note": "The company's mail server confirmed this mailbox exists.",
  "billed": true
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

| Field | Meaning |
|---|---|
| `first_name`, `last_name`, `name`, `domain` | The person as given, the name without titles and letters, the company's registered domain. |
| `email` | The person's work email: published or confirmed. `null` otherwise. |
| `email_status` | `published` — printed on the company's website. `confirmed` — the company's mail server says the mailbox exists. `catch_all` — the server accepts every address, so none can be confirmed. `unanswered` — the server did not answer, twice. `not_found` — none of the usual mailboxes of this name exists. `not_checked` — confirmation is off. `no_mail` — the domain accepts no mail. `invalid` — the row had no name or no company domain. |
| `email_source` | The page that prints the email, `the website` when it was found elsewhere on the site, or `mail server of <domain>`. |
| `likely_email` | For a person without an email: the address the company's pattern — else the commonest one — would give them. **Unverified**; a catch-all server may or may not deliver it. |
| `company_pattern`, `pattern_source` | How the company spells its people's mailboxes (`first`, `first.last`, `last`, `f.last`, `flast`, `firstlast` …), and one published address as the evidence. |
| `checks` | How many addresses the mail server was asked about for this person. |
| `website`, `website_status` | The company website as read, and whether it answered. |
| `company`, `company_email`, `company_phones` | The company's name from its legal notice, its general inbox and phone numbers — in every row, free. |
| `note` | One sentence on what the status means. |
| `billed` | Whether this row was charged. |

### Accuracy

On **October 2, 2026** we took **64 people at 35 companies** — local businesses in Ireland, the UK and Australia, US startups, German firms — whose work address was known: 41 printed on the company's own website, 23 confirmed by the company's mail server a week earlier. Then we asked for each of them by **name and domain only**, with the website reading turned off, and ran the two most used email finders on Apify Store on the same 64 people.

| 64 people, name and domain only | this Actor | the pattern-and-SMTP finder with 299 users | the $0.001 finder with 169 users |
|---|---|---|---|
| Right address returned | **45** | 26 | 0 — no result in 33 minutes (its CAPTCHA solver failed) |
| … of the 41 printed on the websites | **22** | 10 | — |
| Wrong address sold as found | **0** | **14** — `first.last@` guessed on catch-all domains | — |
| Catch-all domain, said so, free | 15 | 0 | — |
| Not found | 1 | 21 | — |
| Mail-server checks | 161 for $0.14 | $0.81 | — |
| **Cost per right address** | **$0.003 + the price per email** | $0.031 | — |

Where the difference comes from: German companies spell their mailboxes `nachname@` and `v.nachname@`; the other finder tries the four common American patterns and found none of them. And on the six catch-all domains it returned a first guess as "found" for all 15 people — 14 of them not the address the company prints.

With the websites read first, as the Actor runs by default, the 41 printed addresses are found without a single check, and the company's pattern makes the first question right in 30 of 32 cases: about one to two checks per person.

### How much does it cost?

- **Verified work email — $0.005** ($5 per 1,000), charged for each person with a **published or confirmed** email. Once per address in a run.
- **Free:** a person whose address was not found, whose company's mail server accepts every address or did not answer, an invalid row, the likeliest address beside each of them, the company's pattern, inbox and phones.
- **Confirming emails** is done by [bounceverify's email verifier](https://apify.com/bounceverify/bounceverify-email-verifier) in a separate run on your account: **$0.00089 per address checked**. In the test above 161 addresses were checked for $0.14 for 64 people: about 2.5 checks, or $0.002, per person — one to two with the websites read first.

1,000 people, all found, cost about **$5 plus $2 of checks plus the platform usage** of reading 1,000 websites (about 0.3 compute units).

### Tips

- **Give the domain the company uses for mail.** It is usually its website's; a company that moved to another domain is followed there when the website is read.
- **Columns from any export work**: `firstName`/`lastName`, `first_name`/`last_name`, `name`, `surname`, `domain`, `website`, `url`.
- **One name twice for one domain** is asked once.
- **A `catch_all` row** means the company's server will accept `likely_email` whether or not the mailbox exists — write to it at your own risk, or ask the company's inbox in `company_email`.
- **Mail servers are asked in batches** of up to 40 companies, after their websites are read: rows appear batch by batch.

### FAQ

#### Where do the emails come from?

From two places only: the company's own website, read at the moment of the run (team pages, legal notice, contact pages, the pages of single people), and the company's own mail server, asked whether a mailbox exists. No database, no LinkedIn.

#### Why `confirmed` and not just "valid"?

Because a mail server that accepts every address — one in six — would call any address valid. Each domain is first asked about a mailbox that cannot exist. A server that accepts it is not believed about anything else, and its people come back as `catch_all`, free, with the likeliest address beside them.

#### Why does a person have no email?

The company does not print one, and its mail server either accepts every address, did not answer, or knows none of the usual mailboxes for the name — a nickname, a double first name (`marietherese@`), a middle initial. A busy server is asked once more; one that stays silent may answer on another day.

#### Can I feed it another Actor's output?

Yes: paste the dataset ID into **Or a dataset of people**. Items with any of the usual name and domain fields are read; LinkedIn scrapers' `fullName` and `companyWebsite`, Google Maps scrapers' `website`, our decision-maker finder's `first_name`, `last_name` and `domain` all work.

#### Is this legal?

The Actor reads public company websites, respecting `robots.txt`, and asks mail servers the question every mail client asks before delivery. A person's name and work email are personal data: under the GDPR you need a legal basis to process them and must inform the people concerned; in Germany §7 UWG requires prior consent for advertising emails in most cases, and other countries have rules of their own (CAN-SPAM, CASL, PECR). You are responsible for how you use the data.

### Related Actors

- [Decision Maker Email Finder](https://apify.com/sandy_yclept/decision-maker-email-finder) — the people who own or run each company on a list of websites, with their emails; feed its output here for the rest of the names.
- [Website Contact & Email Scraper](https://apify.com/sandy_yclept/website-contact-email-scraper) — emails, phone numbers and social profiles from any list of websites, priced per contact.
- [Google Maps Email Extractor](https://apify.com/sandy_yclept/google-maps-email-extractor) — local businesses from a Google Maps search, each with the email from its own website.
- [Shopify Store Leads & Emails](https://apify.com/sandy_yclept/shopify-store-leads) — Shopify stores by product keyword and country, with each store's email.
- [No Website Leads](https://apify.com/sandy_yclept/no-website-leads) — local businesses on Google Maps without a real website.
- [Impressum Email Scraper](https://apify.com/sandy_yclept/impressum-email-scraper) — German company websites: the company, its representatives and contacts from the Impressum.

### Disclaimer

This Actor is a **tool**. You are responsible for complying with the GDPR and local marketing law, the target sites' Terms of Service, and `robots.txt`. It does not build or sell contact databases.

### Support

Got an address that bounced, or a `not_found` for a person whose mailbox exists? Open an issue on the **Issues** tab with the name and domain — accuracy reports shape the roadmap directly.

# Actor input Schema

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

One object per person with a first name, a last name and the company's domain or website: {"firstName": "Jane", "lastName": "Doe", "domain": "acme.com"}. Also accepted: "name" or "full_name" with the whole name, "first_name" / "last_name" / "surname", "website" or "url" instead of "domain", and plain strings like "Jane Doe, acme.com". Titles before a name (Dr., Herr) and letters after it (MD, CPA) are dropped. A row without a name or a company domain, or with a mailbox provider's domain (gmail.com), is returned as invalid and costs nothing.

## `peopleDatasetId` (type: `string`):

The ID of an Apify dataset whose items carry a name and a company domain under any of the field names above - the output of a LinkedIn, Google Maps or decision-maker scraper, or a CSV you uploaded. Read in full, after the people listed above.

## `confirmEmails` (type: `boolean`):

For a person whose address the company does not print, the usual mailboxes of the name are asked of the company's mail server - the pattern the company's own published addresses follow first, then jane@, jane.doe@, doe@, j.doe@, jdoe@, janedoe@ - and the first that exists is returned as `confirmed`. A server that accepts every address proves nothing and is never believed: the row then says `catch_all` and costs nothing. The question goes through the bounceverify/bounceverify-email-verifier Actor in a separate run on your account, which bills each address it checks ($0.00089): in our test 161 checks, $0.14, for 64 people. Off: only emails published on the websites are returned, with the likeliest address unverified beside each other person.

## `readWebsites` (type: `boolean`):

On (default): each company's website is read before its mail server is asked - an address it prints costs no check, and the pattern its other addresses follow (i.doe@, doe@) makes the first question the right one in 94% of cases. Off: the mail server is asked straight away, in the common order; faster, more checks, no published addresses.

## `maxContactPages` (type: `integer`):

How many contact-like subpages (/about, /contact, /team, /impressum) to read on each company website, on top of its homepage, looking for published addresses. Up to 4 more team pages and 8 pages of single people are read on top of these, where the site has them.

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

Optional proxy for fetching pages. Apify Proxy's datacenter IPs are included in every Apify plan, the Free plan too; residential proxies are billed separately. Left disabled, the Actor connects directly, and retries sites that refuse it through Apify Proxy (see below).

## `proxyFallback` (type: `boolean`):

Every cloud run has a datacenter IP address, and some sites turn those away. A site that refuses or drops the direct connection is retried once through Apify Proxy's datacenter IPs (included in every Apify plan, the Free plan too), then once more directly. Sites that answer directly never go through the proxy, and robots.txt is respected either way. Has no effect when a proxy is configured above.

## Actor input object example

```json
{
  "people": [
    {
      "firstName": "Padraic",
      "lastName": "Ferry",
      "domain": "ferrysolicitors.com"
    },
    {
      "firstName": "Michael",
      "lastName": "Stoz",
      "domain": "partner-ag.de"
    },
    {
      "firstName": "Omri",
      "lastName": "Mor",
      "domain": "routable.com"
    }
  ],
  "confirmEmails": true,
  "readWebsites": true,
  "maxContactPages": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "proxyFallback": true
}
```

# Actor output Schema

## `results` (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": "Padraic",
            "lastName": "Ferry",
            "domain": "ferrysolicitors.com"
        },
        {
            "firstName": "Michael",
            "lastName": "Stoz",
            "domain": "partner-ag.de"
        },
        {
            "firstName": "Omri",
            "lastName": "Mor",
            "domain": "routable.com"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("sandy_yclept/work-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 = { "people": [
        {
            "firstName": "Padraic",
            "lastName": "Ferry",
            "domain": "ferrysolicitors.com",
        },
        {
            "firstName": "Michael",
            "lastName": "Stoz",
            "domain": "partner-ag.de",
        },
        {
            "firstName": "Omri",
            "lastName": "Mor",
            "domain": "routable.com",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("sandy_yclept/work-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 '{
  "people": [
    {
      "firstName": "Padraic",
      "lastName": "Ferry",
      "domain": "ferrysolicitors.com"
    },
    {
      "firstName": "Michael",
      "lastName": "Stoz",
      "domain": "partner-ag.de"
    },
    {
      "firstName": "Omri",
      "lastName": "Mor",
      "domain": "routable.com"
    }
  ]
}' |
apify call sandy_yclept/work-email-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sandy_yclept/work-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/IoV6AXAbg7br51Rgy/builds/p7tihmVZ8sIXh1aIj/openapi.json
