Mail-Graveyard/Codex-Briefing.md
2026-07-05 17:58:25 +02:00

5.9 KiB
Raw Blame History

Codex-Briefing — Email-Forwarder

Du baust ein Go-Single-Binary im Hausstil (wie WatchDove): main.go als Orchestrator, nummerierte backend/NN-*.go, Server-gerendertes HTML + HTMX, config.json, SQLite via modernc.org/sqlite (kein cgo). Das Gerüst steht; fülle die // TODO Codex-Stellen. Lies zuerst Projektbeschreibung.md die 5 harten Regeln sind bindend.

Bibliotheken (lean, keine Lawine)

  • IMAP: github.com/emersion/go-imap/v2 (+ imapclient)
  • Parsen (Message-ID, Header, Text/HTML für Viewer): github.com/emersion/go-message
  • SQLite: modernc.org/sqlite
  • POP3-Fallback: github.com/knadh/go-pop3
  • SMTP-Weiterleiten: net/smtp (stdlib) — keine Extra-Dependency

go mod tidy + go mod vendor (Offline-Bunker, wie im Template).

Modul-Landkarte

Datei Inhalt
main.go Flags (--run, --watch), LoadConfig→ConnectDB→InitAuth, Web oder CLI
backend/00-router.go Routen + renderShell (Outlook-2013-Dreispalter) — da steht schon das Layout
backend/01-config.go config.json (App + Forward-SMTP). Konten NICHT hier, sondern DB
backend/02-database.go Schema + Account-CRUD + copied-Cache (Idempotenz)
backend/03-auth.go Login + AuthMiddleware
backend/04-imap-source.go Quelle: Ordnerbaum + Fetch BODY[] FLAGS INTERNALDATE
backend/05-imap-target.go Ziel: EnsureFolder + Append (Flags + INTERNALDATE)
backend/06-mbox.go mbox schreiben (Umzug) und lesen (Viewer)
backend/07-migrate.go Motor: pro Konto/Ordner/Mail, Dedup, Doppel-Write, Fortschritt
backend/08-viewer.go mbox im Browser: Liste, Lesen, Weiterleiten
backend/09-smtp.go SMTP nur fürs Weiterleiten
backend/10-pop3.go POP3-Fallback-Quelle (nur INBOX, nie DELE)

DB-Schema (SQLite)

accounts(id, name,
         src_host, src_port, src_security, src_insecure, src_user, src_pass, src_proto,
         dst_host, dst_port, dst_security, dst_insecure, dst_user, dst_pass,
         mbox_dir, active)
folder_map(id, account_id, src_folder, dst_folder)   -- optional, Vorrang vor Rollen-Automatik
copied(account_id, folder, message_id UNIQUE)        -- Delta-Cache
jobs(id, account_id, started, finished, total, done, errors, state)

src_security/dst_security = "tls" | "starttls" | "none". src_insecure/dst_insecure = ungültige Zerts akzeptieren.

Der Umzugs-Kern (07-migrate.go), Schritt für Schritt

  1. Quelle öffnen: src_proto=imapOpenIMAPSource, sonst OpenPOP3Source.
  2. Folders() → rekursiver Ordnerbaum.
  3. Pro Ordner: Zielordner via MapSourceToTarget (11-folders.go) bestimmen — Rollen-Zuordnung gegen die vorhandenen Ziel-Ordner (keine Dubletten), Trenner umhängen, folder_map als Override. Dann EnsureFolder.
  4. Fetch(folder) streamend. Pro Mail: AlreadyCopied(id,folder,msgID)? → ja: überspringen. Nein: beide schreiben — TargetMailbox.Append (IMAP, mit Flags+INTERNALDATE) und MboxWriter.Append (lokal), dann MarkCopied. Fehler pro Mail zählen, nicht den ganzen Lauf abbrechen.
  5. jobs fortschreiben (Browser pollt /migrate/status alle 3 s).
  6. --watch: Schleife mit Pause; dank copied kopiert jeder Durchlauf nur Neues.

UI — Outlook 2013 (Vorlage)

Look sitzt schon in frontend-js/dist/style.css + renderShell: Ribbon (Outlook-Blau #0072c6) mit Reitern Umzug · Postfächer · Betrachten · Einstellungen, darunter Dreispalter: links Ordnerbaum (Konto → Ordner), Mitte Nachrichtenliste (ungelesen = fett blau), rechts Lesebereich; unten Statusleiste. Flach, Segoe UI, blaue Auswahlzeile #cde6f7. Panes per HTMX nachladen (#tree / #list / #read). Klassen stehen im CSS: .tree-node, .msg-row(.unread/.active), .read-*, .grid/.input/.btn.

Reiter Postfächer = Konten-CRUD (Formular wie WatchDove targetForm, Quelle- und Ziel-Block, „Test"-Button prüft beide Logins). Reiter Umzug = Konten starten + Fortschritt. Reiter Betrachten = mbox-Viewer, im Lesebereich ein „Weiterleiten"-Button (öffnet Formular → 09-smtp.go).

frontend-js/dist/htmx.min.js per Bun holen (wie Template) und mit einchecken.

Sonderfälle — die drei Umzugs-Fallen (zwingend)

  1. Unverschlüsselte Alt-Provider. Verbinden nach src_security: tls=DialTLS (993), starttls=DialStartTLS (143), none=Dial (reiner Klartext). src_insecuretls.Config{InsecureSkipVerify:true} für kaputte/selbstsignierte Zerts. Muss ohne TLS funktionieren — alte Hoster können oft nichts anderes. (04/05-imap-*.go, POP3 analog 110/995.)
  2. Sonderzeichen in Ordnernamen. IMAP-Ordner sind auf der Leitung modified-UTF-7 (GelöschteGel&APY-schte). go-imap dekodiert/kodiert das — intern IMMER mit dem Klartext-Namen arbeiten, nie doppelt kodieren. Hierarchie-Trenner (. vs /) je Server aus LIST lesen und beim Umhängen übersetzen (11-folders.go).
  3. Standardordner nicht doppeln. 11-folders.go bildet jeden Ordner auf eine Rolle ab (SPECIAL-USE \Sent \Drafts \Junk \Trash \Archive, sonst mehrsprachige Namensliste). MapSourceToTarget sortiert Gesendet/Entwürfe/ Spam/Papierkorb/Archiv/Posteingang in den vorhandenen Rollen-Ordner des Ziels statt „Gesendete Objekte" neben „Gesendete Elemente" zu legen. Manuelles folder_map schlägt die Automatik.

Sicherheit

Tool hält fremde IMAP-Passwörter und kann Mails senden. Default bind=127.0.0.1

  • Login. Falls je remote (hinter Caddy): /vadmin-Mail-2FA-Muster aus dem Web-Deploy-Kit vorschalten. config.json/DB nie committen (.gitignore steht).

Fertig-Kriterien (Durchstich zuerst)

  1. Durchstich: ein Konto, nur INBOX, Quelle→Ziel-APPEND + mbox, Message-ID-Dedup, zweimal laufbar ohne Dubletten.
  2. Alle Ordner rekursiv + EnsureFolder im Ziel.
  3. Konten-CRUD + Test-Button im Browser.
  4. Viewer (Liste/Lesen) + Weiterleiten.
  5. --watch-Delta-Schleife.
  6. Optional: POP3-Fallback.