# archivmail Ein selbst gehostetes, unternehmenstaugliches Mail-Archiv-System. Empfängt E-Mails über SMTP (BCC-Journaling), IMAP oder Datei-Upload, speichert sie verschlüsselt, indexiert sie für Volltextsuche und stellt sie über eine Web-Oberfläche zur Verfügung. --- ## Inhaltsverzeichnis - [Funktionsübersicht](#funktionsübersicht) - [Architektur](#architektur) - [Voraussetzungen](#voraussetzungen) - [Installation](#installation) - [Konfiguration](#konfiguration) - [Systemd-Dienste](#systemd-dienste) - [Funktionen im Detail](#funktionen-im-detail) - [Authentifizierung & Rollen](#authentifizierung--rollen) - [SMTP-Eingang (BCC-Journaling)](#smtp-eingang-bcc-journaling) - [IMAP-Import & Auto-Sync](#imap-import--auto-sync) - [EML/MBOX Web-Upload](#emlmbox-web-upload) - [Speicherung & Verschlüsselung](#speicherung--verschlüsselung) - [Volltext-Suche](#volltext-suche) - [E-Mail-Ansicht](#e-mail-ansicht) - [E-Mail-Export](#e-mail-export) - [Admin-Dashboard](#admin-dashboard) - [Audit-Log](#audit-log) - [Integritätsprüfung](#integritätsprüfung) - [CLI Import & Export](#cli-import--export) - [Mailpiler Migration](#mailpiler-migration) - [REST API](#rest-api) - [In Entwicklung](#in-entwicklung) - [Update](#update) --- ## Funktionsübersicht | Funktion | Status | |----------|--------| | Authentifizierung & Rollen (Admin / Auditor / User) | ✅ Deployed | | SMTP-Eingang via BCC-Journaling | ✅ Deployed | | IMAP-Import manuell & automatischer Sync | ✅ Deployed | | EML/MBOX Web-Upload (Admin) | ✅ Deployed | | AES-256-GCM verschlüsselte Speicherung | ✅ Deployed | | Xapian Volltext-Indexierung (async) | ✅ Deployed | | Volltext-Suche mit Filtern & Sortierung | ✅ Deployed | | E-Mail-Ansicht mit HTML-Sandbox | ✅ Deployed | | E-Mail-Export als EML / PDF / ZIP | ✅ Deployed | | Admin-Dashboard (CPU, RAM, Disk, Archiv-Stats) | ✅ Deployed | | Audit-Log (Suche, Login, Import, Export) | ✅ Deployed | | SHA-256 Integritätsprüfung | ✅ Deployed | | CLI: `archivmail import` / `export` | ✅ Deployed | | Mailpiler → archivmail Migration | ✅ Deployed | | Dienste-Verwaltung im Admin-Bereich | ✅ Deployed | | Ordner- & Label-Verwaltung | 🔄 In Progress | | POP3-Import | 🔄 In Progress | | REST API für externe Anbindung (CRM) | 🔄 In Progress | | LDAP / Active Directory | 🔄 In Progress | --- ## Architektur ``` ┌─────────────────────────────────────┐ │ archivmail (Go-Binary) │ │ │ Postfix BCC ──┤── SMTP-Daemon (Port 2525) │ IMAP-Server ──┤── IMAP-Importer + Scheduler │──► PostgreSQL Web-Upload ──┤── HTTP API (Port 8080) │ (Metadaten) │ │ │ │ ▼ │──► /var/archivmail/store │ Async Index Worker │ (AES-256-GCM) │ │ │ │ ▼ │──► /var/archivmail/xapian │ Xapian Index │ (Volltext-Index) └─────────────────────────────────────┘ ▲ │ /api/* ┌─────────────────────────────────────┐ │ Next.js Frontend (Port 3000) │ │ / /search /mail/[id] /admin │ │ /imap │ └─────────────────────────────────────┘ ``` **Komponenten:** | Komponente | Technologie | Beschreibung | |------------|-------------|--------------| | Backend | Go 1.23 | REST API, SMTP-Daemon, IMAP-Importer, Storage, Indexierung | | Frontend | Next.js 16 (TypeScript) | Web-Oberfläche, Tailwind CSS, shadcn/ui | | Datenbank | PostgreSQL | Metadaten, Benutzer, Audit-Log, Session-Blacklist | | Volltextsuche | Xapian | BM25-Ranking, Wildcards, Feldpräfixe | | Speicherung | Dateisystem | AES-256-GCM verschlüsselt, SHA-256 Integrität | --- ## Voraussetzungen **Server:** - Debian 12 / Ubuntu 22.04 oder neuer - Go ≥ 1.23 (mit CGO für Xapian) - Node.js ≥ 20 - PostgreSQL ≥ 14 - libxapian-dev **Ports (Standard):** - `8080` – HTTP API (Backend) - `3000` – Web-Frontend - `2525` – SMTP-Eingang (BCC-Journaling) --- ## Installation ### Automatisch (empfohlen) ```bash curl -fsSL https://gitea.perlbach24.de/scripte/archivmail/raw/branch/main/update.sh | bash ``` Das Skript: 1. Klont/aktualisiert den Quellcode 2. Baut Backend (Go + CGO/Xapian) und Frontend (Next.js) 3. Stoppt Dienste, spielt Binaries ein, startet Dienste neu 4. Führt Datenbankmigrationen durch ### Manuell ```bash # Quellcode git clone https://gitea.perlbach24.de/scripte/archivmail.git /opt/archivmail/_build cd /opt/archivmail/_build # Backend bauen CGO_ENABLED=1 go build -tags xapian -buildvcs=false \ -o /opt/archivmail/bin/archivmail ./cmd/archivmail/ # Frontend bauen npm ci && npm run build rsync -a --delete .next/standalone/ /opt/archivmail/web/ rsync -a --delete .next/static/ /opt/archivmail/web/.next/static/ ``` ### Konfigurationsdatei anlegen ```bash mkdir -p /etc/archivmail /var/archivmail/{store,astore,xapian} /var/log/archivmail cat > /etc/archivmail/config.yml << 'EOF' server: api_port: 8080 smtp_port: 2525 database: host: 127.0.0.1 port: 5432 name: archivmail user: archivmail password: SICHERES_PASSWORT sslmode: disable storage: store_path: /var/archivmail/store astore_path: /var/archivmail/astore xapian_path: /var/archivmail/xapian keyfile: /etc/archivmail/keyfile audit: log_path: /var/log/archivmail/audit.log retention_days: 0 smtp: enabled: true bind: ":2525" domain: "archivmail.firma.de" allowed_ips: - 127.0.0.1 - 192.168.1.0/24 # Postfix-Server-IP(s) api: bind: ":8080" secret: ZUFAELLIGER_JWT_SECRET_MINDESTENS_32_ZEICHEN index: path: /var/archivmail/xapian backend: xapian batch_size: 100 async_queue_size: 1000 EOF # AES-256 Schlüssel generieren dd if=/dev/urandom bs=32 count=1 > /etc/archivmail/keyfile chmod 600 /etc/archivmail/keyfile ``` --- ## Konfiguration ### Vollständige Konfigurationsreferenz ```yaml server: api_port: 8080 # HTTP-API Port smtp_port: 2525 # SMTP-Eingang Port (Fallback wenn smtp.bind nicht gesetzt) database: host: 127.0.0.1 port: 5432 name: archivmail user: archivmail password: "" sslmode: disable # disable | require | verify-full storage: store_path: /var/archivmail/store # Haupt-Mailspeicher (AES-256-GCM) astore_path: /var/archivmail/astore # Anhang-Speicher xapian_path: /var/archivmail/xapian # Xapian-Datenbankpfad (auch in index.path) keyfile: /etc/archivmail/keyfile # 32-Byte AES-Schlüsseldatei smtp: enabled: true bind: ":2525" # TCP-Adresse zum Lauschen domain: "archivmail" # EHLO-Domainname tls_cert: "" # Pfad zum TLS-Zertifikat (leer = kein TLS) tls_key: "" # Pfad zum TLS-Schlüssel max_size_mb: 50 # Maximale E-Mail-Größe in MB allowed_ips: # Nur diese IPs dürfen zustellen - 127.0.0.1 api: bind: ":8080" secret: "" # JWT-Signaturschlüssel (mind. 32 Zeichen, zufällig) index: path: /var/archivmail/xapian backend: xapian # xapian (einziger unterstützter Backend) batch_size: 100 # Dokumente pro Index-Batch async_queue_size: 1000 # Größe der asynchronen Index-Queue audit: log_path: /var/log/archivmail/audit.log retention_days: 0 # 0 = unbegrenzt logging: path: "" # leer = stdout level: info # debug | info | warn | error ``` --- ## Systemd-Dienste Das System läuft mit zwei Systemd-Units: | Dienst | Beschreibung | Port | |--------|--------------|------| | `archivmail` | Go-Backend (API + SMTP + IMAP-Scheduler) | 8080, 2525 | | `archivmail-web` | Next.js-Frontend | 3000 | ```bash # Status prüfen systemctl status archivmail archivmail-web # Logs journalctl -u archivmail -f journalctl -u archivmail-web -f # Neustart systemctl restart archivmail archivmail-web ``` --- ## Funktionen im Detail ### Authentifizierung & Rollen **Rollen:** | Rolle | Rechte | |-------|--------| | `admin` | Vollzugriff: Benutzer verwalten, IMAP einrichten, Dienste steuern, alles suchen/exportieren | | `auditor` | Audit-Log lesen, alle E-Mails suchen und exportieren | | `user` | Nur eigene E-Mails suchen und lesen (Matching auf E-Mail-Adresse) | **Sicherheit:** - Passwörter mit bcrypt (Cost 12) - Sessions als httpOnly SameSite=Strict Cookie (`archivmail_session`) - JWT mit zufälligem JTI (kryptografische Entropie, 16 Byte) - Token-Blacklist in PostgreSQL (Logout invalidiert Token sofort) - Rate-Limiting: max. 5 Fehlversuche in 15 Minuten → HTTP 429 - Login-Versuche in `login_attempts`-Tabelle protokolliert - Letzter Login wird gespeichert (`last_login_at`) **Erstmalige Einrichtung:** Beim ersten Start werden automatisch zwei Benutzer mit zufälligen Passwörtern angelegt: ``` ╔══════════════════════════════════════════════════════════════╗ ║ ARCHIVMAIL — ERSTMALIGE EINRICHTUNG ║ ║ Initiale Zugangsdaten (NUR EINMAL ANGEZEIGT): ║ ║ admin : ║ ║ auditor : ║ ║ Passwörter sofort nach dem ersten Login ändern! ║ ╚══════════════════════════════════════════════════════════════╝ ``` --- ### SMTP-Eingang (BCC-Journaling) Der eingebettete SMTP-Daemon empfängt E-Mails von Postfix (oder anderem MTA) über BCC-Weiterleitung. **Funktionsweise:** ``` Absender → Postfix → Empfänger │ └── always_bcc → archivmail SMTP (Port 2525) │ ▼ Speicherung + Indexierung ``` **Postfix-Konfiguration (`/etc/postfix/main.cf`):** ``` # Alle ausgehenden Mails archivieren: always_bcc = archiv@archivmail-host # Oder granular per Nutzer: sender_bcc_maps = hash:/etc/postfix/sender_bcc ``` **Sicherheit:** - Kein SMTP AUTH – Vertrauen ausschließlich über IP-Allowlist - IP-Allowlist in `smtp.allowed_ips` konfigurieren - 250 OK erst nach erfolgreicher Speicherung (kein Datenverlust) - 250 OK auch bei Duplikaten (Postfix stellt nicht erneut zu) - Maximale E-Mail-Größe konfigurierbar (`smtp.max_size_mb`, Standard: 50 MB) - Optionale TLS/STARTTLS-Unterstützung (`smtp.tls_cert` / `smtp.tls_key`) **API-Endpunkt:** ``` GET /api/admin/smtp/status ``` --- ### IMAP-Import & Auto-Sync E-Mails von IMAP-Postfächern importieren – einmalig (Altbestände) oder automatisch als Hintergrundjob. **Verbindung einrichten (Web-UI unter `/imap`):** | Feld | Beschreibung | |------|--------------| | Name | Bezeichnung der Verbindung | | Host / Port | IMAP-Server-Adresse | | TLS | `ssl` (IMAPS), `starttls`, `none` | | Benutzername / Passwort | IMAP-Zugangsdaten (Passwort AES-256-GCM verschlüsselt in DB) | | Ausgeschlossene Ordner | Ordner die nicht importiert werden | **Sync-Intervall:** | Wert | Verhalten | |------|-----------| | 0 | Automatischer Sync deaktiviert | | 5–1440 | Sync alle N Minuten (Hintergrund-Goroutine) | **Inkrementeller Sync:** - UID-basiert: Nur neue Nachrichten seit letztem Sync werden heruntergeladen - Exponentielles Backoff bei Fehlern: 1s → 60s → 300s (3 Versuche) - Duplikat-Erkennung via Content-Hash **API-Endpunkte:** ``` GET /api/imap # Verbindungen auflisten POST /api/imap # Neue Verbindung anlegen DELETE /api/imap/{id} # Verbindung löschen PATCH /api/imap/{id} # Sync-Intervall ändern POST /api/imap/test # Verbindung testen + Ordner auflisten POST /api/imap/{id}/import # Vollständigen Import starten GET /api/imap/{id}/progress # Import-Fortschritt abfragen POST /api/imap/{id}/sync # Manuellen inkrementellen Sync auslösen ``` --- ### EML/MBOX Web-Upload E-Mails direkt über die Admin-Oberfläche hochladen (Tab „Import" unter `/admin`). **Unterstützte Formate:** - `.eml` – einzelne RFC-2822 E-Mail - `.mbox` – MBOX-Datei mit beliebig vielen E-Mails **Ablauf:** 1. Dateien per Drag-and-Drop oder Datei-Dialog hochladen 2. Backend startet Hintergrund-Import-Job, gibt sofort `job_id` zurück 3. Frontend pollt alle 1,5 Sekunden den Fortschritt 4. Abschlussbericht: Importiert / Übersprungen (Duplikate) / Fehler **API-Endpunkte:** ``` POST /api/admin/upload # Multipart-Upload starten GET /api/admin/upload/{jobID}/progress # Fortschritt abfragen ``` --- ### Speicherung & Verschlüsselung Alle E-Mails werden verschlüsselt auf dem Dateisystem gespeichert. **Verschlüsselung:** - Algorithmus: AES-256-GCM (authentifizierte Verschlüsselung) - Schlüssel: 32-Byte-Datei (`keyfile` in Konfiguration) - Nonce: 12 Byte, kryptografisch zufällig, pro E-Mail neu generiert - Dateiformat: `[12-Byte Nonce][verschlüsselte Daten]` **Datei-ID / Integrität:** - Jede E-Mail erhält als ID den SHA-256-Hash des Klartexts - Duplikat-Erkennung: gleicher Hash → gleiche Datei, Speicherung übersprungen - ID dient gleichzeitig als Integritätsnachweis **PostgreSQL-Metadaten (`emails`-Tabelle):** | Spalte | Typ | Beschreibung | |--------|-----|--------------| | `id` | TEXT PK | SHA-256 Hash des E-Mail-Rohtexts | | `from_addr` | TEXT | Absender | | `to_addrs` | TEXT[] | Empfänger | | `subject` | TEXT | Betreff | | `message_id` | TEXT | RFC-2822 Message-ID | | `mail_date` | TIMESTAMPTZ | Sendedatum | | `size_bytes` | INTEGER | Größe in Bytes | | `has_attachments` | BOOLEAN | Hat Anhänge | | `stored_at` | TIMESTAMPTZ | Archivierungszeitpunkt | | `indexed_at` | TIMESTAMPTZ | Indexierungszeitpunkt (NULL = ausstehend) | | `verify_ok` | BOOLEAN | Letztes Integritätsprüfungsergebnis | | `verified_at` | TIMESTAMPTZ | Zeitpunkt der letzten Prüfung | **Async Index Worker:** - Eingehende E-Mails werden sofort gespeichert - Indexierung erfolgt asynchron über einen Go-Channel (Queue-Größe: 1000) - Backfill beim Start: Nicht indexierte E-Mails werden nachindexiert --- ### Volltext-Suche Suche über alle archivierten E-Mails per Xapian-Index unter `/search`. **Suchfelder:** - Freitext (durchsucht Betreff, Body, Absender, Empfänger, Anhangsnamen) - Absender-Filter (`from`) - Empfänger-Filter (`to`) - Zeitraum (`date_from` / `date_to`, ISO 8601: `2024-01-01`) - Nur Mails mit Anhängen (`has_attachment`) - Sortierung: `date_desc` (Standard), `date_asc`, `relevance` **Xapian-Suchsyntax:** ``` Rechnung AND 2024 # UND-Verknüpfung "Angebot Projekt X" # Phrase Rechn* # Wildcard from:chef@firma.de # Feldpräfix subject:Urlaubsantrag # Feldpräfix ``` **Paginierung:** 25 Ergebnisse pro Seite (konfigurierbar via `page_size`) **Rollenfilter:** - `user`: sieht nur E-Mails an/von der eigenen E-Mail-Adresse - `admin` / `auditor`: sieht alle E-Mails **API-Endpunkt:** ``` GET /api/search?q=...&from=...&to=...&date_from=...&date_to=...&has_attachment=true&sort=date_desc&page=1&page_size=25 ``` --- ### E-Mail-Ansicht Vollständige Darstellung einer archivierten E-Mail unter `/mail/[id]`. **Funktionen:** - HTML-Body original dargestellt in `