2026-04-26 16:24:24 -05:00
2026-04-26 16:24:24 -05:00
2026-04-26 13:47:35 -05:00
2026-04-26 16:05:04 -05:00
2026-04-26 13:47:35 -05:00
2026-04-26 14:36:12 -05:00
2026-04-26 13:47:35 -05:00

MailAdmin MVP

Erste Version einer Admin-Webapp für dein DMS/SES/S3/SQS/DynamoDB-Mail-System.

Die App ist bewusst node-orientiert gebaut: Sie läuft auf node1, node2, usw. und entdeckt die Domains dynamisch aus dem lokalen Docker Mailserver. Dadurch ist sie geeignet für dein Szenario, bei dem Domains neu hinzukommen oder zwischen Nodes umziehen.

Was diese Version bereits kann

  • Login mit eigenem Admin-User
  • PostgreSQL als Admin-Datenbank
  • dynamische Domain-Erkennung über docker exec mailserver setup email list
  • Domains pro Node speichern: node1, node2, ...
  • Mailboxen anzeigen
  • Mailbox anlegen
  • Mailbox löschen
  • Passwort zurücksetzen
  • Speicherverbrauch pro Inbox scannen
  • Forward- und Auto-Reply-Regeln in DynamoDB bearbeiten
  • Blocklisten in DynamoDB bearbeiten
  • Audit Log für Admin-Aktionen
  • Frontend wird vom Backend direkt ausgeliefert
  • Docker Compose Deployment auf dem Mailserver

Warum dynamische Domains berücksichtigt sind

Die Domainliste ist nicht hart codiert. Beim Start und bei jedem manuellen Resync liest die App die DMS-Accounts aus:

docker exec mailserver setup email list

Daraus werden Domains und Mailboxen abgeleitet und in Postgres gespiegelt.

Wenn eine Domain später auf einen anderen Node umzieht, passiert Folgendes:

  • auf dem alten Node werden die lokalen Mailboxen nach einem Resync als missing_on_node markiert
  • auf dem neuen Node wird dieselbe Domain beim Resync als active mit current_node=node2 erkannt
  • die App-Codebasis bleibt identisch; nur .env unterscheidet NODE_NAME=node1 oder NODE_NAME=node2

Struktur

mailadmin-mvp/
  backend/
    src/
      server.ts              Express App, API, static frontend
      config.ts              zentrale Konfiguration über Env Vars
      db.ts                  Postgres Pool + Migration + Initial Admin
      routes/
        auth.ts              Login/Logout/Me
        domains.ts           Domains dynamisch vom DMS syncen/anzeigen
        mailboxes.ts         Mailbox CRUD, Usage, Rules, Blocklist
        audit.ts             Audit Log API
      services/
        dms.ts               DMS Docker Integration + Usage Scan
        sync.ts              Sync DMS -> Postgres
        dynamodb.ts          email-rules + email-blocked-senders
        audit.ts             Audit helper
      utils/
        email.ts             Email/domain/local-part helpers
        shell.ts             sicherer execFile wrapper
    migrations/001_init.sql  PostgreSQL Schema
    Dockerfile               Backend + Frontend Image
  frontend/
    index.html               Single Page App
    app.js                   UI Logik ohne Build-Step
    styles.css               einfache Admin-Oberfläche
  deploy/
    caddy/                   Caddy-Hinweise
    scripts/                 Snippet-Hilfe für update-caddy-certs.sh
  docker-compose.yml         App + Postgres
  .env.example               Beispiel-Konfiguration

Installation auf node1

cd /home/aknuth/git/email-amazon
unzip mailadmin-mvp.zip
cd mailadmin-mvp
cp .env.example .env
nano .env

Wichtige Werte in .env:

MAILADMIN_DB_PASSWORD=ein-sicheres-passwort
MAILADMIN_JWT_SECRET=sehr-langes-random-secret
MAILADMIN_ADMIN_EMAIL=admin@bayarea-cc.com
MAILADMIN_ADMIN_PASSWORD=StartPassword123!
NODE_NAME=node1
NODE_HOSTNAME=node1.email-srvr.com
DMS_CONTAINER=mailserver
AWS_REGION=us-east-2
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...

Start:

docker compose up -d --build

Logs:

docker logs -f mailadmin

Installation auf node2

Gleicher Code, andere .env:

NODE_NAME=node2
NODE_HOSTNAME=node2.email-srvr.com

Die Domainliste wird auch dort aus dem lokalen DMS gelesen.

Caddy: mailadmin.{DOMAIN}

Dein bestehendes update-caddy-certs.sh generiert bereits dynamisch Domain-Blöcke. Ergänze im Domain-Loop zusätzlich diesen Block:

# MailAdmin UI
mailadmin.DOMAIN_HERE {
    encode gzip
    reverse_proxy mailadmin:3000
}

Im Script sieht das ungefähr so aus:

OUTPUT="${OUTPUT}# MailAdmin UI\n"
OUTPUT="${OUTPUT}mailadmin.${domain} {\n"
OUTPUT="${OUTPUT}    encode gzip\n"
OUTPUT="${OUTPUT}    reverse_proxy mailadmin:3000\n"
OUTPUT="${OUTPUT}}\n\n"

Danach:

cd /home/aknuth/git/email-amazon/caddy
./update-caddy-certs.sh
docker exec caddy caddy reload --config /etc/caddy/Caddyfile

Wichtige Sicherheitshinweise

Diese MVP-Version mountet /var/run/docker.sock, damit der Backend-Container docker exec mailserver ... ausführen kann. Das ist praktisch, aber mächtig. Für die nächste Version wäre ein kleiner dedizierter Local-Agent mit begrenzten Operationen sicherer.

Das Admin-Passwort wird nur beim ersten Start erstellt. Wenn du MAILADMIN_ADMIN_PASSWORD später änderst, wird der vorhandene User nicht überschrieben. Das ist Absicht.

API Kurzüberblick

POST /api/auth/login
POST /api/auth/logout
GET  /api/auth/me

GET  /api/domains?resync=true
POST /api/domains/resync

GET    /api/mailboxes?domain=example.com
POST   /api/mailboxes
DELETE /api/mailboxes/:email
POST   /api/mailboxes/:email/password
POST   /api/mailboxes/usage/rescan

GET /api/mailboxes/:email/rules
PUT /api/mailboxes/:email/rules

GET /api/mailboxes/:email/blocklist
PUT /api/mailboxes/:email/blocklist

GET /api/audit

Nächste sinnvolle Ausbaustufen

  1. Domain-Detailseite mit DNS/SES/S3/SQS/Caddy Status
  2. Admin-User Verwaltung im UI
  3. Quotas pro Mailbox
  4. Soft-Delete mit Retention statt hartem Löschen
  5. Outbound Reporting über Postfix Logs und später SES Events
  6. Node-Migration Workflow: Domain gezielt von node1 auf node2 markieren und prüfen
Description
No description provided
Readme 275 KiB
Languages
TypeScript 63.3%
JavaScript 28.1%
CSS 6.3%
Dockerfile 1.2%
HTML 0.6%
Other 0.5%