fa9f77782c
- SEC: requireMailAccess auf GET /api/threads/{threadID} — superadmin/domain_admin konnten Mail-Metadaten lesen
- SEC: requireMailAccess auf POST /api/export/ediscovery — superadmin/domain_admin konnten bis zu 10k EML exportieren
- SEC: V1-API user-role Keys müssen 'contact=' angeben — verhindert vollständige Tenant-Enumeration
- SEC: Domain-Regex-Validierung in handleCertACME vor filepath.Join und certbot-Aufruf
- docs: README und config.test.yml auf Manticore Search aktualisiert (kein Xapian mehr)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
832 lines
26 KiB
Markdown
832 lines
26 KiB
Markdown
# 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 |
|
||
| Manticore Search 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)
|
||
│ │ │
|
||
│ ▼ │──► Manticore Search (Port 9306)
|
||
│ Manticore Index │ (Volltext-Index)
|
||
└─────────────────────────────────────┘
|
||
▲
|
||
│ /api/*
|
||
┌─────────────────────────────────────┐
|
||
│ Next.js Frontend (Port 3000) │
|
||
│ / /search /mail/[id] /admin │
|
||
│ /imap │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
**Komponenten:**
|
||
|
||
| Komponente | Technologie | Beschreibung |
|
||
|------------|-------------|--------------|
|
||
| Backend | Go 1.24 | 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 | Manticore Search | 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.24 (CGO_ENABLED=0, keine C-Abhängigkeiten)
|
||
- Node.js ≥ 20
|
||
- PostgreSQL ≥ 14
|
||
- Manticore Search ≥ 6.x
|
||
|
||
**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_ENABLED=0) und Frontend (Next.js)
|
||
3. Stoppt Dienste, spielt Binaries ein, startet Dienste neu
|
||
4. Führt Datenbankmigrationen durch und reindexiert Manticore
|
||
|
||
### Manuell
|
||
|
||
```bash
|
||
# Quellcode
|
||
git clone https://gitea.perlbach24.de/scripte/archivmail.git /opt/archivmail/_build
|
||
cd /opt/archivmail/_build
|
||
|
||
# Backend bauen
|
||
CGO_ENABLED=0 go build -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} /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
|
||
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:
|
||
backend: manticore
|
||
manticore_dsn: "manticore@tcp(127.0.0.1:9306)/"
|
||
batch_size: 100
|
||
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
|
||
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:
|
||
backend: manticore # manticore (Standard)
|
||
manticore_dsn: "manticore@tcp(127.0.0.1:9306)/" # Manticore Search DSN
|
||
batch_size: 100 # Dokumente pro Index-Batch
|
||
|
||
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 : <zufälliges Passwort> ║
|
||
║ auditor : <zufälliges Passwort> ║
|
||
║ 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 Manticore Search 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`
|
||
|
||
**Suchsyntax:**
|
||
```
|
||
Rechnung 2024 # Mehrere Begriffe (AND)
|
||
"Angebot Projekt X" # Phrase
|
||
Rechn* # Wildcard
|
||
@from chef@firma.de # Feldsuche Absender
|
||
@subject Urlaubsantrag # Feldsuche Betreff
|
||
```
|
||
|
||
**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 `<iframe sandbox="allow-same-origin">` – JavaScript aus der Mail wird blockiert
|
||
- Externe Inhalte (Bilder, Tracking-Pixel) standardmäßig blockiert, per Klick freischaltbar
|
||
- Fallback auf Plaintext wenn kein HTML vorhanden
|
||
- Anhänge einzeln herunterladbar
|
||
- Originale E-Mail-Header aufklappbar
|
||
- Download als `.eml` (Rohdatei)
|
||
- Export als `.pdf`
|
||
- Integrity-Badge: ✅ verifiziert OK / ⬜ noch nicht geprüft / ❌ Integritätsfehler
|
||
|
||
**API-Endpunkte:**
|
||
```
|
||
GET /api/mails/{id} # E-Mail-Details inkl. Body
|
||
GET /api/mails/{id}/attachments/{index} # Anhang herunterladen
|
||
GET /api/mails/{id}/raw # Rohe EML-Datei
|
||
```
|
||
|
||
---
|
||
|
||
### E-Mail-Export
|
||
|
||
**Formate:**
|
||
|
||
| Format | Endpunkt | Beschreibung |
|
||
|--------|----------|--------------|
|
||
| PDF | `GET /api/export/pdf/{id}` | Einzelne Mail als PDF |
|
||
| EML | `GET /api/mails/{id}/raw` | Einzelne Mail als .eml |
|
||
| ZIP | `POST /api/export/zip` | Mehrere Mails + optional Anhänge |
|
||
|
||
**ZIP-Export:**
|
||
```json
|
||
POST /api/export/zip
|
||
{
|
||
"ids": ["sha256hash1", "sha256hash2"],
|
||
"attachments": true
|
||
}
|
||
```
|
||
|
||
ZIP enthält:
|
||
- Eine `.eml`-Datei pro E-Mail
|
||
- `manifest.csv` mit Metadaten (ID, Absender, Empfänger, Betreff, Datum, Größe)
|
||
- Anhänge wenn `attachments: true`
|
||
|
||
**Limits:**
|
||
- Max. 500 Mails pro ZIP-Export
|
||
- Jeder Export wird im Audit-Log erfasst
|
||
|
||
---
|
||
|
||
### Admin-Dashboard
|
||
|
||
Erreichbar unter `/admin` (nur Admins).
|
||
|
||
**Tabs:**
|
||
|
||
| Tab | Inhalt |
|
||
|-----|--------|
|
||
| **Dashboard** | CPU-Last (1/5/15 min), RAM, Festplatten, API-Status, SMTP-Status, Archiv-Statistiken, erste/letzte archivierte Mail |
|
||
| **Dienste** | Systemd-Dienste starten / stoppen / neustarten, externe Verbindungen sperren/freigeben |
|
||
| **Benutzer** | Benutzer anlegen, Rollen ändern, Passwort zurücksetzen, sperren/freischalten, löschen |
|
||
| **Audit-Log** | Alle Audit-Ereignisse mit Paginierung (25/Seite) |
|
||
| **Import** | EML/MBOX-Dateien hochladen, Fortschritt und Abschlussbericht |
|
||
| **Module** | Übersicht aller Features mit Deployment-Status |
|
||
|
||
**Dashboard API-Endpunkte:**
|
||
```
|
||
GET /api/admin/system/stats # CPU, RAM, Disks, erste/letzte Mail
|
||
GET /api/admin/smtp/status # SMTP-Daemon Status und Statistiken
|
||
GET /api/admin/storage/stats # Anzahl archivierter Mails und Gesamtgröße
|
||
GET /api/admin/services # Systemd-Dienste
|
||
POST /api/admin/services/{name}/action # start | stop | restart | enable | disable
|
||
```
|
||
|
||
---
|
||
|
||
### Audit-Log
|
||
|
||
Alle sicherheitsrelevanten Ereignisse werden lückenlos protokolliert.
|
||
|
||
**Erfasste Ereignisse:**
|
||
|
||
| Ereignis | Beschreibung |
|
||
|----------|--------------|
|
||
| `login_ok` | Erfolgreicher Login (Benutzer, IP) |
|
||
| `login_fail` | Fehlgeschlagener Login (Benutzer, IP) |
|
||
| `logout` | Logout |
|
||
| `search` | Suchanfrage (Suchbegriff, Benutzer) |
|
||
| `export_pdf` | PDF-Export einer E-Mail |
|
||
| `export_zip` | ZIP-Export (Anzahl Mails) |
|
||
| `user_create` | Neuer Benutzer angelegt |
|
||
| `user_update` | Benutzerdaten geändert |
|
||
| `user_delete` | Benutzer gelöscht |
|
||
| `imap_import` | IMAP-Import gestartet/abgeschlossen |
|
||
|
||
**Speicherung:** Parallel in PostgreSQL-Tabelle und Flat-File (`audit.log_path`)
|
||
|
||
**API:**
|
||
```
|
||
GET /api/audit?page=1&page_size=25&username=admin&event_type=login_ok
|
||
```
|
||
|
||
---
|
||
|
||
### Integritätsprüfung
|
||
|
||
Jede archivierte E-Mail wird regelmäßig auf Unverändertheit geprüft.
|
||
|
||
**Funktionsweise:**
|
||
1. Beim Speichern: SHA-256-Hash des Klartexts = Datei-ID
|
||
2. Beim Prüfen: Datei laden → entschlüsseln → SHA-256 berechnen → mit ID vergleichen
|
||
3. Bei Abweichung: Warnung im Log + `verify_ok = false` in DB
|
||
|
||
**Hintergrundprüfung:**
|
||
- Läuft beim Start einmal sofort durch
|
||
- Danach alle 5 Minuten wiederholt
|
||
- Ergebnisse in `emails`-Tabelle: `verify_ok`, `verified_at`
|
||
|
||
**Ergebnis in der E-Mail-Ansicht:**
|
||
```
|
||
✅ Integrität OK (geprüft: 2024-03-15 14:22:00)
|
||
❌ INTEGRITÄTSFEHLER – E-Mail wurde möglicherweise verändert
|
||
⬜ Noch nicht geprüft
|
||
```
|
||
|
||
---
|
||
|
||
### CLI Import & Export
|
||
|
||
Das `archivmail`-Binary kann auch ohne laufenden Daemon als CLI-Tool eingesetzt werden.
|
||
|
||
**Import:**
|
||
```bash
|
||
# Einzelne EML-Datei
|
||
archivmail import --file /pfad/zur/datei.eml
|
||
|
||
# MBOX-Datei
|
||
archivmail import --file /pfad/zur/datei.mbox
|
||
|
||
# Verzeichnis (alle EML/MBOX-Dateien)
|
||
archivmail import --dir /pfad/zum/verzeichnis
|
||
|
||
# Rekursiv
|
||
archivmail import --dir /pfad/ --recursive
|
||
|
||
# Simulation (kein Speichern)
|
||
archivmail import --file datei.eml --dry-run
|
||
|
||
# JSON-Ausgabe für Skripting
|
||
archivmail import --dir /pfad/ --json
|
||
```
|
||
|
||
**Export:**
|
||
```bash
|
||
# Alle Mails als EML in Verzeichnis
|
||
archivmail export --out /export/
|
||
|
||
# Als MBOX
|
||
archivmail export --out /export/archiv.mbox --format mbox
|
||
|
||
# Mit Filtern
|
||
archivmail export --out /export/ \
|
||
--from absender@firma.de \
|
||
--date-from 2024-01-01 \
|
||
--date-to 2024-12-31 \
|
||
--query "Rechnung"
|
||
|
||
# Vorhandene Dateien überschreiben
|
||
archivmail export --out /export/ --force
|
||
|
||
# JSON-Ausgabe
|
||
archivmail export --out /export/ --json
|
||
```
|
||
|
||
**Alle Befehle:**
|
||
```
|
||
archivmail serve Daemon starten (Standard)
|
||
archivmail import EML/MBOX importieren
|
||
archivmail import-piler Aus mailpiler migrieren
|
||
archivmail export Exportieren
|
||
archivmail version Version anzeigen
|
||
archivmail help Hilfe
|
||
```
|
||
|
||
---
|
||
|
||
### Mailpiler Migration
|
||
|
||
Vollständige Migration eines bestehenden mailpiler-Archivs nach archivmail.
|
||
|
||
**Methode 1: `pilerexport` (empfohlen)**
|
||
|
||
Erfordert das mailpiler-Tool `pilerexport` auf dem Server. Verarbeitet Entschlüsselung und Dekomprimierung automatisch.
|
||
|
||
```bash
|
||
# Alle Mails migrieren
|
||
archivmail import-piler --config /etc/archivmail/config.yml
|
||
|
||
# Mit Datumsfilter
|
||
archivmail import-piler --date-from 2020-01-01 --date-to 2024-12-31
|
||
|
||
# Benutzerdefinierter Export-Ordner (bleibt erhalten)
|
||
archivmail import-piler --export-dir /mnt/migration/export
|
||
```
|
||
|
||
**Methode 2: Direkt (ohne laufendes mailpiler)**
|
||
|
||
Liest `.m`-Dateien direkt aus dem mailpiler Store-Verzeichnis und verarbeitet sie ohne dass mailpiler installiert sein muss.
|
||
|
||
```bash
|
||
archivmail import-piler \
|
||
--method direct \
|
||
--store-dir /var/piler/store \
|
||
--key-file /var/piler/store/piler.key
|
||
```
|
||
|
||
Unterstützt:
|
||
- AES-256-CBC Entschlüsselung (IV in ersten 16 Bytes der Datei)
|
||
- zlib Dekomprimierung
|
||
- Mehrfache Fallback-Versuche für verschiedene mailpiler-Versionen
|
||
- Unkryptierte/unkomprimierte Dateien als letzter Fallback
|
||
|
||
**Auto-Modus (Standard):**
|
||
|
||
`--method auto` versucht zuerst `pilerexport`, fällt auf `direct` zurück:
|
||
|
||
```bash
|
||
archivmail import-piler --config /etc/archivmail/config.yml
|
||
```
|
||
|
||
**Alle Optionen:**
|
||
```
|
||
--config archivmail Konfigurationsdatei
|
||
--method auto | pilerexport | direct (Standard: auto)
|
||
--pilerexport Pfad zum pilerexport Binary (auto-erkennung)
|
||
--export-dir Ausgabeverzeichnis für pilerexport
|
||
--store-dir mailpiler Store-Verzeichnis (Standard: /var/piler/store)
|
||
--key-file mailpiler AES-Schlüsseldatei (Standard: /var/piler/store/piler.key)
|
||
--date-from Export ab Datum YYYY-MM-DD (pilerexport-Methode)
|
||
--date-to Export bis Datum YYYY-MM-DD (pilerexport-Methode)
|
||
--dry-run Simulation ohne Speichern
|
||
--json JSON-Ausgabe
|
||
```
|
||
|
||
**Typischer Migrationsablauf:**
|
||
```bash
|
||
# 1. Probe-Lauf
|
||
archivmail import-piler --dry-run --json
|
||
|
||
# 2. Migration mit Protokoll
|
||
archivmail import-piler 2>&1 | tee /var/log/archivmail/migration.log
|
||
|
||
# 3. Ergebnis prüfen
|
||
tail -20 /var/log/archivmail/migration.log
|
||
```
|
||
|
||
---
|
||
|
||
## REST API
|
||
|
||
Alle Endpunkte erfordern eine gültige Session (Cookie `archivmail_session` oder `Authorization: Bearer <token>`).
|
||
|
||
### Authentifizierung
|
||
|
||
| Methode | Endpunkt | Beschreibung |
|
||
|---------|----------|--------------|
|
||
| POST | `/api/auth/login` | Login: `{"username":"...","password":"..."}` |
|
||
| GET | `/api/auth/me` | Eingeloggter Benutzer |
|
||
| POST | `/api/auth/logout` | Session invalidieren |
|
||
|
||
### Suche & Mails
|
||
|
||
| Methode | Endpunkt | Beschreibung |
|
||
|---------|----------|--------------|
|
||
| GET | `/api/search` | Volltext-Suche |
|
||
| GET | `/api/mails/{id}` | E-Mail-Details |
|
||
| GET | `/api/mails/{id}/raw` | Rohe EML |
|
||
| GET | `/api/mails/{id}/attachments/{n}` | Anhang herunterladen |
|
||
|
||
### Export
|
||
|
||
| Methode | Endpunkt | Beschreibung |
|
||
|---------|----------|--------------|
|
||
| GET | `/api/export/pdf/{id}` | PDF-Export |
|
||
| POST | `/api/export/zip` | ZIP-Export |
|
||
|
||
### Admin
|
||
|
||
| Methode | Endpunkt | Beschreibung |
|
||
|---------|----------|--------------|
|
||
| GET | `/api/users` | Benutzerliste |
|
||
| POST | `/api/users` | Benutzer anlegen |
|
||
| PATCH | `/api/users/{id}` | Benutzer ändern |
|
||
| DELETE | `/api/users/{id}` | Benutzer löschen |
|
||
| GET | `/api/audit` | Audit-Log |
|
||
| GET | `/api/admin/smtp/status` | SMTP-Status |
|
||
| GET | `/api/admin/storage/stats` | Speicher-Statistiken |
|
||
| GET | `/api/admin/system/stats` | System-Ressourcen |
|
||
| GET | `/api/admin/services` | Dienste-Status |
|
||
| POST | `/api/admin/services/{name}/action` | Dienst steuern |
|
||
| POST | `/api/admin/upload` | EML/MBOX hochladen |
|
||
| GET | `/api/admin/upload/{jobID}/progress` | Upload-Fortschritt |
|
||
|
||
### IMAP
|
||
|
||
| Methode | Endpunkt | Beschreibung |
|
||
|---------|----------|--------------|
|
||
| GET | `/api/imap` | Verbindungen auflisten |
|
||
| POST | `/api/imap` | Verbindung anlegen |
|
||
| DELETE | `/api/imap/{id}` | Verbindung löschen |
|
||
| PATCH | `/api/imap/{id}` | Sync-Intervall setzen |
|
||
| POST | `/api/imap/test` | Verbindung testen |
|
||
| POST | `/api/imap/{id}/import` | Vollständigen Import starten |
|
||
| GET | `/api/imap/{id}/progress` | Import-Fortschritt |
|
||
| POST | `/api/imap/{id}/sync` | Manuellen Sync auslösen |
|
||
|
||
---
|
||
|
||
## In Entwicklung
|
||
|
||
| Funktion | Beschreibung |
|
||
|----------|--------------|
|
||
| **Ordner- & Label-Verwaltung** | E-Mails in Ordner ablegen und mit Labels versehen |
|
||
| **POP3-Import** | E-Mails von POP3-Servern importieren |
|
||
| **REST API (extern)** | Vollständige API für CRM-Anbindung und externe Systeme |
|
||
| **LDAP / Active Directory** | Benutzer-Authentifizierung über LDAP/AD statt lokaler Accounts |
|
||
|
||
---
|
||
|
||
## Update
|
||
|
||
```bash
|
||
# Auf dem Server als root:
|
||
bash /opt/archivmail/update.sh
|
||
|
||
# Oder direkt von Gitea:
|
||
curl -fsSL https://gitea.perlbach24.de/scripte/archivmail/raw/branch/main/update.sh | bash
|
||
```
|
||
|
||
Das Update-Skript führt automatisch durch:
|
||
1. Quellcode aktualisieren (git pull)
|
||
2. Backend neu bauen (CGO_ENABLED=0)
|
||
3. Frontend neu bauen (Next.js standalone)
|
||
4. Dienste stoppen
|
||
5. Binaries und Frontend einspielen
|
||
6. Datenbankmigrationen durchführen
|
||
7. Dienste starten und Status prüfen
|