DEV Community

Cover image for How to bulk verify an email list with Python (before your next email campaign bounces)
MailValid.io
MailValid.io

Posted on

How to bulk verify an email list with Python (before your next email campaign bounces)

If you've ever sent a campaign and watched your bounce rate spike, you already know the fix isn't a better subject line — it's a dirty list. B2B email data decays roughly 2% a month. A list you bought or scraped six months ago is already a different list today, and most inbox providers start treating a domain with a sustained bounce rate above 2% as a spam signal — not just for that campaign, but for everything you send from that domain afterward.

The fix is to verify the list before you send, not after the bounce report tells you what you already paid for.

This post walks through mailvalid-bulk-verify — a free, open-source Python CLI that takes a CSV of emails and gives you back the same file annotated with valid / invalid / catch_all / disposable for every row. No dashboard upload, no subscription, no code to write beyond one command.

What it actually checks

Each address gets run through:

  • Syntax and domain validation - is this even a well-formed address on a domain that exists?
  • MX record lookup - does the domain accept mail at all?
  • SMTP-level verification - does the specific mailbox exist, without actually sending anything?
  • Disposable detection - Mailinator, Guerrilla Mail, and other throwaway providers
  • Catch-all detection - domains that accept everything, so no single address can be confirmed
  • Role-based detection - info@, sales@, support@ - technically valid, usually dead weight in a cold outbound list

Setup

git clone https://github.com/mailvalid-io/mailvalid-bulk-verify.git
cd mailvalid-bulk-verify
pip install -r requirements.txt
export MAILVALID_API_KEY=mv_live_your_key_here
Enter fullscreen mode Exit fullscreen mode

Get a free key at mailvalid.io/register — 100 credits, no card required, roughly a dollar of usage at $0.001/email if you go beyond that.

Usage

python verify_list.py contacts.csv --email-column email
Enter fullscreen mode Exit fullscreen mode

That's it. It submits the whole list as one bulk job, polls until it's done, and writes contacts_verified.csv next to your input file with these columns appended:

Column What it tells you
mv_status valid, invalid, catch_all, unknown, or do_not_mail
mv_is_valid Boolean — mailbox confirmed to exist
mv_is_disposable Temporary/throwaway address
mv_is_role_based info@, sales@, etc.
mv_is_catch_all Domain accepts everything — can't be individually confirmed
mv_is_free_provider Gmail, Outlook, Yahoo, etc.
mv_confidence_score 0–100
mv_status_reason e.g. mailbox_confirmed, no_mx_records, disposable

What to do with the results

This is the part most people get wrong — verification only helps if you act on it consistently:

  • invalid or do_not_mail → delete. These are your hard bounces.
  • catch_all → don't drop these, but don't mix them into your main send either. Segment them onto a secondary domain at low volume.
  • disposable → delete, and if this is a signup form, add verification at signup so they stop arriving in the first place.
  • role_based → fine for transactional or support mail, dead weight in cold outbound.

Why a CLI instead of a dashboard upload

Most verification vendors treat the API as an upsell, you get a demo call, a proprietary SDK, and a monthly minimum sized for someone verifying a million addresses a month. If you just want to drop a CSV in a folder and run one command, weekly, as part of how you already work, a script beats a web dashboard you have to remember to open.

The full source, including how it batches and polls the bulk job, is on GitHub: github.com/mailvalid-io/mailvalid-bulk-verify


Questions, bugs, or a feature you want added; open an issue on the repo or drop a comment below.


Top comments (0)