Photo by Taylor Vick on Unsplash
Verifying 500 addresses is a solved problem. Almost any tool will do it.
A million addresses is a different conversation. Speed becomes real. Cost adds up fast. And if the accuracy isn’t there, you’re not just wasting money — you’re actively damaging the sender reputation of the campaign you’re cleaning the list *for*.
Here’s how to think about bulk verification at scale.
The Number Nobody Talks About: Time to Results
When you upload 500K addresses to a verification service, you need those results before your send window. Most campaign teams don’t think about this until they’re sitting at 11pm waiting on a CSV that’s been “processing” for six hours.
Time estimates at realistic list sizes (based on tool performance):
| List Size | Fast tool (2-3 min/10K) | Slow tool (7 min/10K) |
|---|---|---|
| 50K | ~10 min | ~35 min |
| 250K | ~50 min | ~3 hrs |
| 1M | ~3.5 hrs | ~12 hrs |
| 5M | ~17 hrs | 2.5 days |
If you’re running batch jobs on 5M+ addresses, you need either a fast tool or you need to start the job well before it’s needed. Or both.
BounceKill’s async batch processes at roughly 2M emails/hour. That’s not a typo — it’s a distributed worker pool with configurable concurrency. For most teams running under 500K, results come back in under 30 minutes.
CSV Upload vs API: When to Use Which
CSV upload is the right choice when:
- You’re running a one-time clean on an existing list
- The people running the campaign aren’t technical
- You want a downloadable file with status columns you can filter in Excel or Google Sheets
API is the right choice when:
- You’re processing list imports at scale on a regular basis
- You want to automate the pipeline (import → verify → segment → send)
- You’re integrating with a CRM or ESP that can consume webhooks
- You want results in a structured format without manual download steps
Most enterprise teams end up with both: marketing ops uses the CSV interface for ad-hoc cleans, while the engineering team runs the API for ongoing list processing.
What to Do With the Results
Verification gives you five buckets. Here’s how to handle each:
VALID — Send to these. Full confidence.
INVALID — Remove immediately. These are the hard bounces waiting to happen.
CATCH-ALL — This one trips people up. A catch-all domain accepts any address at that domain — so SMTP probing can’t confirm individual addresses. They could be real; they could be silently discarding your email.
Our recommendation: keep them on a separate “send with caution” segment. A/B test a small portion before sending the full segment. Watch bounce rates closely on the first campaign.
DISPOSABLE — Remove. These are throwaway addresses (Mailinator, Guerrilla Mail, etc.). There’s no real person there worth sending to.
RISKY — Judgment call. These are addresses with indicators of problems but no hard confirmation (role-based addresses like info@, spam trap patterns, recently active but suspicious behavior). Many teams skip these for cold outreach but keep them for transactional sends to existing customers.
UNKNOWN — Couldn’t be verified. Usually catch-all or greylisted servers. Same treatment as catch-all — hold them for a second verification pass or test send.
The Accuracy Question at Scale
At 100K addresses, a 3% accuracy difference between tools means 3,000 misclassified addresses. At 1M, that’s 30,000.
The two failure modes matter differently:
False positives (marking VALID emails as INVALID): You lose real prospects. In B2B, where a valid address might be worth $5K in pipeline, this is the more painful error.
False negatives (marking INVALID emails as VALID): They get through to your send. You take the bounce. Your sender reputation suffers.
Tools with lower accuracy tend to fail more on catch-all detection and older consumer addresses. If your list is heavy on .edu domains, older Gmail accounts, or corporate domains with catch-all configs — accuracy matters more than it would on a clean B2B prospecting list.
Before You Upload: Clean the Obvious Stuff First
Bulk verifiers aren’t magic. The cleaner your input, the better your output.
Before uploading, run a quick normalization pass:
import re
def normalize_email(email: str) -> str | None:
email = email.strip().lower()
# basic format check
if not re.match(r'^[^@s]+@[^@s]+.[^@s]+$', email):
return None
return email
emails = [normalize_email(e) for e in raw_list]
emails = [e for e in emails if e is not None]
# deduplicate
emails = list(dict.fromkeys(emails))
This removes whitespace issues, normalizes case, and filters addresses that don’t even match basic format rules — stuff like “N/A”, “none@none”, and malformed exports. Why spend credits verifying addresses that are obviously wrong?
Ready to Run Your List?
BounceKill handles lists from a few hundred to several million. CSV drag-and-drop for quick runs, REST API with webhook callbacks for automated pipelines.
Upload your list free → — first 100 verifications on us.



Leave a Reply