# Company Email Pattern Finder: GitHub Commits + MX Check (`oswaldocarabano/company-email-pattern-finder`) Actor

Find the email format a company uses (first.last@, flast@, first@…) from public GitHub commits of its organization, with confidence, alternatives, MX and mail provider. Plus GitHub org profile, tech stack and activity. No SMTP probing. $0.03 per domain.

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

## Pricing

from $30.00 / 1,000 company domains

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

## Company Email Pattern Finder: find any company's email format from GitHub commits

Find the **email format a company uses** (`first.last@`, `flast@`, `first@`, `firstlast@`…) from the **public commits of its GitHub organization**, with a **confidence score**, the alternatives, **MX records** and the **mail provider**. Every row also brings the company's GitHub profile: website, location, verified badge, public repositories and members, **tech stack**, top repositories and recent activity.

Give it a list of company domains (`stripe.com`, `nubank.com.br`) and get one row per domain. Add the names of people you want to reach and each row also gives their most likely address. It works as an **email format lookup** and **email permutator** for B2B outreach, sales prospecting and recruiting research, and as a low-cost alternative to the "email format" lookups of paid email finder tools.

### Use cases

- **Cold outreach and sales prospecting**: know whether a company writes `jane.doe@` or `jdoe@` before you guess an address.
- **Lead enrichment**: add email pattern, mail provider (Google Workspace, Microsoft 365…), tech stack and engineering activity to a list of company domains.
- **Developer-tool go-to-market**: find companies that are active on GitHub, what languages they use and how many people commit.
- **Data hygiene**: check MX records and spot domains that cannot receive email, without sending a single message.

**No SMTP probing, ever.** The actor never connects to a mail server and never sends an email: it only reads public commits and DNS MX records. That keeps your IP and domain off blocklists.

### What you get per domain

| Group | Fields |
|---|---|
| **Email pattern** | `pattern`, `patternConfidence` (0–0.99), `patternConfidenceLevel` (high / medium / low / guess), `patternExample` (the pattern applied to "Jane Doe"), `alternatives` with their confidence, `evidenceCount`, `candidates` for the people you list, `roleEmails` (jobs@, hello@…), `otherCorporateDomains` (seen on 2 or more addresses), `relatedDomain` and its pattern (e.g. mozilla.com for mozilla.org) |
| **Mail** | `mxValid`, `mxHosts`, `mxError`, `emailProvider` (Google Workspace, Microsoft 365, Proofpoint, Mimecast, Zoho…), `catchAll` (always null: it cannot be known without SMTP) |
| **GitHub organization** | `githubOrg`, `orgUrl`, `orgName`, `orgDescription`, `orgBlog`, `orgEmail`, `orgLocation`, `orgTwitter`, `orgIsVerified`, `orgFollowers`, `publicRepos`, `publicMembers`, `orgCreatedAt`, `orgArchivedAt`, how sure the match is (`orgMatchConfidence`, `orgMatchReasons`) |
| **Activity and stack** | `lastCommitAt`, `activeCommitters90d`, `commitsScanned`, `scannedRepos`, `techStack` (by bytes of code with a token), `topTopics`, `topRepos` (stars, forks, license, homepage, open issues, created and last push dates, default branch), `totalStars` |
| **Repository inventory** | `reposFetched`, `forkRepos`, `archivedRepos`, `totalOpenIssues`, `reposCreatedLast12m` (new repositories in the last year), `newestRepoCreatedAt`, `licenses` |
| **Counts** | `uniqueEmailsSeen`, `corporateEmailsFound`, `noreplyEmails`, `personalEmailsSeen`, `otherDomainEmails` |
| **Opt-in** | `evidence` (the corporate emails behind the pattern, with name, repository, date and commit count) with **Include evidence emails**; `personalEmails` with **Include personal-domain emails** |

80 fields per domain row, every one present in every row (`null` when there is no value). Inputs that cannot be processed produce a short error row (`row_type: "error"`, `error_type`, `message`) that is never charged.

### How well it works (measured)

Measured on 1 October 2026 on **46 company domains chosen before measuring** (US, EU and Latin American tech companies), 5 repositories × 300 commits each, **148,821 commits** and **8,265 distinct email addresses**:

- **GitHub organization found: 44 of 46 domains (95.7%)**, and for 38 of them it is confirmed by commits from the company's own domain.
- **Pattern measured from real commits: 38 of 44 companies (86.4%)**. Confidence 0.75 or higher: 22 of 44 (50%); 0.5 or higher: 28 of 44 (63.6%).
- Latin American companies (n = 8): pattern measured for 5, high confidence for 3.
- Winning patterns: `first.last` 22, `first` 7, `flast` 6, `firstlast`, `firstl` and `first-last` 1 each.
- MX found for 43 of 44 domains; mail providers: Google Workspace 34, Proofpoint 5, Microsoft 365, Mimecast and others 1–2 each.
- Of all addresses seen in commits: 29.2% on the company's domain, 25.1% GitHub noreply, 23.1% personal (gmail, outlook…), 18.5% other companies. Noreply, bots and personal addresses are **never used as evidence**.

When a company has no GitHub organization, or no commits from its domain, the row says so (`notes`), gives the MX and provider, and the most common pattern for that provider marked as a guess (`patternInferred: true`, confidence 0.10).

### Pricing

Pay per domain, only for rows delivered:

| Event | Price |
|---|---|
| Company domain with its GitHub organization (pattern, MX, org profile, stack, activity) | **$0.03** |
| Company domain without a GitHub organization (MX, provider and a guess) | **$0.003** |
| Actor start | $0.00001 |

#### What a run costs (measured on Apify, 2 October 2026)

| Run | Time | You pay |
|---|---|---|
| 1 domain (the default input) | 16 s | $0.03 |
| 3 domains (`vercel.com`, `mercadolibre.com`, `jetbrains.com`) | 20 s | $0.09 |
| 20 domains, 2 repositories × 100 commits each, no token: GitHub's hourly limit was reached after 17, the other 3 are listed in an error row and not charged | 1 min 8 s | $0.51 |
| 100 domains | — | $3.00 |
| 1,000 domains (with a GitHub token) | — | $30.00 |

Inputs that cannot be processed (personal email domains, typos) produce an error row that is **never charged**. A domain is never charged twice in the same run, including after a platform restart. If you set a maximum cost per run, the actor stops cleanly when it is reached.

### Input

```json
{
  "domains": ["vercel.com", "mercadolibre.com", "jetbrains.com"],
  "knownPeople": ["Jane Doe, vercel.com"],
  "githubToken": "",
  "maxReposPerOrg": 5,
  "commitsPerRepo": 300,
  "includeSamples": false,
  "includePersonalEmails": false
}
```

- **Company domains**: a domain, a website URL or any email of the company. You can also give **GitHub organizations** directly (`stripe` or `https://github.com/stripe`).
- **People to build emails for**: "Jane Doe" applies to every domain; "Jane Doe, vercel.com" to one.
- **GitHub token** (optional, recommended): without it GitHub allows 60 API requests per hour, enough for about **15 domains per run**; with a token, about **500 domains per hour**. A fine-grained token with no permissions, or a classic token with no scopes, is enough (only public data is read). It is never logged or written to the output.
- **Where to read commits**: Git (default) fetches only commit metadata, about 300 commits per repository in about a second, without using API quota.

### Output example

A real row for `vercel.com` from a run on Apify (2 October 2026, shortened):

```json
{
  "domain": "vercel.com",
  "githubOrg": "vercel",
  "orgName": "Vercel",
  "orgBlog": "https://vercel.com",
  "orgIsVerified": true,
  "publicRepos": 239,
  "publicMembers": 72,
  "orgMatchConfidence": "confirmed",
  "pattern": "first.last",
  "patternConfidence": 0.77,
  "patternConfidenceLevel": "high",
  "patternInferred": false,
  "patternExample": "jane.doe@vercel.com",
  "alternatives": [{ "pattern": "first", "confidence": 0.09, "matches": 2 }, { "pattern": "last", "confidence": 0.03, "matches": 1 }],
  "evidenceCount": 20,
  "mxValid": true,
  "mxHosts": ["aspmx.l.google.com", "alt1.aspmx.l.google.com", "alt2.aspmx.l.google.com"],
  "emailProvider": "Google Workspace",
  "catchAll": null,
  "commitSource": "git",
  "reposScanned": 5,
  "commitsScanned": 1282,
  "uniqueEmailsSeen": 110,
  "corporateEmailsFound": 20,
  "noreplyEmails": 32,
  "personalEmailsSeen": 34,
  "lastCommitAt": "2026-10-02T13:33:47.000Z",
  "activeCommitters90d": 50,
  "techStack": [{ "language": "JavaScript", "repos": 10, "share": 0.468 }, { "language": "TypeScript", "repos": 68, "share": 0.353 }, { "language": "Rust", "repos": 1, "share": 0.151 }],
  "topTopics": ["vercel", "nextjs", "react", "ai", "javascript"],
  "notes": []
}
```

With **Include evidence emails** on, `evidence` lists the addresses behind the pattern, for example `{"email": "ana.perez@example.com", "name": "Ana Perez", "patterns": ["first.last"], "kind": "name-match", "source": "commit-author", "repo": "example/app", "date": "2026-09-30T10:00:00Z", "commits": 12}`.

### How the confidence is computed

Each corporate email in the commits is compared with the commit author's name ("Ana Perez" + `ana.perez@` → `first.last`). A match by name counts 1; an address that only has the shape of a pattern counts 0.3; a named address that matches no pattern counts 0.5 against. Confidence is the pattern's share of the evidence times a saturation by number of matches (1 match 0.5, 2 → 0.75, 3 → 0.88, capped at 0.99), halved when the domain has no MX. Ties are flagged with `patternTie`.

### FAQ

**Does it verify that an address exists?** No. Verifying needs SMTP probing (RCPT TO), which gets IPs blocklisted and is easy to abuse. The actor gives the pattern, its confidence and the MX records; `catchAll` is always null.

**Why GitHub?** Engineers at most tech companies commit with their work address. In the measurement, 29.2% of all addresses in company repositories were on the company's own domain.

**What if the company has no GitHub organization?** You get the MX, the mail provider and the most common pattern for that provider, clearly marked as a guess, for $0.003.

**How is this different from an email finder or verifier?** Email finders guess an address and then probe the mail server over SMTP. This actor tells you the company's email naming convention from real evidence, with a confidence score, and never touches the mail server. Pair it with your own verifier if you need per-address validation.

**How many domains can I run?** Without a token, about 15 per run (GitHub's limit of 60 requests per hour). When the limit is reached the run ends green, delivers what it finished, lists the domains that were not processed and does not charge them. With a token, about 500 per hour.

**Is the domain-to-organization match reliable?** Each row says how it was matched (`orgMatchReasons`) and how sure it is (`orgMatchConfidence`). `confirmed` means the organization's commits contain addresses on the requested domain (38 of 44 in the measurement).

**Do you store personal data?** By default the row contains only company-level data: the pattern, counts and the public organization profile. Individual addresses appear only if you turn on **Include evidence emails** (corporate addresses) or **Include personal-domain emails**. Turn them on only if you have a lawful basis to process those personal data. GitHub's terms do not allow using its data for spam or for selling personal information.

**Can I schedule it or call it from my code?** Yes, like any actor: schedules, the API, webhooks and integrations.

# Actor input Schema

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

Company domains to analyze, one per line: "stripe.com", "nubank.com.br". A website URL ("https://www.stripe.com/jobs") or any email of the company also works. The actor finds the company's GitHub organization, reads its public commits and returns the email pattern. Personal email domains (gmail.com, outlook.com…) are skipped.

## `githubOrgs` (type: `array`):

If you already know the GitHub organization, give its login ("stripe") or URL ("https://github.com/stripe"). The company domain is taken from the organization's website or email, or from its commits.

## `knownPeople` (type: `array`):

Names of people at these companies, one per line: "Jane Doe" (applies to every domain) or "Jane Doe, stripe.com". Each row gets their most likely email with the pattern's confidence. Names are only used to build emails and to match commit authors.

## `githubToken` (type: `string`):

A GitHub personal access token raises the API limit from 60 requests per hour (about 15 domains) to 5,000 (about 500 domains) and adds language bytes to the tech stack. Create one at github.com/settings/tokens: a fine-grained token with no permissions, or a classic token with no scopes, is enough because only public data is read. It is never logged or stored in the output.

## `commitSource` (type: `string`):

Git (default) reads the latest commits with a lightweight git fetch of commit metadata only: no API quota, about 300 commits per repository in a second. API reads 100 commits per request from your API quota.

## `maxReposPerOrg` (type: `integer`):

How many of the organization's most recently updated repositories to read (forks and archived ones are skipped). Measured on 44 companies: 1 repository found a pattern for 32, 3 for 36, 5 for 36, with a median of 3, 15 and 30 matching emails.

## `commitsPerRepo` (type: `integer`):

Latest commits read from each repository (authors, committers and co-authors).

## `includeForks` (type: `boolean`):

Forks mostly contain commits from the original project's authors, not the company's. Off by default.

## `checkMx` (type: `boolean`):

Look up the domain's MX records over DNS to confirm it receives email and to identify the mail provider (Google Workspace, Microsoft 365…). No email is ever sent and no mail server is contacted.

## `includeSamples` (type: `boolean`):

Add the corporate email addresses that support the pattern (name, repository and date of the commit). Off by default: the row then contains only company-level data (pattern, confidence, counts). Turn on only if you have a lawful basis to process these personal data.

## `evidenceLimit` (type: `integer`):

With evidence or personal emails turned on, at most this many addresses per domain are listed (all are still counted).

## `includePersonalEmails` (type: `boolean`):

Also list gmail.com, outlook.com, proton.me… addresses of people who committed to the organization's repositories. They are never used as evidence of the company pattern. Off by default; these are private individuals' addresses.

## `maxConcurrency` (type: `integer`):

How many domains are processed at the same time. The GitHub API limit is what usually decides the speed, not this number.

## Actor input object example

```json
{
  "domains": [
    "vercel.com",
    "mercadolibre.com",
    "jetbrains.com"
  ],
  "githubOrgs": [],
  "knownPeople": [],
  "commitSource": "git",
  "maxReposPerOrg": 5,
  "commitsPerRepo": 300,
  "includeForks": false,
  "checkMx": true,
  "includeSamples": false,
  "evidenceLimit": 25,
  "includePersonalEmails": false,
  "maxConcurrency": 3
}
```

# Actor output Schema

## `results` (type: `string`):

One row per domain: email pattern with confidence and alternatives, MX and mail provider, GitHub organization profile, tech stack and commit activity.

## `runSummary` (type: `string`):

Domains delivered and charged, GitHub API usage and quota left, and whether the run stopped early.

## `errors` (type: `string`):

Repositories that could not be read, skipped inputs and limits reached (always written, empty when all went well). Never charged.

# 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": [
        "vercel.com",
        "mercadolibre.com",
        "jetbrains.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("oswaldocarabano/company-email-pattern-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 = { "domains": [
        "vercel.com",
        "mercadolibre.com",
        "jetbrains.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("oswaldocarabano/company-email-pattern-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 '{
  "domains": [
    "vercel.com",
    "mercadolibre.com",
    "jetbrains.com"
  ]
}' |
apify call oswaldocarabano/company-email-pattern-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,oswaldocarabano/company-email-pattern-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/uoQ8XQUmrPljP5ax9/builds/hv14dc6CROasfGFWX/openapi.json
