Files
archivmail/features/PROJ-84-fix-mime-header-charset-backfill.md
sysopsandClaude Sonnet 5 7727ad5cdf docs(PROJ-84,PROJ-85): Status auf Deployed - Backfill/Reindex auf 131+132 verifiziert
PROJ-84: 131 hatte 0 Kandidaten, 132 541/541 korrigiert (bereits
vorher bestätigt). PROJ-85: --apply + reindex auf 132 (54/54) und
131 (Produktiv) ohne Fehler durchgelaufen, User-Gegenprobe bestätigt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WapWkrQusDuBMhaN8WyuXB
2026-08-06 22:38:44 +02:00

5.1 KiB

PROJ-84: Fix MIME-Header-Charset-Dekodierung + Backfill für Bestandsmails

Status: Deployed

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 (0 Kandidaten dort, nichts anzuwenden)

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