Outlook-.msg-Dateien automatisch „schwärzen“ – ein kurzer Leitfaden zum gezeigten Python-Skript
Wer E-Mails weitergeben muss (Tickets, Audits, Schulungen), steht oft vor demselben Problem: personenbezogene Daten sollen drin nicht mehr sichtbar sein. Das hier gezeigte Python-Skript nimmt Outlook-.msg-Dateien aus einem Ordner, maskiert Name und E-Mail-Adresse und speichert eine „geschwärzte“ Kopie – bequem und reproduzierbar.
Was das Skript macht – in drei Sätzen
- Es liest alle .msg-Dateien aus C:/Temp ein.
- Es ersetzt den konkreten Namen Christian Dräger sowie passende E-Mail-Adressen (christian.draeger@…) durch einen Balken (████████████).
- Es erstellt über die Outlook-COM-Schnittstelle neue .msg-Dateien mit den bereinigten Betreff- und Textinhalten.
Voraussetzungen
- Windows mit installiertem Microsoft Outlook (für die COM-Schnittstelle win32com.client).
- Python-Pakete:
- extract_msg (liest .msg-Inhalte ohne Outlook)
- pywin32 (stellt win32com.client bereit)
- Schreib-/Leserechte im Zielordner (C:/Temp im Beispiel).
Kurzer Code-Walkthrough
Konfiguration
verzeichnis = "C:/Temp"
name_to_mask = "Christian Dräger"
email_to_mask = r"christian\.draeger@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
balken = "████████████"
Hier legen Sie Ordner, Zielnamen/E-Mail und das Maskierungszeichen fest. Der E-Mail-Regex ist bewusst restriktiv (passt auf Domains wie example.de, .com, .info etc.).
Maskierung
def maskiere_inhalt(text):
if not text:
return ""
text = text.replace(name_to_mask, balken)
text = re.sub(email_to_mask, balken, text)
return text
replace arbeitet exakt und groß/kleinschreibungs-sensitiv. „christian dräger“ wird also nicht getroffen.
re.sub maskiert die E-Mail anhand des Regex.
Lesen & Schreiben
outlook = win32com.client.Dispatch("Outlook.Application")
for datei in os.listdir(verzeichnis):
if datei.lower().endswith(".msg"):
msg = extract_msg.Message(pfad)
msg_subject = maskiere_inhalt(msg.subject)
msg_body = maskiere_inhalt(msg.body)
mail = outlook.CreateItem(0) # olMailItem
mail.Subject = msg_subject
mail.Body = msg_body
mail.SaveAs(ziel_pfad)
- extract_msg liest Betreff/Body.
- Über Outlook wird ein neues Mail-Objekt erzeugt und als .msg gespeichert.
- Absender/Empfänger werden nicht übernommen – die Infos müssten ggf. in den Body kopiert oder separat dokumentiert werden.
Wichtige Hinweise & Grenzen
- Formatierung: mail.Body ist Nur-Text. Wenn die Original-Mail HTML enthält, geht Formatierung verloren.
- Anhänge: Das Skript überträgt keine Anhänge. Wenn Sie Anhänge brauchen (und ggf. maskieren), muss das ergänzt werden.
- Groß-/Kleinschreibung & Varianten: replace findet nur exakt „Christian Dräger“. Schreibvarianten, Diakritika, Doppelnamen bleiben unmaskiert.
- Kompatibilität: win32com setzt Windows + Outlook voraus.
- Datenschutz/Compliance: Prüfen Sie vorab Ihre internen Richtlinien (Stichwort DSGVO/PII). Automatisches Schwärzen ist hilfreich, aber kein Ersatz für eine inhaltliche Prüfung.
Sinnvolle Verbesserungen (Quick Wins)
- Case-insensitive & Wortgrenzen für Namen:
- name_pattern = re.compile(r"\bchristian\s+drä(?:ger|eger)\b", re.IGNORECASE)
- text = name_pattern.sub(balken, text)
- E-Mail allgemeiner fassen (alle E-Mails maskieren, nicht nur eine Person):
- email_pattern = re.compile(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}")
- text = email_pattern.sub(balken, text)
- HTML erhalten: Wenn msg.htmlBody vorhanden ist, lieber mail.HTMLBody setzen und darin maskieren (Achtung auf HTML-Entities).
- Fehlerbehandlung & Logging: try/except um Datei- und COM-Operationen, Fortschritte loggen.
- Sicher speichern: Bestehende Dateien nicht überschreiben, z. B. Suffix mit Zeitstempel.
- CLI-Parameter: Ordner, Zielmuster, Regex via Kommandozeile übergeben (argparse).
- Dry-Run: Erst nur anzeigen, was maskiert würde – dann erst schreiben.
Phyton-Quellcode
import os
import re
import datetime as dt
import extract_msg
import win32com.client
VERZEICHNIS = r"C:/Temp"
BALKEN = "████████████"
# Muster: alle E-Mails + Name (varianten- & case-insensitive)
EMAIL_RE = re.compile(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}")
NAME_RE = re.compile(r"\bchristian\s+drä(?:ger|eger)\b", re.IGNORECASE)
def mask_text(text: str) -> str:
if not text:
return ""
text = EMAIL_RE.sub(BALKEN, text)
text = NAME_RE.sub(BALKEN, text)
return text
def safe_name(base: str) -> str:
ts = dt.datetime.now().strftime("%Y%m%d-%H%M%S")
return f"{base}_maskiert_{ts}.msg"
def process_msg_file(path: str, outlook) -> str:
msg = extract_msg.Message(path)
subject = mask_text(msg.subject)
# Body: HTML bevorzugen, falls vorhanden
html = getattr(msg, "htmlBody", None)
if html:
body_html = mask_text(html)
else:
body_html = None
body_text = mask_text(msg.body)
mail = outlook.CreateItem(0) # olMailItem
mail.Subject = subject
if body_html:
mail.HTMLBody = body_html
else:
mail.Body = body_text
out_dir = os.path.dirname(path)
out_name = safe_name(os.path.splitext(os.path.basename(path))[0])
out_path = os.path.join(out_dir, out_name)
mail.SaveAs(out_path)
return out_name
def main():
outlook = win32com.client.Dispatch("Outlook.Application")
for fname in os.listdir(VERZEICHNIS):
if not fname.lower().endswith(".msg"):
continue
fpath = os.path.join(VERZEICHNIS, fname)
try:
out = process_msg_file(fpath, outlook)
print(f"[OK] {fname} → {out}")
except Exception as e:
print(f"[FEHLER] {fname}: {e}")
if __name__ == "__main__":
main()
Praxis-Tipps
- Testordner verwenden: Zuerst mit Kopien arbeiten.
- Regex iterativ schärfen: Namen, Kürzel, Telefonnummern, Kundennummern etc. Schritt für Schritt ergänzen.
- Review einplanen: Trotz Automatik immer stichprobenartig prüfen.
- Dokumentieren: Welche Felder werden maskiert? Welche nicht? So bleibt die Weitergabe nachvollziehbar.
Viel Spaß beim Testen ;)