5.9 KiB
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
- Quelle öffnen:
src_proto=imap→OpenIMAPSource, sonstOpenPOP3Source. Folders()→ rekursiver Ordnerbaum.- Pro Ordner: Zielordner via
MapSourceToTarget(11-folders.go) bestimmen — Rollen-Zuordnung gegen die vorhandenen Ziel-Ordner (keine Dubletten), Trenner umhängen,folder_mapals Override. DannEnsureFolder. Fetch(folder)streamend. Pro Mail:AlreadyCopied(id,folder,msgID)? → ja: überspringen. Nein: beide schreiben —TargetMailbox.Append(IMAP, mit Flags+INTERNALDATE) undMboxWriter.Append(lokal), dannMarkCopied. Fehler pro Mail zählen, nicht den ganzen Lauf abbrechen.jobsfortschreiben (Browser pollt/migrate/statusalle 3 s).--watch: Schleife mit Pause; dankcopiedkopiert 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)
- Unverschlüsselte Alt-Provider. Verbinden nach
src_security:tls=DialTLS (993),starttls=DialStartTLS (143),none=Dial (reiner Klartext).src_insecure→tls.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.) - Sonderzeichen in Ordnernamen. IMAP-Ordner sind auf der Leitung
modified-UTF-7 (
Gelöschte→Gel&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). - Standardordner nicht doppeln.
11-folders.gobildet jeden Ordner auf eine Rolle ab (SPECIAL-USE\Sent \Drafts \Junk \Trash \Archive, sonst mehrsprachige Namensliste).MapSourceToTargetsortiert Gesendet/Entwürfe/ Spam/Papierkorb/Archiv/Posteingang in den vorhandenen Rollen-Ordner des Ziels statt „Gesendete Objekte" neben „Gesendete Elemente" zu legen. Manuellesfolder_mapschlä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 (.gitignoresteht).
Fertig-Kriterien (Durchstich zuerst)
- Durchstich: ein Konto, nur
INBOX, Quelle→Ziel-APPEND+ mbox, Message-ID-Dedup, zweimal laufbar ohne Dubletten. - Alle Ordner rekursiv +
EnsureFolderim Ziel. - Konten-CRUD + Test-Button im Browser.
- Viewer (Liste/Lesen) + Weiterleiten.
--watch-Delta-Schleife.- Optional: POP3-Fallback.