Verify an email list before a campaign
Check every address on a list with Ravn, drop the ones that would bounce or hurt your sender reputation, and hand back a send-ready file plus a short report of what was removed and why.
One command.
Installs into ~/.claude/skills for Claude Code. In Claude, upload the downloaded file under Settings → Capabilities → Skills.
npx ravn skill install verify-email-list
When to use
- The user has a CSV, a pasted list or a CRM export and is about to send a campaign.
- The list came from a purchase, an event, an old database or a form with no confirmation step.
- The user asks "is this list safe to send?" or "clean these emails".
Do not use this to find new emails. For that, see the find-work-email or enrich-csv skills.
Before you start
- Check the connection. With MCP, call
get_accountwith{}. With the CLI, runnpx ravn whoami. Both are free. - Note the plan and
fair_use.lookups_remaining_5h. Each unique address costs 1 lookup. - Count unique addresses in the list. If that number is bigger than the lookups left, tell the user. Ravn ($24/month) includes 10,000 lookups a month, then $1 per 1,000 up to the spending cap; the Free plan has 1,000 lookups in total.
Steps
- Find the email column. If there is more than one (for example
EmailandWork Email), ask which one to verify. - Small lists (up to 1,000 addresses) over MCP: call
validate_emailsonce.
{ "emails": ["jane@acme.com", "info@acme.com", "bob@gmial.com"] }
- CSV files with the CLI: dry run, then a sample, then the full run.
npx ravn enrich list.csv --tool validate_email --column Email --dry-run npx ravn enrich list.csv --tool validate_email --column Email --limit 10 --out sample.csv npx ravn enrich list.csv --tool validate_email --column Email --out verified.csv
The dry run prints the row count, the lookups it will use and your remaining lookups. Show the sample to the user before the full run. The run saves progress every 25 rows; rerun the same command to resume after an interruption.
- Sort each row into a bucket using the verdict (
statusover MCP,rw_verdictin the CSV): -valid: keep. -invalid: remove. Thereasonsays why, for examplemailbox_not_found,no_mx,domain_not_foundorbad_syntax. -risky: remove from the send. Usually a catch-all domain (catch_all: true) or a disposable domain. -unknown: hold back. The mailbox could not be checked; never treat it as valid. - Also flag
role_account: true(info@, sales@) andfree_provider: trueif the campaign is B2B. Ask the user whether to keep them. - Write two files:
send-ready.csv(valid only, minus anything the user opted to drop) andremoved.csv(everything else, with the reason).
Output
The verified CSV keeps every original column and adds:
rw_status:ok,not_found,errorordropped(dropped means the run stopped on the rate limit before reaching that row).rw_verdict:valid,invalid,riskyorunknown.rw_risk_score(A to F),rw_reason,rw_domain,rw_provider,rw_disposable,rw_free_provider,rw_role_account,rw_catch_all,rw_mailbox_checked.
Finish with a summary: total rows, unique addresses, counts per verdict, and the top three removal reasons.
Rules
- Never send to anyone who opted out or asked not to be contacted. Remove them before verifying; Ravn's own opt-out list is at /privacy#optout.
- Drop invalid and risky addresses before any send. Do not quietly keep
unknownrows. - No FCRA uses: never verify lists to decide credit, employment, insurance or housing.
- If the list is larger than the lookups left this window, ask before starting a run that will pause and wait.
- On exit code 4 or a 429
fair_use_exhausted, the window is full; the run waits for the reset unless--no-waitis set. Rows not reached showrw_status=dropped; rerun later to finish.
Example prompt
Here's our webinar sign-up list (signups.csv). We're emailing everyone tomorrow. Clean it so we don't bounce, and tell me what you removed.
More skills
Install them all with npx ravn skill install --all.