# B2B Email Finder & Live SMTP/MX Verifier (`haktelaren/b2b-email-finder-verifier`) Actor

Find and verify business email addresses using corporate domain patterns, MX DNS records, and real-time SMTP handshakes without sending actual emails. High-accuracy deliverability scoring.

- **URL**: https://apify.com/haktelaren/b2b-email-finder-verifier.md
- **Developed by:** [Celal Tokmak](https://apify.com/haktelaren) (community)
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 verified b2b email results

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

## B2B Email Finder & Live SMTP/MX Verifier 🎯✉️

Find and verify corporate business email addresses using permutation guessing, DNS MX records, and real-time socket-level SMTP handshakes — **without ever sending actual emails or risking spam complaints**.

Built for cold email agencies, B2B sales teams (SDRs/BDRs), lead generation specialists, and growth marketers who demand **99%+ deliverability** without paying $100+/mo for legacy SaaS tools like NeverBounce, ZeroBounce, or Hunter.

***

### 🌟 Key Features

- 🧠 **Corporate Pattern Permutations:** Generates standard B2B email permutations from first name, last name, and domain:
  - `{first}.{last}@{domain}` *(Gold standard for Enterprise B2B)*
  - `{first}{last}@{domain}`
  - `{first}@{domain}`
  - `{f}{last}@{domain}`
  - `{f}.{last}@{domain}`
  - `{first}_{last}@{domain}`
  - `{last}.{first}@{domain}`
- 🛡️ **Intelligent Catch-All Detection:** Detects domains configured with catch-all policies that accept every incoming address regardless of existence. Crucial for protecting your domain sender reputation from hidden bounces.
- ⚡ **Enterprise Verification Pipeline:** 3-stage verification process:
  1. **Syntax Validation:** RFC 5322 regex conformance.
  2. **DNS MX Priority & Provider Fingerprinting:** Resolves primary MX hosts and detects whether the infrastructure is **Microsoft 365**, **Google Workspace**, **Mimecast**, **Proofpoint**, **Zoho**, **Proton**, etc.
  3. **Live Socket SMTP Handshake:** Executes clean RFC `EHLO`, `MAIL FROM:<check@verifier.net>`, and `RCPT TO:<email>` on port 25. **Never sends DATA or message body**.
- 🔄 **Smart Permutation Preservation on Catch-All:** When a domain is detected as catch-all, the Actor provides the standard `{first}.{last}` email along with all generated `candidate_patterns` so you have complete visibility.
- 📦 **Single Prospect or Bulk Lists:** Verify single contacts or pass thousands of records in bulk arrays.

***

### 🛡️ Why Catch-All Detection is Critical for Cold Email

Many corporate mail servers (such as certain Google Workspace configurations or custom relays) return `250 OK` for *any* random recipient address.

If your email verifier blindly stops at the first `250 OK`:

- It may falsely mark an arbitrary pattern (like `celal@`) as valid.
- When you send cold emails, these messages either silently bounce later or trigger soft bounces, severely damaging your sender score and landing future emails in the spam folder.

**Our Intelligent Engine:**

1. Tests a cryptographically randomized probe address (`verify_{uuid}@{domain}`).
2. If the server accepts the probe, it flags the domain as **Catch-All**.
3. It sets the status to `RISKY (Catch-All - Mailbox cannot be uniquely distinguished)`.
4. It sets `best_guess_email` to the industry standard `{first}.{last}@{domain}` format and outputs all possible addresses in `candidate_patterns`.

***

### 🏢 Enterprise Verification Pipeline Architecture

```mermaid
graph TD
    A[Input: Name & Domain] --> B[Permutation Generator]
    B --> C[DNS MX Resolver & Provider Detection]
    C --> D{MX Records Found?}
    D -- No --> E[Status: MX_NOT_FOUND]
    D -- Yes --> F[Catch-All Probe on Port 25]
    F -- Probe Accepted 250 --> G[Flag: is_catch_all = true]
    F -- Probe Rejected 550 --> H[Flag: is_catch_all = false]
    G --> I[Status: RISKY Catch-All]
    I --> J[Output: best_guess {first}.{last} + candidate_patterns]
    H --> K[Sequential RCPT TO Tests]
    K -- 250 OK Found --> L[Status: VALID Verified Deliverable]
    K -- All 550 Rejected --> M[Status: NO_MATCH_FOUND]
```

***

### 📥 Input Parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `first_name` | `String` | `""` | Prospect first name (e.g. `Sam`). |
| `last_name` | `String` | `""` | Prospect last name (e.g. `Altman`). |
| `domain` | `String` | `""` | Target company website domain (e.g. `openai.com`). |
| `bulk_targets` | `Array<Object>` | `[]` | List of `{first_name, last_name, domain}` objects for bulk verification. |
| `deep_smtp_check` | `Boolean` | `true` | Connect to target MX servers to check mailbox existence via `RCPT TO`. |
| `timeout_seconds` | `Integer` | `10` | Socket timeout for DNS and SMTP checks in seconds. |
| `verifier_api_url` | `String` | `""` | *(Optional)* Custom SMTP Verifier API endpoint. If omitted, built-in enterprise infrastructure is used automatically. |
| `verifier_api_key` | `String` | `""` | *(Optional)* API key for custom verifier endpoint. |

***

### 📦 Output Dataset Schema Examples

#### Example 1: Direct Verified Deliverable (`VALID`)

```json
{
  "full_name": "Satya Nadella",
  "domain": "microsoft.com",
  "best_guess_email": "satya.nadella@microsoft.com",
  "status": "VALID (Verified Deliverable)",
  "mail_provider": "Microsoft 365",
  "is_catch_all": "false",
  "candidate_patterns": "satya.nadella@microsoft.com, satyanadella@microsoft.com, satya@microsoft.com, snadella@microsoft.com, s.nadella@microsoft.com, satya_nadella@microsoft.com, nadella.satya@microsoft.com",
  "tested_patterns": "satya.nadella@microsoft.com: VALID (250: Mailbox exists and accepts messages)",
  "timestamp": "2026-09-14T13:15:00.000Z"
}
```

#### Example 2: Catch-All Domain (`RISKY`)

```json
{
  "full_name": "Sam Altman",
  "domain": "openai.com",
  "best_guess_email": "sam.altman@openai.com",
  "status": "RISKY (Catch-All - Mailbox cannot be uniquely distinguished)",
  "mail_provider": "Google Workspace",
  "is_catch_all": "true",
  "candidate_patterns": "sam.altman@openai.com, samaltman@openai.com, sam@openai.com, saltman@openai.com, s.altman@openai.com, sam_altman@openai.com, altman.sam@openai.com",
  "tested_patterns": "verify_4cc369ade835@openai.com: Catch-All Detected (Random mailbox accepted 250), sam.altman@openai.com: 250 (Accepted by Catch-All MX)",
  "timestamp": "2026-09-14T13:15:05.000Z"
}
```

***

### 🚦 Verification Status Reference

- `VALID (Verified Deliverable)`: Confirmed existent via SMTP `250 OK` on a domain with non-catch-all verification.
- `RISKY (Catch-All - Mailbox cannot be uniquely distinguished)`: Domain accepts all incoming addresses; recommended `{first}.{last}` is provided alongside `candidate_patterns`.
- `NO_MATCH_FOUND`: All tested corporate permutations returned `550 Mailbox Not Found`.
- `UNVERIFIED (MX Active - No SMTP Service)`: Domain has healthy MX records, but SMTP port 25 was restricted or unreachable.
- `MX_NOT_FOUND`: The domain does not have active MX records or does not exist.

***

### 🧪 Local Testing

Run the Actor locally inside the isolated storage sandbox:

```bash
python test_local.py
```

***

### 🚀 Deployment to Apify Cloud

Deploy to Apify platform with a single command:

```bash
python deploy.py --yes
```

# Actor input Schema

## `first_name` (type: `string`):

Contact first name (e.g. Sam)

## `last_name` (type: `string`):

Contact last name (e.g. Altman)

## `domain` (type: `string`):

Target company website or domain (e.g. openai.com, stripe.com)

## `bulk_targets` (type: `array`):

List of targets to verify in bulk. Overrides single input if provided.

## `deep_smtp_check` (type: `boolean`):

Connect to target MX servers to check mailbox existence via RCPT TO. If disabled, only checks MX DNS and syntax.

## `timeout_seconds` (type: `integer`):

Socket timeout for DNS and SMTP checks. Recommended: 8-12.

## `verifier_api_url` (type: `string`):

Optional custom SMTP Verifier API endpoint. If omitted, built-in enterprise infrastructure is used automatically.

## `verifier_api_key` (type: `string`):

Optional API key for custom verifier endpoint.

## Actor input object example

```json
{
  "bulk_targets": [
    {
      "first_name": "Satya",
      "last_name": "Nadella",
      "domain": "microsoft.com"
    }
  ],
  "deep_smtp_check": true,
  "timeout_seconds": 10
}
```

# Actor output Schema

## `full_name` (type: `string`):

Full name of the prospect.

## `domain` (type: `string`):

Corporate domain searched.

## `best_guess_email` (type: `string`):

Highest scoring deliverable email.

## `status` (type: `string`):

Verification status: VALID, RISKY (Catch-All), INVALID, NO\_MATCH\_FOUND, UNVERIFIED (MX Active - No SMTP Service), or MX\_NOT\_FOUND.

## `mail_provider` (type: `string`):

Primary MX provider (e.g., Google Workspace, Microsoft 365, Mimecast, Proofpoint).

## `is_catch_all` (type: `string`):

Whether the domain accepts all incoming emails regardless of mailbox validity (true/false).

## `candidate_patterns` (type: `string`):

All corporate permutations generated for this domain.

## `tested_patterns` (type: `string`):

List and status of generated corporate permutations.

## `timestamp` (type: `string`):

ISO timestamp of verification.

# 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 = {
    "bulk_targets": [
        {
            "first_name": "Satya",
            "last_name": "Nadella",
            "domain": "microsoft.com"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("haktelaren/b2b-email-finder-verifier").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 = { "bulk_targets": [{
            "first_name": "Satya",
            "last_name": "Nadella",
            "domain": "microsoft.com",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("haktelaren/b2b-email-finder-verifier").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 '{
  "bulk_targets": [
    {
      "first_name": "Satya",
      "last_name": "Nadella",
      "domain": "microsoft.com"
    }
  ]
}' |
apify call haktelaren/b2b-email-finder-verifier --silent --output-dataset

```

## MCP server setup

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

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/xBxDtzOLoDFMhhzUv/builds/RJ3ZyBbRGIfwk1YwD/openapi.json
