Almost every contact list starts life somewhere inconvenient: a column in someone else’s spreadsheet, a PDF attendee roster, a page of HTML you copied out of a directory, a forwarded thread with forty people on it. The addresses are in there. The problem is that they are surrounded by commas, angle brackets, table borders, tracking parameters and several thousand words you do not want.
This guide walks through the sources people actually deal with, what each one does to the addresses inside it, and how to get a clean list out the other side without hand-editing anything. The examples assume you are using the extractor on this site, but the logic applies to any pattern-matching tool.
Everything starts as plain text
A pattern matcher does not read file formats. It reads a stream of characters and finds the substrings shaped like an address. That single fact explains most of what follows: your job is never to convert a file, it is to get the characters onto your clipboard. Once they are there, the wrapper stops mattering.
This is also why a browser-based tool can handle sources that sound like they would need a parser. A PDF, a spreadsheet cell and a JSON string all become the same thing the moment you select and copy them. The extractor sees "email": "dana@acme.io", and takes dana@acme.io out of the middle of it, ignoring the quotes, the colon and the trailing comma.
The practical limit is size rather than format. Pasting 50,000 characters at a time — around 1,500 to 2,000 addresses — keeps everything instant. Larger archives are better split into batches, because the failure mode of a giant paste is a stalled browser tab, not a wrong result.
Spreadsheets and CSV exports
Spreadsheet exports are the easiest source and the one where people most often lose contacts. Two habits cause it.
The first is copying a single column. CRM exports rarely keep addresses in one place: a personal address sits in Email, a shared inbox in Company Email, and three more are buried in a Notes field where a rep pasted a signature block. Select the whole sheet instead. Extra columns cost nothing — phone numbers, job titles and dates contain no @ and are simply skipped — while a missed column costs you contacts you already paid to acquire.
The second is trusting the file to be clean. Real exports contain dana@acme.io;sam@acme.io in one cell, addresses wrapped in quotes because the cell also held a comma, trailing spaces from a bad import, and the same person entered three times under two spellings. None of that stops extraction. All of it stops a naive find-and-replace, which is why the deduplication step afterwards matters more than the parsing step.
If your export is a .csv file rather than an open spreadsheet, open it in a text editor rather than in Excel. You skip the import dialog, you skip Excel silently reformatting anything that looks like a date, and you can select the entire file in one keystroke.
PDFs, decks and scanned documents
Conference rosters, sponsor lists, membership directories and press kits arrive as PDFs. There are two kinds, and they behave completely differently.
A text PDF — anything generated from a word processor or a design tool — holds real characters. Select all, copy, paste. The layout will arrive mangled, with columns interleaved and line breaks in odd places, and none of that matters: an address split across a visual column boundary is still contiguous in the underlying text stream.
A scanned PDF is a photograph of a page. There are no characters in it at all, so selecting text either does nothing or returns gibberish. You need OCR first — most modern PDF readers, and the Preview app on macOS, will run it in place. Budget for errors afterwards: OCR routinely reads rn as m, 0 as O, and drops periods in domain names. Extraction from an OCR source needs a verification pass before it is worth sending to.
One PDF-specific trap: soft hyphenation. A long address broken across a line as alexandra.petersen- / @northwind.example will not match, because the hyphen and newline sit inside the address. If a document is heavily justified, scan the line ends manually before you conclude the list is complete.
JSON payloads and HTML source
API responses and page source are the most reliable sources you will ever paste, because machine-generated text is consistent. An address in JSON is always quoted the same way; an address in HTML is almost always inside a mailto: link.
That consistency has one consequence worth knowing. HTML source contains addresses twice when a page links them — once in href="mailto:dana@acme.io" and once in the visible link text. A raw match count from page source is therefore roughly double the real number of contacts, which is exactly why the unique count, not the total count, is the figure to read. Deduplication collapses the pair back to one.
Query strings are the other thing to watch. A link written as mailto:dana@acme.io?subject=Hello should yield dana@acme.io, and a good matcher stops at the ?. If you are using a home-grown regex and seeing dana@acme.io?subject=Hello in your results, that is the bug.
Email threads, headers and signatures
A long forwarded thread is a dense contact source: every reply adds a From line, a To line and usually a signature block. Copying the whole thread — quoted history included — and extracting from it will typically surface more people than the visible recipient list does, because the older messages carry participants who were dropped along the way.
Display names are the complication. Mail clients render recipients as Dana Wright <dana@acme.io>, and the angle brackets sit flush against the address. Bracket handling is basic for any competent parser, but it is worth confirming on your first paste, because a tool that returns dana@acme.io> will quietly poison every downstream import.
Full headers, if you can view them, add another layer: Return-Path, Reply-To, Message-ID and the SPF and DKIM results all contain address-shaped strings. Some of them are people. Many of them are infrastructure — bounces+2481-abc@mail.example.com is a bounce handler, not a prospect. Extract them if you like, then remove them with a role-account filter rather than by eye.
Server logs and support tickets
Mail server logs, signup logs and helpdesk exports are the messiest realistic source and the one where extraction saves the most time. A single log line might read:
2026-08-14T09:12:44Z status=sent to=<dana@acme.io> relay=mx1.acme.io[203.0.113.9] delay=1.2 dsn=2.0.0
Everything in that line except the address is noise, and there may be a hundred thousand such lines. Pattern matching cuts straight through it. Two cautions apply. First, log files repeat the same address on every delivery attempt, so duplicate removal is not optional here — it is the entire point. Second, a mail log records everyone your server touched, including people who unsubscribed, bounced or complained. A list rebuilt from logs is a deliverability incident waiting to happen unless you subtract your suppression list from it afterwards.
What extraction cannot recover
Some addresses are deliberately not there. Being honest about this saves you from concluding a tool is broken when it is working correctly.
- Written-out addresses.
dana [at] acme [dot] ioanddana(at)acme.iocontain no@and no dot in the domain. They will not match, and they should not — inventing an address from a guess about the writer’s intent is how you end up sending to something that does not exist. - Image addresses. Forum signatures and contact pages often render the address as a PNG precisely so this does not work. OCR is the only route.
- Script-assembled addresses. Many sites build the
mailto:link in JavaScript at click time. Viewing source shows the assembly code; using the browser’s inspector on the rendered element shows the finished address. - Contact forms. A form posts to an address you never see. There is nothing to extract, and no tool will change that.
Each of these is a signal as much as an obstacle. Someone who obfuscated their address did it to avoid unsolicited mail — which is worth weighing before you add them to a sequence.
A workflow you can repeat
Once you have done this a few times it collapses into the same five steps regardless of source:
- Get the characters. Select all, copy, paste. Do not tidy the source first — the parser does not care and you will only introduce errors.
- Read the counts before the list. Total matches versus unique addresses tells you immediately whether you pasted a log (heavy duplication), page source (roughly 2×) or a clean export (near 1:1).
- Deduplicate, then filter. Collapse repeats first, then remove role accounts and, if you only want companies, consumer mailbox domains.
- Export with structure. A CSV that splits email, domain and TLD into separate columns lets you sort by company, spot a single domain contributing 200 addresses, and catch a scrape that went sideways before you import it anywhere.
- Verify before sending. Extraction proves format, never deliverability. Lists assembled from documents and logs commonly bounce at 15 to 25 percent, and mailbox providers start throttling well below that.
Steps three through five are where a raw pile of matches becomes something you can actually send to. The next guide covers them in detail: how to clean an email list before your first campaign.