AI developer & architect, building production-ready intelligent systems.

©2026
← Back to projects

Internal toolAI & agents ● 2026

Email Finder

Finds a work email — and tells you how much to trust it

Give it a name and a company website; it gathers evidence across seven tiers — free ones first — infers the domain’s email pattern, and only reports an address as certain as the evidence allows.

7Evidence tiers
4Free tiers before any spend
3Separate claims per result
Product film
Role

Engineer — crawling, inference & verification

Tech
Year

2026

Live

Private build — demo on request

Overview

Most email finders guess a pattern and hope. This engine gathers evidence and weighs it: DNS and MX records, a relevance-scored site crawl, sitemaps, GitHub commit authors, linked PDFs like staff directories, and the Internet Archive for blocked sites.

Paid tiers — search queries, a browser transport for JavaScript-heavy or firewalled pages, and mail-server verification — only run when the free tiers cannot settle the question.

Results keep three claims separate on purpose: published, inferred and verified, because each one fails in a different way. It runs as a web app plus a background worker on Railway.

The problem

Sales teams need a person's work email, and most tools answer by guessing a pattern (first.last@) and labelling it 'verified'. On catch-all domains that label is meaningless, and every bounce hurts the sender's reputation.

The goal was a finder that spends as little as possible per lookup and is honest about certainty — including saying 'don't mail this person here' when the evidence says so.

Tech stack
App
Backend & data
Tooling
Also
Architecture
Email Finder system architecture
A Next.js web app enqueues lookups; a separate worker runs the tiered engine and writes results to Postgres under forced row-level security.
  1. 01

    Resolve the domain

    DNS and MX first — free, and enough to rule out domains that can't receive mail at all.

  2. 02

    Gather free evidence

    A relevance-scored crawl, sitemaps, GitHub commit authors, linked PDFs like staff directories, and the Internet Archive for sites that block crawlers.

  3. 03

    Infer the pattern

    Name/address pairs found along the way teach the domain's format; the engine ranks a candidate ladder from it.

  4. 04

    Spend only if needed

    Search, a browser transport for WAF-blocked or JS-rendered pages, and verification run only when the free tiers can't settle it.

  5. 05

    Verify honestly

    Catch-all detection runs before the ladder; a verified rejection of every candidate returns fail — a useful 'don't mail' rather than a guess.

Inside the product
A lookup working through the evidence tiers (example person and domain).
The confidence tiers a result can earn.
Under the hood: web, queue, worker and Postgres with forced RLS.
Features

Seven evidence tiers

Free sources first; paid search, browser and verification only when needed — costs stay predictable.

Pattern inference

Learns the domain’s email format from any name/address pairs it finds, then ranks a candidate ladder.

Honest confidence

Published, inferred and verified are reported separately — never more certain than the evidence.

Catch-all detection

Detects domains that accept every address before trusting a mail-server “yes”.

Highlights
  • 01Web app and worker deployed as separate Railway services
  • 02Worker waits for the database instead of crashing on cold starts
  • 03Drizzle migrations with separate local and production configs
  • 04Unit-tested inference with Vitest
Key decisions

Three claims, never merged

Published, deliverable and predicted fail differently, so they're reported separately. Only published and deliverable together earns 'confirmed'.

Cheapest evidence first

Four free tiers run before any paid search, browser or verification call, keeping per-lookup cost predictable.

Don't trust the ORM's RLS

Querying pg_policies showed drizzle-kit pushing policies with no USING clause — RLS on, but every row visible. The real predicates live in rls-force.sql, re-run after every push.

A worker that waits

Web and worker deploy as separate Railway services; the worker waits for the database on cold starts instead of crash-looping.

What's next
  • →Wire in a production verification provider so more results can reach 'confirmed'.
  • →Self-hosted browser transport to keep tier 5 costs flat.
  • →Per-lookup cost reporting in the dashboard.
Gallery

Want something like this?

I can build one for you.

Tell me what you have in mind — I'll reply with questions, a plan and a quote.

Next projectReframe →