Using AI at work

Mask names, emails, and phone numbers before pasting text into an AI tool

Remove or replace obvious personal data before sending text to an AI chat assistant, then review both the masked text and a detection report for anything the script missed. This tutorial uses a small synthetic example and keeps the original file unchanged.

Show contents

Who this is forFor people who want a practical pre-check before sending work text containing possible names, email addresses, or phone numbers to an AI assistant.

What you need
  • Python 3.12
  • A text editor and an AI chat assistant

01Start with a small synthetic message

This example is entirely synthetic. The names, email addresses, phone numbers, company details, and message content are invented for the tutorial. The purpose is to practice removing obvious personal data before text leaves your local workspace.

Save the following text as message.txt. It contains two names, two email addresses, two phone numbers, and one deliberately awkward reference that a simple masking rule will miss.

text
Project review notes

Alice Kim asked us to send the revised table to alice.kim@example.com.
If the file is delayed, call Alice at 010-1234-5678.

Bob Lee will review the second draft. His email is bob.lee@example.com and his office number is 02-345-6789.

The final approval should also be checked with A. Kim before Friday.

02Ask AI for a masking plan, not for the sensitive text

You can ask an AI assistant how to design masking rules without sending it the actual sensitive document. Describe the categories and use invented examples instead.

A useful answer should distinguish structured identifiers from unstructured language. Email addresses and phone numbers often have recognizable patterns. Human names are harder: ordinary words can be names, names can contain initials or multiple scripts, and the same person may be referenced in several forms.

03Convert the AI answer into explicit masking rules

For this synthetic example, use a small approved list for names and regular expressions for email addresses and phone numbers. This is intentionally narrower than a general personal-data detector.

Data typeRulePlaceholder
Full nameReplace only exact approved names Alice Kim and Bob Lee[NAME_1], [NAME_2]
EmailMatch common address-like patterns containing a local part, @, and domain[EMAIL_1], [EMAIL_2]
PhoneMatch the two phone formats present in this example[PHONE_1], [PHONE_2]
Other textLeave unchanged for manual reviewNo automatic replacement

Consistent placeholders are useful because repeated references can remain understandable without retaining the original identifier. The script below gives the same placeholder to repeated occurrences of the same detected value.

04Apply the rules to a local copy

The following Python script reads message.txt, applies the approved rules, and writes results into a new outputs folder. It also writes a replacements.csv report containing every detected original value and its placeholder. It stops if outputs already exists and never overwrites message.txt.

python
import csv
import re
import sys
from pathlib import Path

INPUT = Path("message.txt")
OUTPUT_DIR = Path("outputs")
MASKED_FILE = OUTPUT_DIR / "message_masked.txt"
REPORT_FILE = OUTPUT_DIR / "replacements.csv"

KNOWN_NAMES = ["Alice Kim", "Bob Lee"]

EMAIL_RE = re.compile(
    r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b"
)
PHONE_RE = re.compile(
    r"(?<!\d)(?:010-\d{4}-\d{4}|02-\d{3}-\d{4})(?!\d)"
)


def make_replacer(kind, mapping, rows):
    def replace(match):
        original = match.group(0)
        if original not in mapping:
            placeholder = f"[{kind}_{len(mapping) + 1}]"
            mapping[original] = placeholder
            rows.append(
                {
                    "type": kind,
                    "original": original,
                    "replacement": placeholder,
                }
            )
        return mapping[original]

    return replace


def mask_known_names(text, mapping, rows):
    for name in KNOWN_NAMES:
        if name not in text:
            continue
        if name not in mapping:
            placeholder = f"[NAME_{len(mapping) + 1}]"
            mapping[name] = placeholder
            rows.append(
                {
                    "type": "NAME",
                    "original": name,
                    "replacement": placeholder,
                }
            )
        text = text.replace(name, mapping[name])
    return text


def main():
    if not INPUT.is_file():
        sys.exit(f"Input file not found: {INPUT}")

    if OUTPUT_DIR.exists():
        sys.exit(f"Stop: {OUTPUT_DIR} already exists. Review or rename it first.")

    original = INPUT.read_text(encoding="utf-8")
    rows = []

    name_map = {}
    email_map = {}
    phone_map = {}

    masked = mask_known_names(original, name_map, rows)
    masked = EMAIL_RE.sub(make_replacer("EMAIL", email_map, rows), masked)
    masked = PHONE_RE.sub(make_replacer("PHONE", phone_map, rows), masked)

    OUTPUT_DIR.mkdir()
    MASKED_FILE.write_text(masked, encoding="utf-8")

    with REPORT_FILE.open("x", encoding="utf-8", newline="") as target:
        writer = csv.DictWriter(
            target,
            fieldnames=["type", "original", "replacement"],
        )
        writer.writeheader()
        writer.writerows(rows)

    print(f"Unique names masked: {len(name_map)}")
    print(f"Unique emails masked: {len(email_map)}")
    print(f"Unique phones masked: {len(phone_map)}")
    print(f"Masked copy: {MASKED_FILE}")
    print(f"Replacement report: {REPORT_FILE}")


if __name__ == "__main__":
    main()

Place mask_personal_data.py beside message.txt and run python mask_personal_data.py. For this exact example, the expected summary is 2 unique names, 2 unique emails, and 2 unique phone numbers masked.

05Check the replacements against the source

Work out the expected replacements before relying on the result. The script should record six unique detected values.

TypeOriginalReplacement
NAMEAlice Kim[NAME_1]
NAMEBob Lee[NAME_2]
EMAILalice.kim@example.com[EMAIL_1]
EMAILbob.lee@example.com[EMAIL_2]
PHONE010-1234-5678[PHONE_1]
PHONE02-345-6789[PHONE_2]

Alice Kim appears twice in the source but should use [NAME_1] both times. The report contains unique detected values rather than one row for every occurrence.

06Review what the automatic rules missed

Automatic replacement is only the first pass. Open outputs/message_masked.txt and read the entire result before pasting it anywhere. In this example, the last paragraph still contains A. Kim. The script cannot know from its approved list that this may refer to Alice Kim.

  1. Search the masked file for @ and confirm that no email address remains.
  2. Search for 010- and 02- and confirm that the two expected phone formats are gone.
  3. Search for Alice Kim and Bob Lee and confirm that the approved full names are gone.
  4. Read every line manually for initials, nicknames, signatures, addresses, employee IDs, account numbers, project-specific identifiers, or other identifying context.
  5. Notice that A. Kim remains. Decide manually whether it identifies a person in the real document and mask it if necessary.
  6. Compare replacements.csv with the source and confirm that each listed replacement corresponds to the intended text.

07Common mistakes and limits

  • Do not paste the original sensitive text into an AI tool merely to ask the AI what should be masked.
  • Do not assume a regular expression can reliably identify arbitrary human names.
  • Do not rely on one phone-number pattern if your source may contain spaces, country codes, extensions, parentheses, or other formats.
  • Do not delete the mapping report until you have finished checking the masked text, but protect that report because it contains the original identifiers.
  • Do not overwrite the source file. Keep the original separate from the masked copy.
  • Do not assume masking three categories removes confidential business information, credentials, financial data, health information, or other sensitive content.

For real workflows, define what must be removed based on the document, applicable policy, and purpose of the AI task. When possible, provide only the minimum text required for the task instead of masking a large document and sending the whole thing.

Execution and verification record

2026-09-21 · hand-checked example · Python 3.12

  • I checked the synthetic source text and expected replacements by hand.
  • The expected detection set contains 2 unique full names, 2 unique email addresses, and 2 unique phone numbers.
  • Alice Kim occurs twice but should consistently map to [NAME_1].
  • The deliberately abbreviated reference A. Kim is expected to remain unmasked and demonstrates a false negative.
  • The script reads message.txt and writes only outputs/message_masked.txt and outputs/replacements.csv.
  • The script stops if outputs already exists instead of replacing a previous review.
Verification limits
  • I did not execute the Python code; the small example and expected results were checked manually.
  • The full-name detection uses an explicit two-name list and is not a general named-entity recognition system.
  • The email regular expression covers common address-like forms but is not intended to implement every valid email syntax.
  • The phone regular expression covers only the two formats used in this synthetic example.
  • Masking obvious identifiers does not guarantee anonymization or compliance with any specific privacy law or organizational policy.

Site-wide writing and verification principles

References

The explanations and examples were written for this site. See the official sources below for the related behavior and concepts.