Files
archivmail/features/PROJ-84-fix-mime-header-charset-backfill.md
T
sysopsandClaude Sonnet 5 8f46d688a8 feat(PROJ-85): Fix undeklarierte 8-Bit-Zeichen in Header/Body ohne Encoded-Word
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
2026-08-06 20:46:58 +02:00

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 von htmlindex unterstützten Charsets korrekt
  • CLI-Kommando archivmail fix-subjects identifiziert 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_skipped gezählt, DB-Subject bleibt beim Fallback (DecodeMIMEHeader auf vorhandenem String)
  • Mail bereits mit OCR-Text indexiert → Reindex darf attachment_text nicht 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() Erkennung
  • internal/storage/subject_backfill.go (neu) — ListRawEncodedSubjects(), UpdateSubjectMetadata()
  • cmd/archivmail/cmd_fix_subjects.go (neu) — CLI-Kommando inkl. Reindex + Audit
  • internal/audit/audit.go — neue Konstante EventMetadataBackfill = "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