Files
Emailsorter/docs/development/IMAP_IMPLEMENTATION_PLAN.md
ANDJ cbb225c001 feat: Gitea Webhook, IMAP, Settings & Deployment docs
- Webhook route and Gitea integration
- IMAP service and Nextcloud/Porkbun setup docs
- Settings UI improvements and API updates
- SSH/Webhook fix prompt for emailsorter.webklar.com
- Bootstrap, config and AI sorter updates
2026-01-31 15:00:00 +01:00

10 KiB
Raw Blame History

Implementierungsplan: IMAP / Porkbun / Nextcloud

Plan, um EmailSorter um einen IMAP-Provider (z.B. Porkbun) zu erweitern. Dann funktioniert die Sortierung auch für Postfächer, die in Nextcloud Mail genutzt werden.


Übersicht

Phase Inhalt Aufwand (grobe Schätzung)
1 IMAP-Bibliothek + Service-Grundgerüst 12 h
2 Datenbank + Connect-Route für IMAP 1 h
3 Sortier-Logik für IMAP (Ordner statt Labels) 23 h
4 Frontend: IMAP-Verbindung anlegen 12 h
5 Testen, Feinschliff, Doku 1 h

Phase 1: IMAP-Bibliothek und Service

Ziel: Backend kann sich per IMAP (z.B. Porkbun) verbinden, INBOX auflisten und E-Mails lesen.

1.1 Abhängigkeit hinzufügen

  • Datei: server/package.json
  • Aktion: Dependency imapflow hinzufügen (moderner IMAP-Client für Node, SSL-Support).
  • Befehl: npm install imapflow im Ordner server/.

1.2 Neuer Service

  • Datei (neu): server/services/imap.mjs
  • Inhalt (Kern-Interface):
    • Konstruktor: ImapService({ host, port, secure, user, password }) z.B. für Porkbun: host: 'imap.porkbun.com', port: 993, secure: true.
    • connect() Verbindung aufbauen (login).
    • listEmails(maxResults, fromSeq?) Nachrichten aus INBOX (z.B. per FETCH ENVELOPE), Rückgabe: { messages: [{ id, uid, ... }], nextSeq }.
    • getEmail(messageId) bzw. batchGetEmails(ids) eine bzw. mehrere Mails laden, Rückgabe-Format wie Gmail/Outlook: { id, headers: { from, subject }, snippet }.
    • close() Verbindung sauber trennen (LOGOUT).
  • Hinweis: IMAP nutzt oft UID oder Sequence Number als „id“; einheitlich als id nach außen geben (String), damit die Sortier-Route wie bei Gmail/Outlook arbeitet.

1.3 Akzeptanz Phase 1

  • Ein kleines Test-Script (z.B. server/scripts/test-imap.mjs) oder ein temporärer Route-Handler liest Umgebungsvariablen (IMAP_HOST, IMAP_PORT, IMAP_USER, IMAP_PASSWORD), baut ImapService auf, ruft listEmails(10) und getEmail(...) auf und loggt das Ergebnis. Keine Credentials im Repo nur .env / Umgebungsvariablen.

Phase 2: Datenbank und Connect-Route

Ziel: Ein neuer Account-Typ „imap“ kann angelegt werden; Zugangsdaten werden gespeichert.

2.1 Datenbank (Appwrite)

  • Datei: server/bootstrap-v2.mjs (oder separates Migrations-Script).
  • Aktion: In der Collection email_accounts optionale Attribute anlegen:
    • imapHost (String, optional)
    • imapPort (Integer, optional)
    • imapSecure (Boolean, optional)
  • Alternative (einfacher für nur Porkbun): Keine neuen Felder; Host/Port im Code fest (imap.porkbun.com, 993). Dann nur email + Passwort nötig; Passwort in bestehendem Feld accessToken speichern (semantisch „geheimer Token für IMAP“). Für spätere andere IMAP-Server die optionalen Felder nachziehen.

2.2 Connect-Route erweitern

  • Datei: server/routes/email.mjs
  • Route: POST /api/email/connect (bzw. die Route, die Accounts anlegt).
  • Aktionen:
    • Im Validierungs-Schema provider um 'imap' erweitern: z.B. rules.isIn('provider', ['gmail', 'outlook', 'demo', 'imap']).
    • Body für IMAP: mindestens userId, provider: 'imap', email, password (oder accessToken als Passwort). Optional: imapHost, imapPort, imapSecure.
    • Wenn provider === 'imap':
      • Host/Port/Secure aus Body oder Default (Porkbun: imap.porkbun.com, 993, true).
      • Passwort nicht loggen; in DB in accessToken (oder neuem Feld) speichern.
      • Optional: einmalig ImapService instanziieren, connect() + listEmails(1) aufrufen; bei Erfolg Account anlegen, sonst Fehler zurückgeben („Ungültige Anmeldedaten“).
    • Account-Dokument anlegen mit provider: 'imap', email, accessToken (= Passwort), ggf. imapHost, imapPort, imapSecure.

2.3 Middleware/Validierung

  • Datei: server/middleware/validate.mjs (falls dort Regeln liegen) oder direkt in der Route.
  • Aktion: Für IMAP ggf. zusätzliche Felder erlauben: imapHost, imapPort, imapSecure, password (oder wie du das Feld nennst).

2.4 Akzeptanz Phase 2

  • Per API-Client (Postman/curl) oder Frontend: POST mit provider: 'imap', email, password (und optional Host/Port) an /connect senden. Erwartung: 201, Account in Appwrite mit provider: 'imap'. Bei falschem Passwort: 4xx mit verständlicher Meldung.

Phase 3: Sortier-Logik für IMAP

Ziel: POST /api/email/sort funktioniert für Accounts mit provider === 'imap': E-Mails werden per KI kategorisiert und in IMAP-Ordner verschoben.

3.1 Ordner-Mapping

  • Konzept: Kategorien (z.B. vip, promotions, newsletters, archive) auf Ordner-Namen mappen. Z.B.:
    • archive / archive_read → Ordner Archive oder EmailSorter/Archive
    • promotionsPromotions oder EmailSorter/Promotions
    • usw.
  • Datei: Entweder in server/services/imap.mjs (Funktion getFolderNameForCategory(category)) oder in server/services/ai-sorter.mjs / Config. Einheitliche Liste (z.B. Objekt categoryToFolder) verwenden.

3.2 IMAP-Service erweitern

  • Datei: server/services/imap.mjs
  • Neue Methoden:
    • ensureFolder(folderName) Ordner anlegen (CREATE), falls nicht vorhanden; Fehler „existiert bereits“ ignorieren.
    • moveToFolder(messageId, folderName) Nachricht aus INBOX in den Ordner verschieben (MOVE oder COPY + DELETE aus INBOX).
    • Optional: markAsRead(messageId) falls „archive_read“ = verschieben + als gelesen markieren.

3.3 Sortier-Route erweitern

  • Datei: server/routes/email.mjs
  • Stelle: Dort, wo account.provider === 'gmail' und === 'outlook' abgefragt werden (und Demo).
  • Aktion: Neuen Block else if (account.provider === 'imap') hinzufügen:
    1. ImapService aus Account-Daten instanziieren (host, port, secure, user = email, password = accessToken).
    2. connect().
    3. In einer Schleife (analog Gmail/Outlook):
      • listEmails(batchSize, nextSeq) → Liste von Nachrichten.
      • batchGetEmails(ids) → From, Subject, Snippet.
      • Für jede E-Mail: KI-Kategorie ermitteln (bestehender AISorterService), dann ensureFolder(categoryToFolder[category]) und moveToFolder(id, folderName).
      • Bei „archive_read“ ggf. zusätzlich als gelesen markieren.
    4. Statistiken aktualisieren (wie bei Gmail/Outlook).
    5. close() aufrufen.
  • Fehlerbehandlung: Bei IMAP-Fehlern (z.B. „Invalid credentials“) sinnvolle Meldung zurückgeben und ggf. Account als „reconnect nötig“ markieren.

3.4 Akzeptanz Phase 3

  • Ein IMAP-Account ist verbunden. Aufruf von POST /api/email/sort mit userId und accountId. Erwartung: E-Mails aus INBOX werden kategorisiert und in die richtigen Ordner verschoben; Response enthält z.B. sortedCount und Kategorie-Statistiken. In Nextcloud Mail (oder anderem IMAP-Client) erscheinen die neuen Ordner und verschobenen Mails.

Phase 4: Frontend IMAP verbinden

Ziel: Nutzer können im UI „Anderes Postfach (IMAP)“ wählen und E-Mail + Passwort eingeben.

4.1 Verbindungs-Flow

  • Datei(en): Dort, wo heute Gmail/Outlook/Demo angeboten werden (z.B. Setup, Settings, „E-Mail verbinden“).
  • Aktion:
    • Neue Option „IMAP / anderes Postfach“ (oder „Porkbun / eigenes Postfach“).
    • Beim Klick: Formular anzeigen mit:
      • E-Mail (Pflicht)
      • Passwort / App-Passwort (Pflicht, Typ Passwort)
      • Optional (z.B. für Power-User): Host, Port, SSL (Checkbox); Defaults: imap.porkbun.com, 993, SSL an.
    • Submit: POST an Backend (z.B. /api/email/connect) mit provider: 'imap', email, password, optional imapHost, imapPort, imapSecure.
    • Bei Erfolg: Erfolgsmeldung, Account-Liste aktualisieren. Bei Fehler: Meldung anzeigen (z.B. „Anmeldung fehlgeschlagen prüfe E-Mail und Passwort“).

4.2 API-Client (Frontend)

  • Datei: z.B. client/src/lib/api.ts
  • Aktion: Methode connectImapAccount(userId, { email, password, imapHost?, imapPort?, imapSecure? }) hinzufügen, die POST /api/email/connect mit diesen Daten aufruft.

4.3 Akzeptanz Phase 4

  • Im UI „IMAP verbinden“ auswählen, E-Mail + Passwort eingeben, absenden. Account erscheint in der Account-Liste. Danach „Sortieren“ auslösbar und funktioniert wie in Phase 3.

Phase 5: Testen und Doku

  • Manuell: Mit einem echten Porkbun-Account (oder anderem IMAP) verbinden, Sortierung ausführen, in Nextcloud prüfen, ob Ordner und Mails stimmen.
  • Sicherheit: Prüfen, dass Passwörter nirgends geloggt werden und nicht im Frontend gespeichert werden.
  • Doku: docs/setup/IMAP_NEXTCLOUD_PORKBUN.md ggf. um „Konfiguration Porkbun“ und „Troubleshooting“ ergänzen (z.B. App-Passwort, 2FA).

Kurz-Checkliste

  • Phase 1: imapflow installiert, server/services/imap.mjs mit connect, listEmails, getEmail, close; Test mit .env-Credentials.
  • Phase 2: Appwrite email_accounts ggf. um IMAP-Felder erweitert; Connect-Route akzeptiert imap und speichert Zugangsdaten; Test: Account per API anlegen.
  • Phase 3: Ordner-Mapping; ImapService: ensureFolder, moveToFolder; Sortier-Route: Block für provider === 'imap'; Test: Sortierung für IMAP-Account.
  • Phase 4: Frontend-Option „IMAP“, Formular E-Mail/Passwort, API-Anbindung; Test: End-to-End Verbindung + Sortierung aus UI.
  • Phase 5: Manueller Test mit Porkbun/Nextcloud; Sicherheits-Check; Doku aktualisiert.

Dateien-Übersicht

Aktion Datei
Neu server/services/imap.mjs
Neu (optional) server/scripts/test-imap.mjs
Ändern server/package.json (imapflow)
Ändern server/bootstrap-v2.mjs (optional: IMAP-Attribute)
Ändern server/routes/email.mjs (provider imap, connect + sort)
Ändern server/middleware/validate.mjs (falls nötig)
Ändern Frontend: Connect-UI (Setup/Settings) + client/src/lib/api.ts
Ändern docs/setup/IMAP_NEXTCLOUD_PORKBUN.md (Feinschliff)

Wenn du mit Phase 1 startest, reicht zunächst: imapflow einbinden und imap.mjs mit connect + listEmails + getEmail implementieren und lokal mit Porkbun testen.