bb963a796f
- seedDefaultUsers: generiert kryptographisch zufällige Passwörter (crypto/rand) statt hartkodiertes "archivmailrockz" — Passwörter werden einmalig im Terminal angezeigt und können danach nicht wiederhergestellt werden - generateJTI: verwendet crypto/rand (16 Byte, hex) statt time.UnixNano XOR deadbeef Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.6 KiB
7.6 KiB
PROJ-15: CLI Import & Export
Status: Deployed
Created: 2026-03-13 Last Updated: 2026-03-17
Dependencies
- Requires: PROJ-5 (Speicherung & Indexierung) – Import nutzt Storage Coordinator
- Requires: PROJ-1 (Authentifizierung) – CLI läuft als Systembenutzer
archivmail, kein Web-Login
Hinweis
Die CLI läuft direkt auf dem Server als Systembenutzer archivmail – kein Web-Login, kein API-Key. Zugriff über den gleichen Storage Coordinator wie der Daemon. Gedacht für automatisierte Skripte, Cron-Jobs und administrative Bulk-Operationen.
User Stories
- Als Systemadministrator möchte ich EML/MBOX-Dateien per CLI importieren, damit ich Bulk-Importe skriptbasiert automatisieren kann.
- Als Systemadministrator möchte ich E-Mails per CLI exportieren (EML/MBOX), damit ich Sicherungen oder Migrationen durchführen kann.
- Als Systemadministrator möchte ich Import/Export mit Pfadangabe starten, damit ich Quell- und Zielverzeichnisse flexibel festlegen kann.
- Als System möchte ich Import-Fortschritt und Ergebnis auf stdout ausgeben, damit Skripte den Status auswerten können.
Acceptance Criteria
Import
archivmail import --file /pfad/zu/datei.eml– einzelne EML importierenarchivmail import --file /pfad/zu/archiv.mbox– MBOX importierenarchivmail import --dir /pfad/zum/verzeichnis/– alle EML-Dateien in einem Verzeichnis importieren (rekursiv optional:--recursive)- Fortschrittsausgabe auf stdout (eine Zeile pro 100 Mails)
- Exit-Code 0 bei Erfolg, 1 bei Fehler
- Duplikate werden übersprungen (SHA256-Dedup im Store), kein Fehler
--dry-runFlag: zeigt was importiert würde ohne tatsächlich zu speichern
Export
archivmail export --out /pfad/ziel/– alle Mails als EML-Dateien exportierenarchivmail export --out /pfad/archiv.mbox– alle Mails als MBOX exportierenarchivmail export --from alice@firma.de --out /pfad/– Filter nach Absenderarchivmail export --date-from 2024-01-01 --date-to 2024-12-31 --out /pfad/– Filter nach Datumarchivmail export --query "Rechnung" --out /pfad/– Filter per Volltext-Suche (Xapian)- Exportierte Mails als Klartext EML auf Disk
--format eml(Standard) oder--format mbox
Allgemein
- CLI läuft als Systembenutzer
archivmail– Config aus/etc/archivmail/config.yml - Fehler werden auf stderr ausgegeben
archivmail helpzeigt Übersicht aller Befehlearchivmail versionzeigt Version
Edge Cases
- Verzeichnis beim Import enthält keine EML-Dateien → Hinweis + Exit-Code 0
- Zieldatei beim Export bereits vorhanden → Fehler mit
--forceFlag zum Überschreiben - Kein Lese-/Schreibrecht auf Pfad → klare Fehlermeldung auf stderr
- Import unterbrochen (Ctrl+C) → partiell importierte Mails werden gespeichert, kein Rollback (Archiv ist append-only)
- Export bei leerem Archiv → leeres Verzeichnis / leere MBOX, Exit-Code 0
Technical Requirements
- CLI ist Teil desselben Go-Binaries (
archivmail) – Subcommands viaarchivmail <command> - Zugriff auf Storage Coordinator direkt (kein HTTP-Umweg über den laufenden Daemon)
- Key-Datei muss lesbar sein (
/etc/archivmail/keyfile,chmod 400, Ownerarchivmail) - Kann parallel zum laufenden Daemon betrieben werden (Xapian WritableDatabase: Lock beachten)
- Strukturierte Ausgabe optional:
--jsonFlag für maschinenlesbare Ausgabe
Tech Design (Solution Architect)
CLI-Struktur
archivmail <command> [flags]
Commands:
import E-Mails importieren (EML, MBOX, Verzeichnis)
export E-Mails exportieren (EML, MBOX)
version Version anzeigen
help Hilfe anzeigen
archivmail import
--file /pfad/datei.eml oder .mbox
--dir /pfad/verzeichnis/
--recursive Unterverzeichnisse einschließen (mit --dir)
--dry-run Simulation ohne Speichern
--json Maschinenlesbare Ausgabe (JSON)
archivmail export
--out /pfad/ziel/ oder /pfad/archiv.mbox (Pflicht)
--format eml (Standard) | mbox
--from Absender-Filter
--to Empfänger-Filter
--date-from Datum von (ISO 8601: 2024-01-01)
--date-to Datum bis (ISO 8601: 2024-12-31)
--query Volltext-Suche (Xapian QueryParser)
--force Zieldatei überschreiben
--json Maschinenlesbare Ausgabe (JSON)
Komponentenstruktur
archivmail (Go-Binary)
│
├── main.go ← Subcommand-Router (import / export / ...)
│
├── cmd/import.go
│ ├── Flag-Parsing
│ ├── Dateityp-Erkennung (.eml / .mbox / Verzeichnis)
│ ├── EML-Parser
│ ├── MBOX-Parser (zeilenweise)
│ └── → Storage Coordinator (PROJ-5, direkt, kein HTTP)
│
└── cmd/export.go
├── Flag-Parsing
├── Filter-Builder (from, to, date, query)
├── → Xapian ReadonlyDatabase (Suche/Filter)
├── → PostgreSQL Metadaten-Lookup
├── → .m-Datei lesen + AES-256-GCM entschlüsseln
└── Schreiben als EML-Dateien oder MBOX
Import-Fluss
$ archivmail import --dir /backup/mails/ --recursive
Key laden aus /etc/archivmail/keyfile
Verzeichnis scannen → 3.842 .eml-Dateien gefunden
[████████░░] 2.150 / 3.842 (übersprungen: 12 Duplikate)
Fertig:
Importiert: 2.130
Übersprungen: 12 (Duplikate)
Fehler: 0
Export-Fluss
$ archivmail export --from alice@firma.de \
--date-from 2024-01-01 \
--out /backup/export/
Key laden aus /etc/archivmail/keyfile
Xapian: 847 Mails gefunden (Filter: from=alice, date>=2024-01-01)
Exportiere nach /backup/export/
[████████████] 847 / 847
Fertig:
Exportiert: 847 EML-Dateien
Ziel: /backup/export/
JSON-Ausgabe (--json Flag)
{
"status": "done",
"imported": 2130,
"skipped": 12,
"errors": 0,
"duration_sec": 42
}
Xapian-Lock beim parallelen Betrieb
Daemon läuft (WritableDatabase hält Lock für Index-Worker)
│
CLI export → ReadonlyDatabase → kein Lock-Konflikt ✓
CLI import → Storage Coordinator → WritableDatabase
│
└── Lock bereits gehalten?
→ Warten (max. 30 Sek.) → dann Fehlermeldung:
"Index locked by running daemon. Stop daemon or retry."
Technische Entscheidungen
| Entscheidung | Begründung |
|---|---|
| Gleiche Binary, Subcommands | Kein separates CLI-Tool – archivmail import und archivmail serve teilen Code und Storage Coordinator |
| Direkter Speicherzugriff, kein HTTP | CLI läuft als archivmail-User mit Dateisystem-Zugriff – kein laufender Daemon nötig für Import/Export |
--dry-run |
Sicher testen ohne Daten zu verändern – wichtig für große Bulk-Imports |
--json Flag |
Maschinenlesbar für Cron-Jobs, Monitoring-Skripte, Ansible-Playbooks |
| Exit-Codes | 0 = Erfolg, 1 = Fehler – Standard für Shell-Skripting |
| Xapian ReadonlyDatabase für Export | Export kann parallel zum Daemon laufen ohne Lock-Konflikte |
Abhängigkeiten
| Paket | Zweck |
|---|---|
github.com/spf13/cobra |
Subcommand-CLI-Framework |
| Xapian CGo-Bindings | Volltext-Filter beim Export (bereits PROJ-5) |
Implementation Notes
- Subcommands in
cmd/archivmail/main.goviaos.Args[1]Router (kein cobra nötig) cmd_import.go: EML + MBOX Import,--file,--dir,--recursive,--dry-run,--jsoncmd_export.go: EML + MBOX Export, alle Filter,--force,--json- MBOX Parser in
pkg/mailparser/mbox.go(SplitMbox) - MBOX Export mit korrektem
>FromEscaping - Deployed auf
root@192.168.1.131, Daemon läuft
QA Test Results
To be added by /qa
Deployment
To be added by /deploy