Getrennt von PROJ-84: Header (v.a. Subject) mit rohen 8-Bit-Bytes ohne RFC-2047-Encoded-Word-Syntax wurden nicht auf tatsächliches Charset geprüft, landeten als ungültiges UTF-8 in emails.subject und Manticore. Gleiche Lücke bei decodeCharset() für den Body ohne verwertbaren Content-Type. RepairUTF8/RepairUTF8Bytes (charset_repair.go): bytegenaue Reparatur, gültiges UTF-8 bleibt Identität, nur ungültige Byte-Sequenzen fallen auf Windows-1252 zurück. Attachment.Data bewusst ausgenommen (bleibt byte-exakt für Downloads). fix-subjects-Kommando erkennt jetzt beide Fälle (HasEncodedWord || NeedsCharsetRepair). Verifiziert auf 192.168.1.132: 54 zusätzliche Subject-Fälle, 219 Body-Fälle behoben (bodyInvalidUTF8 219 -> 0). --apply noch nicht ausgeführt, Body-Korrektur braucht zusätzlich reindex. Die ursprünglich gemeldete Amazon-Mail bleibt bewusst unverändert: Encoding-Fehler kam bereits so vom Absender (=3F statt =DC im Original-Encoded-Word), GoBD verbietet nachträgliche Korrektur archivierter Originalinhalte. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WapWkrQusDuBMhaN8WyuXB
5.0 KiB
PROJ-84: Fix MIME-Header-Charset-Dekodierung + Backfill für Bestandsmails
Status: In Review
Created: 2026-08-06 Last Updated: 2026-08-06
Kontext
Betreffzeilen mit MIME-Encoded-Words (RFC 2047) in Charsets außerhalb UTF-8/US-ASCII/ISO-8859-1 (z.B. Windows-1252, ISO-8859-15) wurden nicht dekodiert und roh angezeigt (=?Windows-1252?Q?ARAG_4_...?=). Ursache: decodeMIMEHeader() in pkg/mailparser/parser.go nutzte mime.WordDecoder ohne CharsetReader — Go unterstützt dort nativ nur die drei genannten Charsets. Der Body-Decoder (decodeCharset, genutzt seit PROJ-57) konnte das bereits über htmlindex, der Header-Decoder nicht.
Fix (Commit 31d7113) behebt das für künftige Importe. Bestandsmails behalten den kaputten Betreff, bis sie per Backfill korrigiert werden — dafür dieses Ticket.
Dependencies
- Baut auf PROJ-57 (UTF-8-Encoding-Fix) auf — nutzt dieselbe
htmlindex-Charset-Logik - Betrifft PROJ-11/PROJ-48 (Audit-Log) — Backfill-Lauf wird auditiert
User Stories
- Als User will ich, dass Mail-Betreffs unabhängig vom ursprünglichen Absender-Charset korrekt lesbar sind, sowohl bei neuen als auch bei bereits archivierten Mails.
- Als Admin will ich einen nachvollziehbaren, wiederholbaren Weg haben, bestehende Mails mit kaputtem Betreff zu korrigieren, ohne das archivierte Original anzufassen.
Acceptance Criteria
decodeMIMEHeader()dekodiert Encoded-Words in Windows-1252, ISO-8859-15 und weiteren vonhtmlindexunterstützten Charsets korrekt- CLI-Kommando
archivmail fix-subjectsidentifiziert Bestandsmails mit undekodiertem Encoded-Word im Betreff - Dry-Run ist Default, echte Änderung nur mit
--apply - Korrektur ändert ausschließlich die Postgres-Metadaten-Spalte
emails.subject— die archivierte Original-EML im Storage-Layer bleibt unverändert - Nach Korrektur wird der Manticore-Suchindex für die betroffene Mail nachgezogen (inkl. Erhalt von vorhandenem OCR-Text)
- Jeder Lauf (auch Dry-Run) erzeugt einen Audit-Log-Eintrag (
event_type=metadata_backfill) mit Zählern --apply-Lauf auf 132 durchgeführt und stichprobenartig verifiziert (541/541 aktualisiert, 0 Fehler, User-Gegenprobe an ARAG-Mail bestätigt 2026-08-06)--apply-Lauf auf 131 (Produktiv) durchgeführt, nach Freigabe
Edge Cases
- Encoded-Word verletzt RFC 2047 selbst (z.B. Leerzeichen im codierten Teil, an Vortext geklebt) → wird übersprungen, mit WARN geloggt, bleibt unverändert (2 von 543 Fällen auf 132)
- Mail-Original nicht mehr ladbar/parsebar (z.B. DSGVO-gelöscht) → Index wird nicht angefasst, als
index_skippedgezählt, DB-Subject bleibt beim Fallback (DecodeMIMEHeaderauf vorhandenem String) - Mail bereits mit OCR-Text indexiert → Reindex darf
attachment_textnicht löschen, wird aus bestehendem Index-Dokument übernommen
Technical Requirements (optional)
- Kein neues Datenbankschema, keine neue Tabelle
- CLI-Subkommando statt Wegwerf-Skript, für künftige ähnliche Encoding-Bugs wiederverwendbar
- Exit-Code 1 bei Fehlern (cron-/scripttauglich)
Tech Design (Solution Architect)
Direkt umgesetzt ohne vorgelagerte Architektur-Phase — kleiner, klar umrissener Bugfix + Backfill-Tool, kein neues UI, kein neues Datenmodell.
Quelle der Wahrheit ist das archivierte Original: pro Mail wird die verschlüsselte EML lesend geladen und mit mailparser.Parse() neu geparst, der neue Betreff kommt aus pm.Subject. Fallback auf direktes Redekodieren des gespeicherten Strings, falls Original nicht ladbar. Geschrieben wird ausschließlich UPDATE emails SET subject=....
Implementation Notes (Backend, 2026-08-06)
Neue/geänderte Dateien:
pkg/mailparser/header_decode.go(neu) —DecodeMIMEHeader()exportierter Wrapper,HasEncodedWord()Erkennunginternal/storage/subject_backfill.go(neu) —ListRawEncodedSubjects(),UpdateSubjectMetadata()cmd/archivmail/cmd_fix_subjects.go(neu) — CLI-Kommando inkl. Reindex + Auditinternal/audit/audit.go— neue KonstanteEventMetadataBackfill = "metadata_backfill"cmd/archivmail/main.go,cmd/archivmail/cmd_import.go— Dispatch + Hilfetext
Kommando:
archivmail fix-subjects # Dry-Run (Default), alle Mandanten
archivmail fix-subjects --tenant 3 --limit 50
archivmail fix-subjects --apply
archivmail fix-subjects --apply --verbose # + jede Änderung alt->neu loggen
Messung auf 192.168.1.132 (Dry-Run, read-only): 543 Kandidaten, 541 reparierbar, 2 nicht dekodierbar (RFC-2047-Verletzung im Original, korrekt übersprungen). Charset-Verteilung: ISO-8859-15 (219), windows-1252 (185), Cp1252 (69), Windows-1252 (38), iso-8859-15 (11), utf8-Varianten (14), windows-1258 (5), ASCII (1).
Build auf 132 verifiziert (CGO_ENABLED=0 go build -buildvcs=false ./cmd/archivmail/ → OK), Dry-Run zweimal gegen Live-DB gelaufen, Stichproben korrekt (u.a. mehrteilige Windows-1252-Encoded-Words richtig zusammengesetzt). --apply noch nicht ausgeführt.
QA Test Results
To be added by /qa
Deployment
To be added by /deploy