← Home

How to Clean a Lead List: The Full Pass

2026-07-20

A dirty lead list is not a tidiness problem. It is a compounding tax on everything downstream. Duplicates mean one company gets three messages from you in a week. Dead addresses mean bounces, and bounces mean mailbox providers quietly decide you deserve less inbox space. Worst of all, a dirty list corrupts your feedback loop: when a campaign underperforms, you cannot tell whether the message was wrong or the list was garbage, so you rewrite the message and learn nothing. Cleaning is the highest-leverage unglamorous work in outbound. Here is the full pass, in the order that actually saves time.

The order matters

Run it in this sequence: normalise formats, deduplicate, remove what must never be contacted, verify, then check enrichment completeness. Normalising first makes deduplication possible at all. Deduplicating before verification cuts the verification bill, and removing suppressed contacts first stops you paying to verify people you are barred from contacting.

1. Normalise formats first

Matching logic fails on cosmetic differences. Two records obviously identical to a human — +34 912 34 56 78 and 0034912345678 — are two different strings to a computer. So build a normalised shadow copy of each field, match on that, and keep the original for display. That is the rule people skip and regret: normalise a copy for matching, write to humans from the original. Nobody wants an email addressed to "acme trading" because your pipeline lowercased everything.

  • Phones to E.164. Plus sign, country code, national number, no spaces or brackets. This requires knowing the country, which is why phone normalisation fails silently on mixed-geography lists.
  • Domains to a canonical root. Strip the protocol and www, drop the path, tracking parameters and trailing slash, lowercase. You want the bare registrable domain, nothing else.
  • Emails lowercased and trimmed. Whitespace from spreadsheet copy-paste is the most common cause of "valid address, failed send". Strip invisible characters too — non-breaking spaces travel unseen through exports.
  • Countries and regions to one vocabulary. Mixed naming breaks segmentation, and segmentation is how you avoid sending an English message to a market that will not read it.
  • Company names de-suffixed for matching. Strip legal-form suffixes, punctuation and accents into a matching key. Preserve the original spelling for anything a human will read.

2. Deduplication is harder than it looks

Everyone assumes dedup means removing identical rows. Identical rows are the easy five percent. The real problem is one company appearing as Acme Ltd, ACME Limited and Acme, at three slightly different addresses, with three different contacts, from three sources.

Match on stable keys, not names

Company names are the worst possible identifier and the one most lists default to. They vary by legal-form suffix, punctuation, accents, transliteration, trading versus registered name, and whoever typed them in. Use them last.

  1. Registry number. Where you have it, definitive. One number, one legal entity. Most scraped lists lack it, which is why registry-sourced data is worth more than it looks.
  2. Website domain. The strongest key you will realistically have. Two records sharing a registrable domain are almost always the same company. Exceptions: platform subdomains, and franchises where many independent businesses sit under one corporate domain — handle those as known exceptions, not by dropping the rule.
  3. Phone in E.164. A good second key with one caveat: shared reception numbers and call centres mean a phone match sometimes indicates a shared switchboard, not a shared company. Phone alone is a candidate, not a verdict.
  4. Normalised name plus city. The fallback. Treat its output as a review queue, not an automatic merge.

People are not companies

Two contacts at the same company are usually not duplicates. They are two people. Deleting one because it "duplicates" the company is how you lose the decision-maker and keep the intern.

But your motion may still need a one-contact-per-company rule. On a cold pitch, three people at a twelve-person firm getting near-identical messages the same morning reads as spam to them and looks like spam to filters. Pick the best contact, park the rest as a second wave. On account-based work with different messages per role, keep them all. The rule follows the motion, not the data.

3. Remove what should never be contacted

  • Role addresses that do not fit your motion. Generic inboxes are not automatically bad — for small local businesses they are often the only address and the owner reads them. For an enterprise sale they are a dead end. Decide per campaign, not by blanket rule.
  • Placeholder data. Test addresses, repeated digits in phone fields, single-character names, an address field reading "none". Filter them once, in a rule you keep.
  • Aggregators and directories. A large share of scraped rows are not companies at all — directory pages, marketplaces, review sites and booking portals that matched your query. The tell is a domain attached to dozens of different business names. Detect them automatically: the same domains resurface in every list you build.
  • Competitors. Obvious, routinely missed.
  • Existing customers and open opportunities. The embarrassing one. Cold-pitching a company you already invoice, or a deal a colleague is negotiating, does more damage than any bounce. Check every list against customer and pipeline data before loading, every time.
  • Your suppression list. Anyone who unsubscribed, asked not to be contacted, or complained. Suppression is permanent and must survive every re-import and tool migration. If a suppressed contact can reappear because someone imported a fresh file, you do not have a suppression list — you have a temporary filter.

4. Verification and bounce control

Verify in cost order — the cheap checks eliminate a meaningful share before you pay for anything.

  1. Syntax. Free. Structurally invalid addresses, missing symbols, spaces in the middle.
  2. Domain level. Nearly free. Does the domain resolve, and does it accept mail at all? A domain with no mail configuration cannot receive anything, however plausible the address looks.
  3. Mailbox level. The paid step, worth it on any list you will send to at volume. This is where you find addresses that look perfect and do not exist.

Be honest about catch-all domains

Many business domains accept mail for every address and reject nothing at the door. Mailbox verification cannot resolve these — it can only tell you the domain is catch-all, and anything reporting a confident verdict on one is guessing. Treat them as a separate tier: send in small batches and watch what comes back.

Bounce discipline

Prune known-bad before sending rather than discovering bad addresses by bouncing off them. Every bounce is a deposit into the account that decides your inbox placement, and that account has a long memory.

Hard bounces go straight to permanent suppression — no retries, ever. Soft bounces get a few retries over days, then retire. And treat a bounce spike as a stop signal, not a statistic: if a batch bounces far above baseline, halt and inspect the list. Something upstream is wrong, and continuing to send spends reputation to confirm what you already know.

5. Enrichment gaps

A record missing the one field your message depends on is not usable. If your opening line references the city and the city is blank, that record produces a broken message. Half-personalised outreach is worse than none — it advertises automation and carelessness at once.

So per campaign, list the fields the message genuinely requires, then split: complete records go now, incomplete ones go to a fill queue, and anything you cannot fill affordably is dropped or moved to a generic message that never references the missing field. What you never do is send the personalised template to a record you did not finish. Platforms that build lists with contacts already attached — including JustLeadIt — fill much of this at collection time, but the completeness check still belongs in your pre-send routine.

A before and after

A small messy sample, of the kind every raw export produces:

  • Northgate Logistics Ltd — northgatelogistics.co.uk — +44 20 7946 0812 — info@
  • NORTHGATE LOGISTICS LIMITED — northgatelogistics.co.uk plus a contact path — 020 7946 0812 — sarah.dunn@
  • Northgate Logistics — northgatelogistcs.co.uk — no phone — s.dunn@
  • Harrow Freight Services — harrowfreight.co.uk — +44 161 496 0233 — office@
  • Harrow Freight — a directory listing, no own domain — 0161 496 0233 — no email
  • Bexley Transport Co — bexleytransport.co.uk — +44 20 8290 4471 — accounts@
  • Test Company — a placeholder domain — 00000000 — a test address

Run the pass.

Normalisation makes rows one to three comparable and reduces both phone variants to +442079460812. Deduplication collapses them into one company, keeping two contacts — the generic inbox and Sarah Dunn — and discarding the third, because northgatelogistcs is a typo domain that does not resolve, caught at the domain check. Rows four and five are the same company found twice; the second is a directory listing, so keep the real domain and the phone, which matches anyway. Row seven is placeholder data and dies at the filter. Row six survives clean, but the pipeline check flags it: Bexley Transport is already a customer, so it moves to suppression.

Seven rows became two companies and three contact points. You lost most of the list, and that is good news — what you lost was a duplicate, a duplicate, a typo, a directory page, a fake row and an existing client. Sending to all seven would have produced one bounce, one embarrassing email to a paying customer, two people at one small firm getting the same pitch, and a reply rate you would have blamed on your subject line.

Re-verification cadence

There is no universal interval, and anyone quoting one is selling something. Derive it from how fast your segment churns.

Two mechanisms decay a list. People change jobs, killing individual addresses while the company continues. And companies close or restructure, killing everything attached to them. The second is far more common among small, young and thin-margin businesses — hospitality, retail, personal services. The first dominates in large organisations, where the company is stable but the person moves.

So reason it out. Selling to small independent businesses in a volatile sector, closure rate drives the cadence and it is short. Selling to established mid-market firms, job changes drive it, so role-level checks matter more than domain checks. A company-level list decays slowly; a person-level, seniority-targeted one decays fast.

Practically: re-verify anything that has sat unused for more than a quarter before sending to it, verify harder in segments where you have seen higher bounce rates, and let your own bounce data set the schedule. Your bounces are a better decay estimate for your market than any published figure.

Make it a routine, not a project

The biggest improvement is not one big cleanup. It is making cleaning automatic, every time, before any list reaches a sending tool: normalise, dedup and check suppression, customers and pipeline on import; verify and check field completeness before send. Cleaning then stops being a project you postpone and becomes a filter nothing bypasses.

The payoff is bigger than it sounds. A clean list improves deliverability, protects a sending reputation you cannot buy back, and gives you honest metrics. When the list is clean and a campaign fails, you have learned something real about your message.

No subject-line test will ever beat that.

Find your next B2B leads

Search companies by niche and region — get contacts in one click.

Start a free search