Verify that email addresses belong to real people using lightweight web + LLM signals. Upload/paste lists, run concurrent checks, and export annotated results.
bg_*
fields)The app is a single HTML page (index.html
) that serves a light client built with Alpine.js and Tailwind. It lets you:
For each email, MailCheck performs a staged evaluation and collapses results into a single status and message:
spam
.whitelist
with rule annotation.spam
with rule annotation.info
, noreply
).compound-beta
): returns strict JSON with
status
in { person_high, person_low, person_none, spam }
message
, explanation_short
, and evidence[]
The prompt prefers identity‑first summaries and concrete evidence (role/title, org, city) and penalizes vague name‑only matches.openai/gpt-oss-20b
+ browser_search
tool): performs targeted queries (quoted email, handle+domain, site:linkedin, site:github, org/staff pages). Produces an analysis that is converted to JSON with status/message/explanation/evidence.openai/gpt-oss-120b
)
Consolidates assessor outputs + heuristics (academic, role, domain). Policy:spam > person_none > person_low > person_high
.spam
.person_high
.person_low
over person_none
.
The judge produces a single status/message, a short identity‑first summary, and deduplicated evidence bullets suitable for the UI.Statuses map to compact UI labels (e.g., person_low
→ “possible person”). Where assessors supply explanations, we derive a short identity‑first one‑liner for readability.
person_high
person_low
person_none
spam
whitelist
(short‑circuit on allowlist)deno task serve
This runs: deno serve --port 8013 --allow-sys --allow-read --allow-import --allow-env --allow-write --allow-net --reload=https://esm.town ./main.js
.
Open http://localhost:8013. If the server doesn’t have GROQ_API_KEY
, add a user key in the UI.
GROQ_API_KEY
: Groq key (server). The UI also supports a per‑user key.POST /api/check/background
{ "email": "someone@example.com", "systemPrompt": "optional extra guidance", "userApiKey": "<optional if server GROQ_API_KEY is set>", "whitelist": [ "@company.com", "*@partner.org", "/^first\\.last@org\\.edu$/i" ], "blacklist": [ "@temp-mail.com", "*@noidem", "/^[a-z]{2,}\\d{2,4}@gmail\\.com$/i" ] }
whitelist
(UI label: Allowlist) and blacklist
(UI label: Blocklist) accept strings:
"user@example.com"
"@example.com"
, "*@example.com"
, or bare "example.com"
"/^first\\.last@company\\.com$/i"
@
whitelist
.spam
and bg_blacklist_*
fields.{ "email": "someone@example.com", "status": "person_low | person_high | person_none | spam | whitelist", "message": "short description", "fields": { "bg_*": "diagnostic fields for UI" } }
Create a job to process many emails concurrently.
Create job
/api/jobs
{ "items": ["a@example.com", {"email": "b@example.com"}], "systemPrompt": "", "concurrency": 8, "userApiKey": "<optional>" }
{ id, running, total, completed, items: [{ id, email, status }] }
Get status: GET /api/jobs/:id
Cancel: POST /api/jobs/:id/cancel
Tip: If you want per‑job allowlist/blocklist, they can be added to the job payload and threaded into the runner.
gmail\.com
), anchor when needed (^...$
).Powered by Groq — get a key at https://groq.com.