d360c9a5ba
- Systemauslastungs-Sektion wird immer gerendert (nicht nur bei Erfolg) - Fehlermeldung wenn /api/admin/system/stats nicht erreichbar ist - Feature-Status auf In Review gesetzt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
9.2 KiB
9.2 KiB
PROJ-3: E-Mail-Import: IMAP-Verbindung
Status: In Review
Created: 2026-03-12 Last Updated: 2026-03-14
Dependencies
- Requires: PROJ-1 (Authentifizierung) – nur Admins verwalten IMAP-Verbindungen
- Requires: PROJ-5 (Speicherung & Indexierung) – importierte E-Mails werden gespeichert
User Stories
- Als Admin oder User möchte ich einen IMAP-Server konfigurieren (Host, Port, Zugangsdaten), damit das System E-Mails von dort abholen kann.
- Als Admin oder User möchte ich beim ersten Verbinden alle vorhandenen E-Mails eines Postfachs importieren (Initial-Import).
- Als System möchte ich beim Verbinden automatisch Junk- und Trash-Ordner per IMAP erkennen und ausschließen, damit kein Spam ins Archiv gelangt. Alle anderen Ordner werden importiert.
- Als Admin oder User möchte ich den Verbindungsstatus sehen (verbunden, Fehler, letzter Sync), damit ich Probleme erkennen kann.
- Als System möchte ich die IMAP-Verbindung testen bevor sie gespeichert wird, damit Konfigurationsfehler früh erkannt werden.
- Als Admin möchte ich alle IMAP-Konten aller Nutzer sehen und verwalten können.
- Als User möchte ich nur meine eigenen IMAP-Konten sehen und verwalten (keine fremden).
Acceptance Criteria
- Konfigurationsformular: Host, Port, TLS/SSL, Benutzername, Passwort
- Verbindungstest vor dem Speichern (Timeout: 10 Sekunden)
- Passwörter werden verschlüsselt in der Datenbank gespeichert (nie im Klartext)
- Automatische Ordner-Erkennung via IMAP LIST-EXTENDED (RFC 6154 Special-Use Flags:
\Junk,\Trash) - Fallback auf bekannte Ordnernamen wenn Special-Use Flags fehlen:
Junk,Spam,Trash,Deleted Items,Deleted Messages,Papierkorb - Erkannte Ausschluss-Ordner werden dem Admin vor dem Import angezeigt (mit Option zur manuellen Korrektur)
- Initial-Import: alle Ordner außer Junk/Trash – Ordnerstruktur wird verworfen, nur E-Mail-Inhalt archiviert
- Fortschrittsanzeige während Initial-Import
- Duplikate (Message-ID) werden übersprungen
- Verbindungsstatus-Übersicht im Admin-Bereich
Edge Cases
- IMAP-Server nicht erreichbar → Fehlermeldung mit Retry-Option
- Falsche Zugangsdaten → klare Fehlermeldung
- IMAP-Server trennt Verbindung während Import → automatischer Reconnect
- Postfach mit 200.000+ E-Mails → paginierter Import, kein Speicher-Overflow
- OAuth2/XOAUTH2 für Gmail/Outlook → als spätere Erweiterung markiert (nicht MVP)
Technical Requirements
- Verbindungsmodi:
SSL/TLS– direkte TLS-Verbindung ab dem ersten Byte (Port 993)STARTTLS– Verbindung startet unverschlüsselt, wird per STARTTLS-Befehl auf TLS hochgestuft (Port 143)None– unverschlüsselt, nur für lokale/Testumgebungen
- IMAP IDLE-Unterstützung für Echtzeit-Benachrichtigungen (optional)
- Zugangsdaten AES-256-GCM verschlüsselt in der DB (gleicher Key wie Mail-Store)
Tech Design (Solution Architect)
Komponentenstruktur
Next.js Frontend (Admin-Bereich):
/admin/imap
├── IMAP-Verbindungsliste
│ └── VerbindungsCard (pro Konto)
│ ├── Name, Host, Status (OK / Fehler)
│ ├── Letzter Import + Anzahl importierter Mails
│ └── Aktionen: Bearbeiten / Löschen / Import starten
├── Verbindung-Formular (anlegen / bearbeiten)
│ ├── Host, Port, TLS-Auswahl
│ ├── Benutzername, Passwort
│ └── [Verbindung testen] Button
├── Ordner-Vorschau (nach erfolgreichem Test)
│ ├── Automatisch erkannte Ausschlüsse (Junk/Trash) – markiert
│ └── Manuelle Korrektur möglich (Checkbox pro Ordner)
└── Import-Fortschrittsanzeige
├── Fortschrittsbalken (X von Y E-Mails)
├── Aktueller Status
└── Abschlussbericht (importiert / übersprungen / Fehler)
Go Backend:
IMAP-Dienst
├── Verbindungsverwaltung
│ ├── POST /api/admin/imap ← Verbindung anlegen
│ ├── POST /api/admin/imap/test ← testen + Ordner-Erkennung
│ ├── GET /api/admin/imap ← alle Verbindungen auflisten
│ └── DELETE /api/admin/imap/{id} ← Verbindung löschen
│
├── IMAP-Client
│ ├── TLS/SSL + STARTTLS Handler
│ ├── Ordner-Erkenner (Special-Use + Fallback)
│ ├── SELECT + FETCH UID-basiert
│ └── Reconnect-Handler
│
├── Import-Worker (Hintergrund-Goroutine)
│ ├── Batch-weise FETCH (50 Mails pro Batch)
│ ├── Duplikat-Check (Message-ID)
│ ├── → Storage Coordinator (PROJ-5)
│ └── Fortschritt in DB schreiben
│
└── GET /api/admin/imap/{id}/progress ← Polling durch Frontend
Ordner-Erkennungslogik
IMAP-Verbindung aufgebaut
│
▼
LIST-EXTENDED "" "*" RETURN (SPECIAL-USE) ← RFC 6154
│
├── \Junk gefunden? → Ordner ausschließen
├── \Trash gefunden? → Ordner ausschließen
└── Flags nicht unterstützt? → Fallback:
Ordnernamen prüfen (case-insensitive):
"junk", "spam", "trash", "deleted items",
"deleted messages", "papierkorb"
→ übereinstimmende Ordner ausschließen
│
▼
Ordnerliste mit Markierungen an Frontend:
INBOX ✓ (wird importiert)
Sent ✓ (wird importiert)
Drafts ✓ (wird importiert)
Junk [\Junk erkannt] ✗ (ausgeschlossen)
Trash [\ Trash erkannt] ✗ (ausgeschlossen)
│
▼
Admin kann Ausschlüsse manuell korrigieren
→ Speichern → Import starten
Importfluss
Import-Worker startet
│
▼
Für jeden nicht ausgeschlossenen Ordner:
│
├── IMAP UID SEARCH ALL → alle UIDs
│
└── Batch-weise (50 UIDs):
├── IMAP FETCH RFC822
├── Message-ID Duplikat? → überspringen
└── Storage Coordinator (PROJ-5)
→ verschlüsseln + speichern + indexieren
│
▼
Fortschritt in DB → Frontend pollt alle 2 Sek.
Datenmodell
Tabelle imap_accounts:
| Feld | Beschreibung |
|---|---|
id |
Interne ID |
name |
Bezeichnung |
host |
IMAP-Hostname |
port |
Port (143 / 993) |
tls |
ssl / starttls / none |
username |
IMAP-Benutzername |
password_enc |
AES-256-GCM verschlüsseltes Passwort |
excluded_folders |
JSON-Array ausgeschlossener Ordner |
last_import_at |
Zeitpunkt des letzten Imports |
last_import_count |
Anzahl importierter Mails |
status |
idle / running / error |
error_msg |
Letzter Fehler |
Technische Entscheidungen
| Entscheidung | Begründung |
|---|---|
| RFC 6154 Special-Use Flags | Standard-Weg für Junk/Trash-Erkennung – funktioniert bei Dovecot, Exchange, Gmail |
| Fallback auf Ordnernamen | Ältere oder nicht-standardkonforme Server kennen Special-Use nicht – Fallback deckt die gängigsten Namen ab |
| Admin-Korrektur möglich | Automatik kann irren – Admin sieht die Erkennungsergebnisse und kann vor dem Import eingreifen |
| Nur Ausschlüsse konfigurieren | Einfacher als Whitelist: alle Ordner importieren außer den erkannten Ausreißern |
| UID-basierter Fetch | Bei Reconnect kann genau dort weitergemacht werden wo abgebrochen wurde |
| Batch-Größe 50 | Balance zwischen RAM-Verbrauch und IMAP-Roundtrips |
Abhängigkeiten
| Paket | Zweck |
|---|---|
github.com/emersion/go-imap |
IMAP-Client (RFC 6154 LIST-EXTENDED, TLS, FETCH) |
Implementation Notes (2026-03-14)
Go Backend
internal/imap/store.go: DB CRUD forimap_accountstable with AES-256-GCM password encryption. Auto-migrates table on startup. Index onownercolumn.internal/imap/client.go: IMAP client wrapper usinggo-imap/v2(beta.8). Supports SSL/STARTTLS/plaintext. Folder detection via RFC 6154 special-use flags with name-based fallback.internal/imap/importer.go: Background import worker. Fetches all UIDs per folder, processes in batches of 50, stores viastorage.Store.Save()(SHA256 dedup), indexes viaindex.Indexer.IndexSync(). Progress written to DB for frontend polling.internal/api/server.go: 6 new IMAP endpoints (GET/POST /api/imap,DELETE /api/imap/{id},POST /api/imap/test,POST /api/imap/{id}/import,GET /api/imap/{id}/progress). All auth-protected, ownership enforced (admin sees all, user sees own).cmd/archivmail/main.go: Wires IMAP store and importer into API server.
Frontend
src/app/imap/page.tsx: Full IMAP management page with account cards, add dialog (with connection test and folder preview), progress polling, delete confirmation.src/lib/api.ts: IMAP types and 6 API functions.src/components/navbar.tsx: Added "IMAP Import" link for all roles.
Deviations from spec
- Routes use
/api/imap(not/api/admin/imap) since all authenticated users can manage their own IMAP accounts. - Using
go-imap/v2beta.8 (latest available) instead of beta.5. - IMAP page at
/imap(not/admin/imap) to match the route pattern.
QA Test Results
To be added by /qa
Deployment
Deployed to 192.168.1.131 on 2026-03-14. Both archivmail and archivmail-web services restarted and active. Database table imap_accounts auto-created with index.