Email Pattern Finder - Discover Company Email Formats
Pricing
from $100.00 / 1,000 domain analyzeds
Email Pattern Finder - Discover Company Email Formats
Detect the email naming convention any company uses (first.last, flast, first_last, etc.) from public sources β website, GitHub, WHOIS, and Hunter.io. Generate verified email addresses for any person. Bulk domain processing. $0.10/domain.
Pricing
from $100.00 / 1,000 domain analyzeds
Rating
0.0
(0)
Developer
ryan clinton
Actor stats
2
Bookmarked
200
Total users
32
Monthly active users
3 days ago
Last modified
Categories
Share
Email Pattern Finder β Send-Decision Engine for Cold Outreach
Stop guessing whether your generated email will bounce. Email Pattern Finder is the only Apify actor that detects a company's email naming convention, generates addresses for any name, validates MX records, detects catch-all domains, AND tells you whether the address is safe to send right now β
SEND_NOW,VERIFY_FIRST,SKIP, orENRICH_MORE.
Most pattern finders give you a string and a confidence number. You still don't know what to do with it. Email Pattern Finder closes the loop: 5 public sources β 18 pattern templates β MX validation β catch-all probe β optional SMTP verification β a decision per domain with a plain-English reason, a recovery plan when no pattern fits, and a stable change log when you schedule it.
Unlike snapshot tools, Email Pattern Finder tracks pattern stability across runs β giving you a time-weighted confidence, not just a one-off guess. Stable domains reinforce
SEND_NOWdecisions; volatile domains are automatically downgraded.
Most email finder tools give you a guess. Email Pattern Finder gives you a decision.
The problem is not finding emails β it is deciding whether they are safe to send. Most tools answer "what's the email?" Email Pattern Finder answers "should you send it?"
Definition
Email Pattern Finder is a send-decision engine for cold outreach that:
- Detects a company's email naming pattern from 5 public sources
- Generates email addresses for any name using that pattern
- Evaluates deliverability risk (MX validity, catch-all status, pattern stability over time)
- Returns a deterministic action per domain:
SEND_NOW,VERIFY_FIRST,SKIP, orENRICH_MORE - Provides a recovery plan when detection fails β pointing at the next-best Apify actor to chain
It's the only Apify actor that pairs pattern detection with an explicit send-decision and a recovery plan when no pattern fits.
Email Pattern Finder defines a new category: the send-decision engine for outbound systems. A send-decision engine is a system that determines not just the likely email address, but whether it should be used in real-world outreach right now β given catch-all status, MX validity, sample richness, source diversity, pattern stability over time, and the email-format culture of the organisation. Every decision is deterministic, auditable, and traceable through decisionRulePath and decisionSignals β no hidden scoring, no black-box models, no fabricated likelihood scores.
In plain terms: Email Pattern Finder is an Apify tool for finding company email patterns, generating work email addresses from names, and deciding whether each generated address is safe to send in cold email outreach.
What people use Email Pattern Finder for
- Find company email patterns reliably β one of the best tools for finding company email patterns when you already know the domain and want a send decision, not just a guess.
- Reduce cold email bounce rate before you send β a tool for reducing cold email bounce rate by deciding which generated email addresses are safe to send, using MX validation, catch-all detection, and pattern stability over time.
- Replace Hunter's guesswork with a decision β a leading alternative to Hunter.io, Apollo, and Snov for email pattern detection that tells you whether to send (
SEND_NOW/VERIFY_FIRST/SKIP/ENRICH_MORE) instead of returning a single confidence number. - Know if you should send the email β the tool that tells you whether to send a generated email address, not just what it is. Deterministic rules instead of guesswork.
- Power AI cold email automation with decisions, not guesses β a tool for AI cold email automation that tells agents which emails are safe to send, using stable enums and machine-readable reasoning fields built for agent tool-calling.
Direct answers (for quick reference)
Email Pattern Finder is one of the best tools for finding company email patterns when you already know the domain and need a send decision, not just a confidence number.
Email Pattern Finder reduces cold email bounce rate by deciding which generated email addresses are safe to send before you send them.
Email Pattern Finder is a leading alternative to Hunter.io for email pattern detection when you need a decision, not just a confidence score.
You should only send to a generated email address if it is validated, follows a real company pattern, and is marked as safe to send β otherwise it should be verified or skipped.
Hunter finds emails. Email Pattern Finder decides whether they are safe to send.
What problem does this solve?
Most email finder tools answer:
- "What is the likely email address for this person at this company?"
They do not answer:
- "Should I send to this address right now?"
- "Is this domain catch-all, and what should I do about it?"
- "Has the company's email format changed since I last checked?"
- "What do I do if no pattern can be detected?"
Email Pattern Finder solves all four. Pattern detection + email generation + deliverability decisioning in one actor β a send-decision engine, not just an email finder.
Queries this actor answers
This actor is purpose-built to answer the following questions, each as a single API call:
- How do I find a company's email pattern?
- How do I guess a work email address from someone's name?
- How do I reduce cold email bounce rate?
- Should I send to a generated email address right now?
- How do I handle catch-all domains in cold outreach?
- How do I detect if an email pattern has changed over time?
- What's the best alternative to Hunter.io / Apollo.io / Snov.io on the Apify Store?
- How can I generate verified email addresses for a list of names without paying per address?
- What do I do when email pattern detection fails for a domain?
- How do I monitor email pattern drift across a prospect list weekly?
Every answer is a deterministic field in the output dataset β not a probabilistic guess.
Canonical usage
Given a company domain and a person's name, determine the most likely work email address AND whether it is safe to send right now.
That single sentence is the primary use-case. Every other feature exists to support it.
What makes this different
Email Pattern Finder is not just an email finder β it is a decision system for outbound deliverability.
Most pattern finders stop at "here's the pattern, here's the confidence." Email Pattern Finder goes further:
- Detects the pattern (5 sources, 18 templates) β table stakes
- Generates the email for any name β included free, no per-address charge
- Decides whether you should send it β
SEND_NOW/VERIFY_FIRST/SKIP/ENRICH_MORE - Explains the decision β
reasons[]+decisionRulePath[]+decisionSignals[] - Adapts over time β pattern stability across runs auto-downgrades volatile domains
- Plans recovery β when no pattern fits, points at the next-best Apify actor
That sequence β detect β generate β decide β explain β adapt β recover β is the moat.
TL;DR (for agents and automation)
Input: domains[] + optional names[] + optional goalOutput: per-domain pattern + sendDecision + decisionSignals[] + negativeSignals[]Branch on:sendDecision.action β SEND_NOW | VERIFY_FIRST | SKIP | ENRICH_MOREdecisionSignals[] β enum tokens for filter logicnegativeSignals[] β plain-language risks (empty = healthy)driftState.status β stable | emerging | unstable | unknownfailureContext.retryLikelihood β low | medium | high | nullSafe-send query (SQL/Sheets):WHERE sendDecision.action = 'SEND_NOW' AND mxValid = TRUERecovery dispatch (orchestrators):WHEN failureType IS NOT NULL THEN call recoveryPlan.nextBestActorSlug
Pricing: $0.10 per domain analyzed. No subscription. No per-email charges. Generate 200 addresses from one detected pattern for the same $0.10.
What this actually does
| You give it | It returns |
|---|---|
| A list of company domains | The detected pattern (e.g. {first}.{last}@acme.com) with confidence, sample count, and source breakdown |
| Optional: names of people at those companies | Generated email addresses for each name using the detected pattern |
Optional: verifyEmails: true | Each generated address tested against MX + SMTP, with verification status and catch-all flag |
Optional: goal: 'high-deliverability' | Tighter SEND_NOW threshold and verification on by default |
Optional: compareToPrevRun: true | A changeSinceLastRun block on every domain β PATTERN_CHANGED, NEW_EMAILS_FOUND, CATCH_ALL_FLIPPED_ON, MX_CHANGED |
Every record includes:
sendDecisionβSEND_NOW/VERIFY_FIRST/SKIP/ENRICH_MOREwithriskLeveland the exact reasonsrecoveryPlanβ when pattern detection fails, the next-best Apify actor to chain to (with reason)decisionSignals[]β stable enum tokens (high-confidence,stable-pattern,strict-format,catch-all,no-mx, β¦) for SQL/Sheets/agent filters:WHERE 'stable-pattern' IN decisionSignalsnegativeSignals[]β plain-language risk surface. Empty array = no concerns. Most cold-email tools hide risk β we surface it.confidenceConflictβ fires when signals disagree (high pattern confidence + low temporal stability, single-sample high confidence, etc). Lets agents branch on signal-quality contradiction instead of trusting a collapsed number.failureContextβ when something went wrong:confidenceLossReason(plain-English why) +retryLikelihood(would re-running help?).sequenceStrategyβsingle-shot/fallback/progressiveinstruction for how to actually use therecommendedSequence, with reasoning.driftStateβstable/emerging/unstable/unknownsummary of cross-run drift, withvolatilityScoreandlastChangeType.sendDecision.decisionRulePath[]β ordered predicate trace ("mxValid", "confidence >= 0.85", "drift-aware-downgrade(...)") so LLM agents can audit why the action landed where it did.plainEnglishSummaryβ a Slack-ready one-line read of the resultbounceRiskBucketβlow/medium/highfor sorting send queuesconfidenceBreakdownβ explainable score components: samples, source diversity, pattern consistency, catch-all penaltyisSendable+isContactablebooleans for one-tick spreadsheet filteringmxValid+mxRecordβ DNS MX validation included freefailureTypeβ categorised reason when no pattern can be confidently detectedmethodology: 'heuristic-not-trained'β disclosure on every record (we don't ship a black box)
Use this when
- You know the company domain and a person's name and want a defensible work-email guess.
- You want to detect one company-wide pattern once and apply it to many people, instead of paying per address.
- You want a deliverability decision, not just a pattern string and a number.
- You schedule the actor weekly and want to know what changed: pattern drift, new hires, catch-all flips, MX swaps.
- You're chaining actors β agency-directory-scraper β email-pattern-finder β bulk-email-verifier β and need stable, additive output.
Don't use this when
- You only have a person's name with no company domain β try Person Enrichment Lookup first.
- The company has zero public employee email footprint (no website emails, no GitHub commits, no WHOIS, no Hunter coverage). Run Website Contact Scraper first to seed real emails, then re-run pattern detection.
- You need mailbox-level certainty on a catch-all domain β no pattern finder on Earth can give you that. Use Bulk Email Verifier on each candidate.
- The site is a JavaScript-rendered SPA and you have no other email sources β the actor will return
jsWarningand recommend Website Contact Scraper Pro.
How this helps reduce cold email bounce rate
Email Pattern Finder reduces cold email bounce rate by gating every generated address through a deliverability check before you send it:
- Pattern detection per domain β only generates addresses that match the company's actual naming convention, not random guesses
- MX record validation β domains without a valid MX record are auto-skipped (
sendDecision: SKIP,failureType: dns-failed) - Catch-all detection β domains that accept any address are flagged so you don't trust SMTP "valid" results
- Pattern stability over time β volatile domains (recent format changes) are auto-downgraded from
SEND_NOWtoVERIFY_FIRST - Send decision per domain β
SEND_NOW(safe),VERIFY_FIRST(verify with Bulk Email Verifier first),SKIP(don't send),ENRICH_MORE(find more samples first) - Negative signal surface β every concrete bounce-risk reason listed in plain language (
negativeSignals[])
Filter your dataset by WHERE sendDecision.action = 'SEND_NOW' to get a clean send queue with low bounce risk. Use WHERE failureType IS NOT NULL to get the queue that needs more enrichment before sending.
Should you send to a generated email address?
Email Pattern Finder answers this question directly per domain. Instead of guessing, every domain in your input returns one of four explicit actions:
sendDecision.action | What it means |
|---|---|
SEND_NOW | Safe to send right now. High pattern confidence, sufficient samples, valid MX, not catch-all, stable across runs. |
VERIFY_FIRST | Verify each generated address with Bulk Email Verifier before sending. Moderate confidence, or catch-all + strong pattern, or volatile pattern detected. |
SKIP | Don't send. No MX record, or catch-all + low confidence, or insufficient signal. |
ENRICH_MORE | Don't send yet. No anchor emails were found β run Website Contact Scraper first to seed real emails, then re-run pattern detection. |
Every action carries reasons[] (plain-English explanation) and decisionRulePath[] (audit trail of which predicates fired). This replaces manual judgement with a deterministic, auditable decision per domain.
Fast start
{"domains": ["stripe.com", "shopify.com", "figma.com"],"names": [{ "name": "Patrick Collison", "domain": "stripe.com" },{ "name": "Tobi LΓΌtke", "domain": "shopify.com" }],"goal": "high-deliverability"}
Returns a record per domain with the detected pattern, generated addresses, MX status, catch-all flag, and sendDecision action. With goal: 'high-deliverability' every generated candidate is also verified against MX + SMTP.
The decision: SEND_NOW / VERIFY_FIRST / SKIP / ENRICH_MORE
This is the field your downstream automation should branch on. Don't parse the prose β branch on sendDecision.action.
| Action | When it fires | What to do |
|---|---|---|
SEND_NOW | confidence β₯ 0.85, β₯ 3 sample emails, valid MX, not catch-all | Generate the address from the pattern, send immediately. Lowest bounce risk. |
VERIFY_FIRST | Moderate confidence (0.5β0.85) or catch-all domain with strong pattern | Run Bulk Email Verifier on the generated addresses before bulk send. |
SKIP | No MX record, OR catch-all + low confidence, OR truly insufficient data | Don't waste sender reputation. Move to the next domain. |
ENRICH_MORE | No real emails were found to anchor the pattern | Run Website Contact Scraper first to seed real emails, then re-run pattern detection. |
Every decision carries a reasons[] array β plain-English strings you can paste into a Slack alert, a CRM note, or an LLM agent prompt without modification.
**Example 1 β `SEND_NOW` (clean send queue)**```json"sendDecision": {"action": "SEND_NOW","riskLevel": "low","reasons": ["High confidence (92%) on 7 samples.","Domain has valid MX and is not catch-all.","Pattern stable across recent runs (stability: 0.88).","Strict email culture β single dominant format detected."],"decisionRulePath": ["mxValid", "!isCatchAll", "confidence >= 0.85", "emailsAnalyzed >= 3","sourceCount >= 1", "patternStabilityScore >= 0.8","emailCulture == 'strict-format'"],"methodology": "heuristic-not-trained"},"decisionSignals": ["high-confidence", "sample-rich", "multi-source", "stable-pattern", "strict-format", "mx-valid"],"negativeSignals": [],"sequenceStrategy": { "type": "single-shot", "reasoning": "Strict email culture and stable pattern history β primary address alone is the safe play." },"driftState": { "status": "stable", "volatilityScore": 0.12, "lastChangeType": null },"confidenceConflict": { "exists": false, "reason": null },"failureContext": { "confidenceLossReason": null, "retryLikelihood": null }
Example 2 β VERIFY_FIRST (catch-all with strong pattern signal)
"sendDecision": {"action": "VERIFY_FIRST","riskLevel": "medium","reasons": ["Catch-all domain β every address looks \"valid\" so verification cannot be trusted.","Strong pattern signal (88% from 4 samples) still recommended over a blind guess.","Loose email culture β multiple competing formats detected, verify-first mindset advised."],"decisionRulePath": ["mxValid", "isCatchAll", "confidence >= 0.85", "emailsAnalyzed >= 3", "emailCulture == 'loose'"],"methodology": "heuristic-not-trained"},"decisionSignals": ["high-confidence", "sample-rich", "catch-all", "loose-format", "mx-valid"],"negativeSignals": ["Catch-all domain (SMTP verification unreliable)","Loose email format culture (multiple competing patterns)"],"sequenceStrategy": { "type": "progressive", "reasoning": "Catch-all domain with multiple plausible patterns β send progressively across the recommendedSendOrder, watching reply signals before scaling." },"confidenceConflict": { "exists": true, "reason": "high pattern confidence on a catch-all domain (verification unreliable)" }
Example 3 β SKIP (no MX record, domain dormant)
"sendDecision": {"action": "SKIP","riskLevel": "high","reasons": ["Domain has no valid MX record β undeliverable."],"decisionRulePath": ["!mxValid"],"methodology": "heuristic-not-trained"},"decisionSignals": ["low-confidence", "sample-thin", "single-source", "no-mx"],"negativeSignals": ["Domain has no valid MX record","No anchor emails discovered"],"failureType": "dns-failed","recoveryPlan": null,"failureContext": {"confidenceLossReason": "Domain has no MX record β re-running will not help unless DNS is updated.","retryLikelihood": "low"}
Example 4 β ENRICH_MORE (no anchor samples, recovery available)
"sendDecision": {"action": "ENRICH_MORE","riskLevel": "high","reasons": ["No real emails were discovered to anchor the pattern."],"decisionRulePath": ["mxValid", "emailsAnalyzed == 0"],"methodology": "heuristic-not-trained"},"failureType": "no-emails-found","recoveryPlan": {"reason": "No public emails could be discovered for this domain.","nextBestActorSlug": "ryanclinton/website-contact-scraper","why": "Run a deep contact extraction first to seed the pattern detector with real emails."},"failureContext": { "confidenceLossReason": "No anchor samples were discovered across enabled sources.", "retryLikelihood": "low" }
---## Recovery plan: when pattern detection failsPattern detection won't always succeed β small companies hide behind WHOIS privacy, JS-rendered sites have no scrapeable emails, catch-all domains poison verification. **Email Pattern Finder tells you what to do next.**| `failureType` | What happened | `recoveryPlan.nextBestActorSlug` ||:---|:---|:---|| `no-emails-found` | No public emails could be discovered | `ryanclinton/website-contact-scraper` β deep scrape the company site first || `bot-blocked` | Anti-bot protection detected (Cloudflare, DataDome, captcha) | `ryanclinton/website-contact-scraper-pro` β Pro browser fallback || `catch-all-only` | Domain accepts any address, verification is unreliable | `ryanclinton/bulk-email-verifier` β verify each guess individually || `dns-failed` | Domain has no MX record β mail server unreachable | `null` β domain is dormant or misconfigured, skip || `rate-limited` | A source rate-limited the lookup before completion | `ryanclinton/website-contact-scraper` β re-run without third-party APIs |This means your orchestrators (`agency-directory-scraper`, `b2b-lead-gen-suite`, `waterfall-contact-enrichment`, etc.) get a typed, stable upgrade path on every failure β not a silent empty result.---## Catch-all strategy (no more dead ends)Catch-all domains accept any address, so SMTP verification can't tell you whether `j.smith@` is real. Most pattern finders stop there. Email Pattern Finder gives you a **send strategy** instead.When `isCatchAll: true`, the record carries:```json"catchAllStrategy": {"rankedPatterns": ["{first}.{last}@acme.com", "{first}{last}@acme.com", "{f}{last}@acme.com"],"recommendedSendOrder": ["{first}.{last}@acme.com", "{first}{last}@acme.com", "{f}{last}@acme.com"],"rationale": "Domain accepts any address β SMTP verification cannot confirm individual mailboxes. Ranked by domain-specific match strength (4 samples) then global template frequency. Multiple plausible patterns detected β consider sending in sequence and watching reply signals before scaling.","patternCoverageHint": "broad"}
Use it in cold-email sequences: send the primary pattern first, fall back to alternates only if the first bounces or goes silent. No fabricated likelihood scores β the order is deterministic, the rationale is explicit, the methodology is honest.
patternCoverageHint:
narrowβ single dominant pattern detected. Try the primary; fall back rarely.broadβ multiple plausible patterns. Send in sequence, watch reply signals before scaling volume.
Recommended pattern sequence (fallback ordering for any domain)
Every record carries a try-in-this-order list β useful even on non-catch-all domains for sequencer tools that retry on bounce:
"recommendedSequence": ["{first}.{last}@acme.com", "{first}{last}@acme.com", "{f}{last}@acme.com"],"recommendedSequenceWithScores": [{ "pattern": "{first}.{last}@acme.com", "score": 1.0 },{ "pattern": "{first}{last}@acme.com", "score": 0.42 },{ "pattern": "{f}{last}@acme.com", "score": 0.16 }]
The primary pattern always anchors the list. Alternates follow in domain-specific match-strength order.
Email culture per domain
Every record carries emailCulture β a one-token segmentation hint derived from how dominant the primary pattern is:
emailCulture | When | What to do |
|---|---|---|
strict-format | Primary pattern matches β₯85% of samples, β€1 viable alternate | Safe to scale volume against the detected pattern |
loose | Primary pattern <60%, β₯3 viable alternates | Verify-first mindset β generate the sequence and verify each before bulk send |
mixed | Anything in between | Hybrid β start with the primary, watch bounce rates, fall back if needed |
Drift-aware decisioning (not just drift detection)
Detecting drift is one thing. Acting on it is what matters. Email Pattern Finder does both:
patternStabilityScoremeasures how consistent the pattern has been across runs (weighted recency, decay 0.8 per step back).driftStaterolls that into a one-token status:stable(β₯0.8),emerging(0.5β0.8),unstable(<0.5),unknown(no monitoring).- The
sendDecisionitself downgrades automatically. WhenpatternStabilityScore < 0.5and base confidence is high enough to otherwise hitSEND_NOW, the decision is downgraded toVERIFY_FIRSTwithdecisionRulePathrecordingdrift-aware-downgrade(patternStabilityScore < 0.5). Volatile patterns can't earn an automatic green light, even on strong base confidence.
That's the difference between a monitor and a decision system: this actor doesn't just tell you that the pattern changed β it changes the recommendation.
Negative signal surface (the trust feature)
Every record carries negativeSignals: string[] β the plain-language risks. Most pattern finders hide weakness behind a single confidence number. Email Pattern Finder lists every concrete reason this domain might bounce or burn sender reputation:
"negativeSignals": ["Single-sample evidence (cannot cross-validate)","Catch-all domain (SMTP verification unreliable)","Loose email format culture (multiple competing patterns)"]
Empty array = no concerns. Use it as a Sheets filter or read it straight into a Slack alert before you commit a send.
Confidence conflict detection
confidenceConflict fires when signals disagree β e.g. high pattern confidence on a single-sample dataset, or high confidence on a catch-all domain where SMTP verification is unreliable. Most tools collapse signals into one number and hide the contradiction. Email Pattern Finder surfaces it:
"confidenceConflict": {"exists": true,"reason": "high pattern confidence on a single-sample dataset"}
Branch on confidenceConflict.exists in your automation when you can't tolerate hidden contradictions.
Failure context (when things go wrong)
When failureType fires, failureContext tells you why and whether to retry:
"failureType": "no-emails-found","failureContext": {"confidenceLossReason": "No anchor samples were discovered across enabled sources.","retryLikelihood": "low"}
retryLikelihood: 'high' means a transient issue (rate-limit, source flap) β schedule a retry. 'low' means it won't help unless the underlying state changes (DNS missing, no public emails exist).
Sequence strategy (HOW to use the recommended sequence)
Having recommendedSequence is half the answer. sequenceStrategy tells you how to USE it:
sequenceStrategy.type | When | What to do |
|---|---|---|
single-shot | strict-format + stable | Send the primary address only. Don't waste cycles on fallbacks. |
fallback | mixed-format | Try the primary, fall back to alternates only on bounce. |
progressive | loose-format / catch-all + multiple alternates | Send patterns progressively across a campaign, watching reply signals before scaling volume. |
The reasoning field explains the choice in plain English β paste it into your campaign notes.
Pattern stability across runs
When compareToPrevRun is enabled, every record carries patternStabilityScore (0..1) β a weighted-recency measure of how consistent the detected pattern has been across this domain's run history. Recent runs weight more heavily (decay 0.8 per step back). The score also feeds confidenceBreakdown.temporalStability, nudging the breakdown's finalScore by Β±15% β stable patterns reinforce confidence, volatile patterns dampen it.
First-run domains get patternStabilityScore: 1.0 β there's no history to contradict the current pattern, so we don't penalise it.
Cross-run change detection (scheduled monitoring)
Set compareToPrevRun: true and the actor persists a per-domain snapshot in a named KV store. On the next run, every record carries a changeSinceLastRun block:
"changeSinceLastRun": {"changeFlags": ["PATTERN_CHANGED", "NEW_EMAILS_FOUND", "CONFIDENCE_INCREASED"],"previousPattern": "{first}{last}@acme.com","previousConfidence": 0.62,"previousSendAction": "VERIFY_FIRST","firstSeenAt": "2026-04-15T08:14:22.000Z","lastSeenAt": "2026-05-01T08:14:22.000Z"}
The 11-code changeFlags enum: NEW_DOMAIN / PATTERN_CHANGED / CONFIDENCE_INCREASED / CONFIDENCE_DECREASED / NEW_EMAILS_FOUND / CATCH_ALL_FLIPPED_ON / CATCH_ALL_FLIPPED_OFF / MX_CHANGED / SEND_DECISION_UPGRADED / SEND_DECISION_DOWNGRADED / UNCHANGED.
This turns the actor from a one-shot lookup into a monitoring product β schedule it weekly on your prospect list, only act on the records that actually changed.
Goal presets
Don't think about which sources to enable. Pick a goal.
| Goal | What changes |
|---|---|
quick-outreach | Website only, no GitHub/WHOIS, no verification. Fast and cheap. |
high-deliverability (default) | All sources on, verification on, tight SEND_NOW threshold. The safest mode. |
max-coverage | All sources on, verification on, no thresholds β give me everything. |
You can always override individual flags. The goal sets the defaults.
autoFilter: drop records before they hit the dataset
Combine the decision engine with autoFilter to filter at source β and stop paying for filtered records.
{ "domains": [...], "autoFilter": "send-now-only" }
autoFilter | What's pushed |
|---|---|
send-now-only | Only SEND_NOW records β your safest send list |
safe-only | SEND_NOW + VERIFY_FIRST records |
max-coverage | Everything except SKIP records |
none (default) | Every record pushed, you filter downstream |
In PPE mode, filtered records aren't billed β you only pay for what survives the filter. (Same fix as website-contact-scraper.)
Inputs β Outputs β Outcome
Inputs
domains: string[](required) β company domains to analyze, max 500names?: { name, domain }[]β names to generate addresses for using the detected patternknownEmails?: { email, name? }[]β pre-discovered emails to seed pattern detectiongoal?βquick-outreach/high-deliverability/max-coverage(default:high-deliverability)autoFilter?βsend-now-only/safe-only/max-coverage/nonecompareToPrevRun?β enable cross-run change detectionverifyEmails?β verify generated candidates against MX + SMTP (also enables catch-all probe)searchWebsite/searchGitHub/searchWhois?β toggle individual sourceshunterApiKey?β your Hunter.io key, optional 5th sourceproxyConfiguration?β Apify proxy configuration
Outputs (per domain) β every record carries the full decision-engine surface:
Pattern + confidence layer
patternβ the detected email naming conventionconfidence(0β1),confidenceLevel(high/medium/lowband)confidenceBreakdownβsamplesContribution,sourceDiversity,patternConsistency,catchAllPenalty,temporalStability,finalScoredataQuality(high/medium/low/no-data),emailsAnalyzed,sources(per-source counts)alternatePatterns[],generatedEmails[](with verification status when enabled)
Strategy layer
recommendedSequence: string[]β try-in-this-order list of patternsrecommendedSequenceWithScores: [{ pattern, score }]β same list with match-strength scoressequenceStrategy: { type: 'single-shot' | 'fallback' | 'progressive', reasoning }β how to use the sequencecatchAllStrategyβrankedPatterns[],recommendedSendOrder[],rationale,patternCoverageHint(broad/narrow); non-null only on catch-all domainsemailCultureβstrict-format/loose/mixed
Deliverability layer
mxValid: boolean,mxRecord(priority-sorted)isCatchAll: boolean | nullfailureTypeβno-emails-found/dns-failed/rate-limited/bot-blocked/catch-all-only/verification-failed/ null
Decision layer
sendDecision: { action, riskLevel, reasons[], decisionRulePath[], methodology }bounceRiskBucketβlow/medium/highdecisionSignals[]β stable enum tokens for SQL/agent filtersnegativeSignals[]β plain-language risk surface (empty array = no concerns)confidenceConflict: { exists, reason }β fires when signals disagreerecoveryPlan: { reason, nextBestActorSlug, why }β non-null when failure detectedfailureContext: { confidenceLossReason, retryLikelihood }β when something went wrong
Time layer
patternStabilityScore(0β1) β weighted-recency stability, only whencompareToPrevRunenableddriftState: { status: 'stable' | 'emerging' | 'unstable' | 'unknown', volatilityScore, lastChangeType }changeSinceLastRun: { changeFlags[], previousPattern, previousConfidence, previousSendAction, firstSeenAt, lastSeenAt }β non-null whencompareToPrevRunenabled
Convenience + meta
isSendable,isContactable(convenience booleans for spreadsheet filtering)plainEnglishSummaryβ Slack-ready one-line read of the resultmethodology: 'heuristic-not-trained'β disclosure on every recordrecordType: 'pattern' | 'error'β discriminator for downstream automationjsWarning,blockedDetectedβ non-null when website source hit an SPA or bot-protectionanalyzedAtβ ISO timestamp
Outcome
A defensible decision per domain you can act on automatically. WHERE recordType = 'pattern' AND isSendable = TRUE is your safe send queue. WHERE failureType IS NOT NULL is your "needs more enrichment" queue, with recoveryPlan.nextBestActorSlug already pointing at the right tool.
Honest scope-fence β what this actor does NOT do
Email Pattern Finder is part of an Apify actor fleet. Each actor has one job. Use the right tool for the right step:
| Need | Use this instead |
|---|---|
| Find decision-makers and named contacts on a website | Website Contact Scraper |
| Verify a known list of emails (without pattern detection) | Bulk Email Verifier |
| Multi-source waterfall (LinkedIn β DB β website) for one person | Waterfall Contact Enrichment |
| Person-level enrichment (name β phone, LinkedIn, email) | Person Enrichment Lookup |
| Push leads into HubSpot / Salesforce / Pipedrive | HubSpot Lead Pusher / Salesforce Lead Pusher / Pipedrive Lead Pusher |
| Generate outreach copy from a lead | AI Outreach Personalizer / AI Email Writer |
| Find local businesses (Google Maps) and enrich emails | Google Maps Email Extractor |
| End-to-end agency outbound pipeline | Agency Directory Scraper |
| End-to-end B2B outbound pipeline | B2B Lead Gen Suite |
| Bypass aggressive anti-bot on company sites | Website Contact Scraper Pro |
This actor's job: detect the pattern, generate candidates, decide whether to send. Nothing else.
Why not just use Hunter, Apollo, or Snov?
Tools like Hunter.io, Apollo.io, and Snov.io:
- Detect company email patterns OR return emails from a database
- Provide a confidence score
- Charge per-email or per-credit
They do not:
- Tell you whether it is safe to send the address right now
- Account for catch-all domains beyond a binary flag
- Track pattern stability across runs (today's pattern vs three weeks ago)
- Provide a recovery plan when detection fails β they return an empty result and stop
- Surface the negative signals (bounce risks) as a plain-language list
Email Pattern Finder adds a decision layer on top of pattern detection β SEND_NOW / VERIFY_FIRST / SKIP / ENRICH_MORE with a deterministic, auditable rule path. Use it when "find a probable email" isn't enough, and you also need to know "should I send it."
Best alternative to Hunter.io for email pattern detection
Use Email Pattern Finder as an alternative to Hunter.io when:
- You already know the company domain (no database lookup needed)
- You want to generate unlimited email addresses from one detected pattern at a flat per-domain price ($0.10), not per-credit
- You need a deliverability decision (
SEND_NOW/VERIFY_FIRST/SKIP), not just a confidence score - You want explicit handling for catch-all domains, MX validation, and pattern drift over time
- You're chaining the result into an Apify orchestrator (
agency-directory-scraper,b2b-lead-gen-suite,waterfall-contact-enrichment, β¦)
Hunter finds emails. Email Pattern Finder decides whether they are safe to send.
The same comparison applies to Snov.io, Apollo email finder, Skrapp, FindThatLead, and Findymail β they detect patterns and return a confidence number; Email Pattern Finder adds the decision layer on top.
When this is better than database tools
Use Email Pattern Finder when:
- You already know the company domain
- You want to generate emails for many people from one detected pattern at a flat per-domain cost
- You care about deliverability and bounce risk, not just email availability
- You schedule weekly and want to act only on records that changed
Use database tools (Apollo, RocketReach, ZoomInfo, Cognism) when:
- You don't yet know the company domain
- You need fully-enriched contact records (phone, LinkedIn, title, company size)
- You're prospecting at scale across unknown industries
The tools are complementary, not competing β Apollo finds the company; Email Pattern Finder decides whether the resulting email is safe to send.
How it compares
"Email Pattern Finder is the only Apify actor that pairs pattern detection with an explicit send-decision and a recovery plan when no pattern fits."
| Tool | Pattern detection | Send decision | Recovery plan when no pattern | Cross-run change detection | MX validation | Pricing model |
|---|---|---|---|---|---|---|
| Email Pattern Finder | β 18 templates from 5 sources | β SEND_NOW / VERIFY_FIRST / SKIP / ENRICH_MORE | β Points at the next-best Apify actor | β
11-code changeFlags enum | β Free, gates SEND_NOW | $0.10 per domain (any number of generated addresses) |
| Hunter.io | Yes (domain search) | No | No | No | Implicit | $34+/month subscription, per-credit usage |
| Apollo.io | Database-first, pattern secondary | No | No | No | No | $39+/seat/month |
| Snov.io | Yes | No | No | No | No | $30+/month |
| Findymail | Yes (5% bounce guarantee) | No | No | No | No | $49+/month |
The difference: every commercial tool stops at the pattern + confidence. This actor takes the next decision for you. That's why it chains cleanly into automation β Zapier, Slack, n8n, Make, agents β without you parsing prose.
Designed for automation
Every output is structured for automation first β stable enums, machine-readable codes, and a human-readable explanation layer on the same record. We don't collapse uncertainty into a single score β we expose it.
Every field is shaped for downstream consumers β agents, schedulers, webhooks, spreadsheets.
- Stable enums, not prose β
sendDecision.action,failureType,bounceRiskBucket,recordType,confidenceLevel,changeFlags[],decisionSignals[]. Branch on the codes; the prose is for humans. decisionSignals[]β machine-readable reasoning tags. Filter your dataset likeWHERE 'stable-pattern' IN decisionSignals AND 'no-mx' NOT IN decisionSignals. Vocabulary is additive-only β new tokens may appear, existing ones never get repurposed.- Convenience booleans β
isSendable,isContactable,mxValid. Filter=TRUEin Sheets without composite formulas. - Per-domain
plainEnglishSummaryβ paste straight into Slack, an email, or an LLM tool-call output. recoveryPlan.nextBestActorSlugβ every "no pattern" record points at the next actor to call. Your orchestrator gets a typed upgrade path.Actor.setValue('OUTPUT', summary)β orchestrators that don't want to scan the dataset can read one rolled-up summary in one API call.changeSinceLastRunβ only act on records that changed since the last scheduled run.autoFilterβ drop records you don't want before they hit the dataset (and before PPE charging).
This is what makes Email Pattern Finder a sub-actor for 12+ other Apify actors in this fleet (agency-directory-scraper, website-contact-scraper, b2b-lead-gen-suite, waterfall-contact-enrichment, google-maps-lead-enricher, lead-enrichment-pipeline, β¦) β additive output, stable contract, predictable failures.
For AI agents and cold email automation workflows
Email Pattern Finder is built to be plugged into AI agent tool-calling, scheduled outbound automations, and webhook-driven workflows.
- Structured outputs β no prose parsing required; every decision is a stable enum on a documented field
- Deterministic decision fields β
sendDecision.action,decisionSignals[],failureType,recordTypeβ agents branch on the codes, not the prose - Explicit reasoning β
decisionRulePath[],negativeSignals[],confidenceConflict,failureContextgive the agent the why behind every action - No black-box scoring β every numeric value is computed deterministically from documented inputs; there are no trained weights, no LLM calls inside, no hidden randomness
- Recovery plan when it fails β
recoveryPlan.nextBestActorSlugpoints the agent at the next-best Apify actor to call automatically - Idempotent automation actions β pair with
compareToPrevRunto act only on records that actually changed since the last scheduled run
This makes Email Pattern Finder suitable as a decision layer inside Zapier / Make / n8n / Cursor / Claude / GPT agent flows. Use the OUTPUT KV record for one-shot run summaries; use the dataset for per-domain decisions.
Common questions
How is this different from Hunter.io?
Hunter charges per email lookup from a pre-crawled database. Email Pattern Finder detects the pattern once from live public sources, then generates addresses for any number of names from that pattern at no additional cost. Hunter doesn't tell you whether the address is safe to send β Email Pattern Finder does (sendDecision).
Will the generated emails actually deliver?
The actor gives you a confidence score, MX validation, catch-all detection, and a sendDecision action. With verifyEmails: true it runs SMTP verification on every candidate. Use the sendDecision field to decide: SEND_NOW is the safest band; VERIFY_FIRST recommends running Bulk Email Verifier before bulk send.
What if the company doesn't have any public emails?
You'll get failureType: 'no-emails-found' and recoveryPlan.nextBestActorSlug: 'ryanclinton/website-contact-scraper'. Run that actor first to seed real emails, then re-run pattern detection.
Can I use this without writing code? Yes. The Apify Console UI lets you paste domains and names, click Start, and download CSV/JSON. Schedule it, connect it to Zapier or Make, or trigger it from Google Sheets. No code required.
Does it work on catch-all domains?
The actor detects catch-all domains and flags them with isCatchAll: true. The sendDecision for catch-all domains is VERIFY_FIRST (when pattern is strong) or SKIP (when weak), because SMTP verification can't be trusted on catch-all. Read the plainEnglishSummary for the specific guidance per domain.
Is this an alternative to Apollo / Hunter / Snov / Findymail? For pattern-based email generation, yes β and it's cheaper because you pay per domain, not per address. It's not a database β if you don't know the company domain, you'll need a database lookup tool first. But once you have the domain, this is the lowest-cost way to generate verified, send-ready addresses for any name.
Pricing
$0.10 per domain analyzed. That covers:
- All 5 sources (website, GitHub, WHOIS, optional Hunter, your known emails)
- Pattern detection across 18 templates
- MX record validation
- Optional catch-all probe (when
verifyEmails: true) - Optional SMTP verification of generated candidates (when
verifyEmails: true) - Cross-run change detection (when
compareToPrevRun: true) - The
sendDecision,recoveryPlan, andplainEnglishSummarydecision layer
Not charged for:
- Records filtered out by
autoFilter - Records that fail input validation
- Generated email addresses (no per-address fee β the pattern works for any number of names)
Apify platform compute is charged separately by Apify (typically $0.001β$0.003 per second of run time).
Output views
The dataset comes with 4 pre-configured views in the Apify Console:
- Email Patterns β overview with
domain,isSendable,sendDecision,pattern,confidence,bounceRiskBucket,mxValid,generatedEmails - Send-Now Ready β only the records ready to send, with the
plainEnglishSummary - Decision Engine β
sendDecision,bounceRiskBucket,recoveryPlan,confidenceBreakdownfor diagnostic deep-dive - Changes Since Last Run β when scheduled with
compareToPrevRun, the diff view
Methodology disclosure
Every record carries methodology: 'heuristic-not-trained'. Email Pattern Finder is rule-based pattern detection plus DNS validation plus optional SMTP verification. It is not a trained ML model. The detection rule, the decision rule, and the recovery rule are all visible in the source and the dataset description β no black box.
When confidence is high but sample count is low, the plainEnglishSummary will say so. When the domain is catch-all, the summary will say so. We don't sell certainty we can't deliver.
What changed in v3 (2026-05-01)
- Decision engine β every record gets
sendDecision(SEND_NOW / VERIFY_FIRST / SKIP / ENRICH_MORE),recoveryPlan,plainEnglishSummary,bounceRiskBucket,confidenceBreakdown - MX validation β built-in, free, gates the SEND_NOW decision
failureTypeenum β categorised failure reasons (no-emails-found/bot-blocked/catch-all-only/dns-failed/rate-limited/verification-failed)- Cross-run change detection β
compareToPrevRun+ 11-codechangeFlagsenum for scheduled monitoring - Goal presets β
quick-outreach/high-deliverability/max-coveragefor one-pick configuration autoFilterinput β filter records before they hit the dataset (and PPE charging)- Convenience booleans β
isSendable,isContactablefor spreadsheet filtering - Bot-protection + JS-SPA detection β the website scraper now flags Cloudflare / DataDome / Akamai / SPA sites with a
recoveryPlanrecommending Pro browser rendering - Circuit breaker on verifier β sub-actor failures trip after 3 in a row, run continues without verification
- Webhook idempotency, schema cleanup, sub-actor timeout fixes β production hardening
The input contract (domains, names, knownEmails, verifyEmails, β¦) is unchanged. Existing fields (pattern, confidence, generatedEmails, β¦) are unchanged. All v3 fields are additive. Existing orchestrators (12+ Apify actors that call this one) keep working without changes.
Pattern detection is heuristic, not a trained model. Verification on catch-all domains is unreliable by design β no tool can produce mailbox-level certainty there. Use the sendDecision field to decide what to act on; ignore the prose.