Email is where personal data actually leaks — one autocompleted recipient at a time. This guide covers scanning inbound and outbound messages, subjects, attachments, and decade-deep archives; wiring detection into DLP and quarantine workflows; and the regulations that make all of it mandatory.
Start ReadingAsk a security team where they expect to lose personal data and they describe attackers; ask the breach statistics and they describe the Send button. Year after year, the UK Information Commissioner's Office reports that misdirected email — a message sent to the wrong recipient — is among the most reported causes of data incidents, routinely rivaling or beating phishing in sheer count. Verizon's DBIR tells the same story from the other direction: misdelivery sits stubbornly among the top error-driven breach actions, and "error" as a category features in roughly a quarter to a third of breaches depending on the year. The pattern holds because email combines maximum PII density with maximum human fallibility.
The failure modes are mundane and therefore relentless. Autocomplete resolves "Dav" to the wrong David. Reply-all carries a salary spreadsheet to forty people instead of four. Cc is used where Bcc was intended, disclosing hundreds of addresses — and, when the sender is a clinic or a charity, disclosing something sensitive about every one of them by mere membership in the list. A forwarded thread drags along an earlier message nobody re-read, containing exactly the account numbers the forwarder never saw. None of these are exotic; every organization does all of them weekly.
Meanwhile the content itself is uncontrolled. Customers email their card numbers to support unprompted. HR threads carry SSNs and health accommodations. Sales exports CRM slices to spreadsheets and mails them to personal accounts to "work from home." And unlike a database, email persists everywhere at once — sender's outbox, recipient's inbox, both servers, the journal archive, and every device that synced the thread.
The engineering response is to make content visible at the moment of transmission: scan every message for personal data as it moves, decide policy on what is found, and keep evidence of both. That is email PII scanning, and modern context-aware detection — the kind described in the PII detection pillar guide — finally makes it accurate enough to enforce without drowning administrators in false alarms.
No regulation says "scan your email" in those words. Every major one imposes duties — minimization, safeguards, breach notification, subject access — that are unmeetable for email without content-level detection.
| Regulation | How Email Triggers It | What Scanning Delivers | Guide |
|---|---|---|---|
| GDPR | A misdirected email containing personal data is a personal data breach under Art. 4(12); mailboxes are searchable "filing systems" in scope for access and erasure requests | 72-hour breach scoping ("what was actually in that message?"), DSAR search across mailboxes, minimization evidence for Art. 5(1)(c) | GDPR PII detection |
| HIPAA | PHI in email between staff, patients, and payers; the Security Rule requires transmission safeguards, the Privacy Rule requires minimum necessary | Detection of the 18 identifiers in bodies and attachments before send; breach risk assessment inputs after an incident | HIPAA PHI guide |
| GLBA | The Safeguards Rule obliges financial institutions to protect customer nonpublic personal information (NPI) — account numbers, balances, applications — which circulates constantly in advisor and back-office email | Outbound NPI blocking, monitoring evidence for the written information security program, vendor-channel controls | Banking PII detection |
| PCI DSS | Cardholder data may not be stored unprotected — and customers email PANs to support anyway, silently pulling mail systems into scope | Detection and redaction of PANs on arrival, keeping the mail platform out of the cardholder data environment | PCI DSS discovery |
| CCPA/CPRA & state breach laws | Consumer PI in marketing, support, and sales email; all 50 US states require breach notification keyed to specific data elements (SSN, DL number, account + credential) | Deletion-request fulfillment across mailboxes; element-level inventory of an exposed mailbox to determine notification duty | CCPA/CPRA guide |
A complete program watches four distinct surfaces. Each has its own risk profile, its own policy, and its own tolerance for latency.
Customers and partners send you PII you never asked for — card numbers, IDs, medical details. Scanning on arrival lets you redact or vault it before it settles into mailboxes, ticket queues, and CRMs, keeping unsolicited PANs out of PCI scope and volunteered health data out of general storage. Inbound findings also make superb coaching triggers: reply templates that tell customers what not to email.
The high-stakes direction: this is where misdirection, oversharing, and exfiltration happen. Outbound policy can block, quarantine, encrypt, or warn based on what is detected, who is sending, and where it is going — an SSN to a payroll processor is routine; the same SSN to a personal Gmail address is an incident. Detection runs synchronously in the delivery path, so accuracy and latency both matter.
Subjects deserve their own mention because they escape every protection applied to bodies: they appear in push notifications on lock screens, in delivery reports, in journaling indexes, and they stay plaintext even when the body is encrypted. "Re: Maria Alvarez claim #A-2241 — SSN verification" leaks from a locked phone in a coffee queue. Scan subjects with the same call as the body; they are just more text.
Every reply drags the whole thread along. The message being written may be clean while message four in the quoted history carries an account number — so scan the full MIME body, not just the newest fragment. Signatures add a twist: they are legitimate PII (the sender's own contact block), which naive scanners flag on every single message. Context-aware detection plus a custom_instruction exclusion for signature blocks keeps the alert stream meaningful.
Email scanning is a data loss prevention discipline, and the integration point determines what you can do about a finding. The strongest position is the mail flow itself: a milter on Postfix, a transport-rule connector in Microsoft 365, or a content-compliance hook in Google Workspace intercepts each message between submission and delivery. At this point the message can still be blocked, rerouted to quarantine, encrypted, or stripped of an attachment. Detection runs as an API call inside the hook: POST the subject plus body, branch on entities_detected and the types returned.
One tier back is the API-based scan (Graph API, Gmail API): near-real-time polling or change notifications inspect messages seconds after delivery. You can no longer stop transmission, but you can remediate — pull a misdirected internal message, alert the sender, open an incident with the exact entities involved. This tier is dramatically easier to deploy and is the pragmatic starting point for most teams.
The third tier is batch and archive scanning — journals, PSTs, mbox exports — covered in its own section below. Mature programs run all three tiers against the same detection endpoint with shared entity profiles, so "what counts as sensitive" is defined once and enforced everywhere. This is the pattern the broader DLP guide develops across channels beyond email.
What makes modern detection fit DLP better than the regex rulepacks of legacy gateways is precision under context. First-generation email DLP became infamous for flagging every nine-digit invoice number as an SSN until administrators shut the rules off — the NER vs regex comparison explains why. A transformer-based detector reads the sentence around the number, returns a confidence score you can tune per policy via threshold, and accepts natural-language exclusions via custom_instruction — "ignore our order numbers formatted ORD-#########" — without a rule-engine rewrite.
Three working patterns against the canonical API: a raw cURL scan of a single message, a Node.js outbound gateway hook, and a Python batch scanner that walks an entire mbox archive.
# cURL — scan one email (subject + body together) for high-risk entities
curl -X POST https://piidetectionapi.com/api/moderate.php \
-H "Content-Type: application/json" \
-d '{
"api_key": "YOUR_API_KEY",
"api_type": "pii_detection",
"text": "Subject: Onboarding docs for Maria Alvarez\n\nHi team, attaching her file. SSN 512-84-1177, DOB 04/12/1985, home address 14 Elm St, Springfield. Card for relocation costs: 4111 1111 1111 1111 exp 09/27.",
"entities": ["PERSON_NAME","SSN","DATE_OF_BIRTH","ADDRESS","CREDIT_CARD_NUMBER","CREDIT_CARD_EXPIRATION_DATE","FINANCIAL_ACCOUNT_NUMBER"],
"mask_mode": "replace",
"threshold": 0.45
}'
// JavaScript (Node fetch) — outbound gateway hook: block, quarantine, or pass
const BLOCK_TYPES = ["SSN", "CREDIT_CARD_NUMBER", "CVV_NUMBER", "PASSWORD", "API_KEY"];
async function checkOutbound(subject, body, recipientDomains) {
const resp = await fetch("https://piidetectionapi.com/api/moderate.php", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
api_key: process.env.PII_API_KEY,
api_type: "pii_detection",
text: subject + "\n\n" + body, // subjects leak too — scan them
mask_mode: "replace",
threshold: 0.5,
custom_instruction: "Ignore the sender signature block and our ticket IDs like TCK-12345",
}),
});
const data = await resp.json();
const types = data.detected_entities.map(e => e.type);
const external = recipientDomains.some(d => d !== "ourcompany.com");
if (external && types.some(t => BLOCK_TYPES.includes(t)))
return { action: "quarantine", reason: types, preview: data.anonymized_text };
if (external && data.entities_detected > 0)
return { action: "warn_sender", reason: types };
return { action: "deliver" };
}
# Python — batch-scan an mbox archive and write a per-message PII report
import mailbox, requests, csv
ENDPOINT = "https://piidetectionapi.com/api/moderate.php"
MAX_CHARS = 50000 # API request limit per call
def scan_text(text):
resp = requests.post(ENDPOINT, json={
"api_key": "YOUR_API_KEY",
"api_type": "pii_detection",
"text": text[:MAX_CHARS],
"mask_mode": "replace",
"threshold": 0.45,
}, timeout=30)
resp.raise_for_status()
return resp.json()
def body_of(msg):
if msg.is_multipart():
parts = [p.get_payload(decode=True) for p in msg.walk()
if p.get_content_type() == "text/plain"]
return "\n".join(p.decode("utf-8", "replace") for p in parts if p)
payload = msg.get_payload(decode=True)
return payload.decode("utf-8", "replace") if payload else ""
with open("pii_report.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["message_id", "date", "entities", "count"])
for msg in mailbox.mbox("export.mbox"):
text = (msg.get("Subject", "") or "") + "\n\n" + body_of(msg)
result = scan_text(text)
if result["entities_detected"]:
types = sorted({e["type"] for e in result["detected_entities"]})
writer.writerow([msg.get("Message-ID"), msg.get("Date"),
";".join(types), result["entities_detected"]])
Full request/response schemas live in the API documentation. Note the report stores entity types and counts, never matched values — the audit trail must not become a second copy of the PII it documents.
Bodies carry sentences; attachments carry datasets. The spreadsheet with 4,000 customer rows, the PDF benefits enrollment form, the zipped CRM export — when email loses data at scale, an attachment is usually the vehicle. An email scanning program that stops at the body inspects the envelope and ignores the parcel.
The pipeline is extract-then-detect. Walk the MIME structure, pull each attachment, and convert it to text with a format-appropriate extractor: spreadsheet cells serialized row by row, DOCX paragraphs, PDF text layers, and OCR for scanned or image-only documents. Then send the extracted text through exactly the same detection call as the body — same entity profile, same thresholds, so one policy governs the whole message. The extraction toolchain, including pdfplumber and OCR handling with worked code, is the subject of the document and PDF scanning guide.
Two email-specific wrinkles deserve attention. Volume asymmetry: a body is a few kilobytes but an attachment can explode past the 50,000-character request limit, so chunk large extractions across multiple calls and aggregate the findings per attachment. Container formats: zips within zips, EML files forwarded as attachments, and password-protected archives all hide content from naive scanners; unpack recursively where possible and treat unscannable encrypted containers as a policy decision in their own right — many outbound policies quarantine them by default precisely because they cannot be inspected.
The payoff scales with the stakes: policies can key on volume, not just presence. One phone number in a body is conversation; five hundred PERSON_NAME plus SSN pairs in an attached CSV headed to an external domain is an exfiltration event, and the entities_detected count gives the gateway exactly the signal it needs to tell the difference.
Real-time scanning protects tomorrow's mail; the archive is where yesterday's risk compounds. Organizations under retention duties — finance under SEC/FINRA books-and-records rules, healthcare, public bodies — journal every message into immutable stores that grow for years. Those archives are simultaneously a compliance asset and the largest unindexed PII repository the organization owns: nobody knows how many SSNs sit in the 2016 folder, and until someone scans it, every DSAR, breach, and legal hold is answered by guesswork.
Batch scanning converts that unknown into an inventory. The mbox walker in the code section is the miniature version; production versions parallelize across mailboxes and date ranges, checkpoint progress so a ten-million-message scan can resume, respect rate limits with a worker pool, and write findings — message ID, date, folder, entity types, counts — into a queryable index. That index then answers the questions that otherwise trigger panics: Which mailboxes contain data about this data subject? What was in the mailbox that was just phished? Which folders can we defensibly delete?
Prioritize by blast radius rather than scanning chronologically. Start with shared mailboxes (support@, hr@, claims@) because they concentrate third-party PII; then executive and finance mailboxes because they concentrate consequence; then the long tail. Teams in legal and eDiscovery run the same machinery for privilege and redaction review — finding every occurrence of a person across a custodian's mailbox is literally the DSAR problem with a docket number.
Archive scans are also the honest way to measure your email problem before buying policy fights: a week of scanning last quarter's journal yields the statistic that wins the budget — "we emailed N unencrypted account numbers externally last quarter" is not an argument anyone continues.
Detection without a proportionate response is just logging. The art of email DLP is matching the action to the finding — block rarely, warn often, and never train users to ignore the system.
For moderate findings, bounce the decision to the sender before delivery: "This message appears to contain 1 SSN and 2 account numbers and is addressed outside the organization — send anyway, edit, or encrypt?" Most misdirections die right here, because the sender genuinely didn't know. The masked preview from anonymized_text makes the warning concrete without re-displaying the sensitive values, and every warn-then-edit event is a training moment that costs the security team nothing.
High-risk combinations — blocklisted entity types to external domains, bulk counts, unscannable encrypted attachments — hold the message in a review queue instead of delivering it. The reviewer sees the masked rendition plus entity types, counts, and confidence scores, and releases, rejects, or escalates; auto-release timers keep business flowing when reviewers are slow. Discipline matters: quarantine queues rot into rubber stamps unless volume is kept low by good thresholds and precise entity selection.
A narrow set of findings warrants automation without a human in the loop: reject the send outright with an explanatory NDR (card numbers with CVVs to consumer domains), auto-redact on delivery using the masked body (inbound PANs into the ticket system), or force TLS/portal encryption for permitted-but-sensitive flows like payroll files to the benefits provider. Reserve hard blocks for cases with near-zero false-positive risk — checksum-validated entities at high confidence — because a wrongly blocked offer letter costs the program its political capital.
Every message you keep is risk you retain. GDPR's storage-limitation principle says personal data may be kept only as long as its purpose survives; sectoral rules pull the other way with retention floors — seven years for certain financial records, six for HIPAA documentation. The reconciliation is a schedule: retain what a rule requires, for exactly as long as it requires, and delete the rest on a calendar rather than a someday.
Email breaks naive schedules because one mailbox mixes every category: contracts that must live seven years sit beside customer complaints that should have died after two, in folders named "Misc". Content-level scanning gives retention engines the classification signal they lack — a message whose scan found HEALTH_INSURANCE_ID routes to the healthcare schedule, one with FINANCIAL_ACCOUNT_NUMBER to the books-and-records schedule, and the 94% with nothing sensitive can age out on the default timeline without legal review.
Scanning also unlocks the middle path between keep and delete: redact and retain. Where the business value of a thread is the decision it records rather than the identifiers it contains, store the masked rendition and delete the original at the schedule date. The thread stays searchable and evidentiary for operations; the SSN inside it stops being a liability. This is the same move that shrinks DSAR scope — a masked archive returns fewer hits because it holds less personal data.
And retention interacts with breach math directly: when a mailbox is compromised, notification duty attaches to what was in it. An organization that enforced two-year deletion plus PAN redaction answers for a fraction of what its packrat competitor must disclose. Pair the schedule with the archive-scanning inventory above and deletion becomes a defensible, documented program — the cheapest security control email has.
The operating habits that separate programs users respect from programs users route around.
Run detection in monitor-only mode for two to four weeks before any blocking. You learn your real base rates — which entity types actually flow, to which domains, from which teams — and tune thresholds and exclusions against reality instead of guesses. The monitoring report doubles as the business case, and the eventual enforcement rules inherit credibility from data.
The same entity means different things on different routes. Key decisions on entity type × direction × destination × count: internal HR mail legitimately carries SSNs; the same SSN to a consumer domain is an incident; five hundred of anything external is an event regardless of type. Flat "no PII in email" rules fail in a week because email's job is partly to carry PII — policy must encode which PII, where.
Synchronous outbound scanning sits in the send path, but the budget is comfortable: users tolerate a second of submission delay they never perceive, and message-sized payloads process in a few hundred milliseconds. Set aggressive API timeouts with a deliberate fail-open or fail-closed choice per policy tier — fail-open for warn rules, fail-closed for the hard-block set — and push oversized attachment scans to the asynchronous remediation tier.
Every detection event is a teachable moment. Route warn-tier findings back to senders with the masked preview; publish team-level trends (never leaderboards of shame); and give support staff canned replies asking customers to stop emailing card numbers — paired with a safe alternative channel. Organizations that pair scanning with feedback watch their incident base rate fall quarter over quarter, which no purely technical control achieves. Adjacent guide: support ticket PII detection.
custom_instruction such as "do not flag the sender's own contact details in the signature block"; use exclude_entities for types you never act on in your context; and de-duplicate findings against the quoted history so only the newly written fragment generates alerts while full-thread scanning still protects forwards. Confidence thresholds then trim the residue — signature hits typically pattern differently once context is considered.Paste a message into the live demo and watch every identifier surface with type, offsets, and confidence — then wire the same call into your gateway, archive scanner, or ticket queue.
Try the Live Demo View Pricing