mherrlein 93f7d78c27
Docker / build (push) Canceled after 0s
Add webhook bearer token support
2026-09-02 15:17:05 +02:00
2025-03-31 23:32:29 +02:00
2026-09-02 15:17:05 +02:00
2026-09-02 15:17:05 +02:00
🚀📥
2024-09-19 21:51:50 +08:00
2026-09-02 15:17:05 +02:00
2026-09-02 15:17:05 +02:00
2025-03-31 23:34:12 +02:00
2026-09-02 12:15:55 +02:00
2024-09-22 15:57:24 +10:00
2026-09-02 15:17:05 +02:00

Inbound Email (SMTP) to Webhook

Diese Version ist eine gehärtete Weiterentwicklung des ursprünglichen Projekts. Sie nimmt E-Mails über SMTP an, parst Inhalt und Header, lädt Anhänge optional nach Amazon S3 und sendet die Nachricht an einen HTTP(S)-Webhook.

Originalentwickler: Martin Krivosija LinkedIn

Dieses Repository ist von kriiv/inbound-email geforkt und wird hier als eigenständige, gehärtete Weiterentwicklung gepflegt.

Das Repository liegt unter:

https://git.hacker.schule/mherrlein/inbound-email

Funktionsweise

Der Zustellweg lautet:

SMTP -> mailparser -> optional S3 -> persistenter Spool -> Webhook

Eine Nachricht wird vor der SMTP-Bestätigung als JSON unter SPOOL_DIR/pending gespeichert. Erst nach erfolgreicher Webhook-Antwort wird sie gelöscht. Dadurch überlebt die Zustellung Neustarts und vorübergehende Webhook-Fehler.

Die Zustellung ist „at least once“. Wenn der Prozess nach erfolgreicher Webhook-Annahme, aber vor dem Löschen der Spool-Datei abstürzt, kann die Nachricht doppelt zugestellt werden. Der Webhook sollte deshalb idempotent sein.

Voraussetzungen

  • Node.js 18 oder neuer und npm
  • ein erreichbarer HTTP(S)-Webhook
  • AWS-S3-Zugangsdaten und ein Bucket, wenn Anhänge gespeichert werden sollen
  • bei Produktion ein eigener Dienstbenutzer, z. B. smtpwebhook

Installation

git clone https://git.hacker.schule/mherrlein/inbound-email.git
cd inbound-email
npm ci
cp .env.example .env
${EDITOR:-vi} .env
chmod 640 .env

WEBHOOK_URL muss gesetzt werden. Für einen lokalen Test kann ein nicht privilegierter Port verwendet werden:

PORT=25252 \
SPOOL_DIR=/tmp/smtpwebhook-spool \
LOG_DIR=/tmp/smtpwebhook-logs \
npm start

Produktive Spool- und Log-Verzeichnisse müssen dem Dienstbenutzer gehören und restriktiv geschützt sein:

install -d -o smtpwebhook -g smtpwebhook -m 700 \
  /var/lib/smtpwebhook \
  /var/lib/smtpwebhook/spool/pending \
  /var/lib/smtpwebhook/spool/failed \
  /var/lib/smtpwebhook/logs

Konfiguration

Die Anwendung liest .env aus dem Arbeitsverzeichnis. WEBHOOK_URL ist zwingend erforderlich und hat keinen öffentlichen Defaultwert.

Variable Bedeutung Standardwert
WEBHOOK_URL Ziel-URL für die geparste Nachricht erforderlich
WEBHOOK_BEARER_TOKEN Optionaler Bearer Token für den Authorization-Header des Webhooks nicht gesetzt
PORT SMTP-Port 25 (Produktion: 2525)
SMTP_SECURE TLS/SMTPS beim Verbindungsaufbau false
TLS_KEY_PATH TLS-Privatschlüssel bei aktiviertem TLS keiner
TLS_CERT_PATH TLS-Zertifikat bei aktiviertem TLS keines
SMTP_ALLOWED_IPS Komma-separierte Quell-IP-Allowlist leer = alle
MAX_MESSAGE_SIZE Maximale Nachrichtengröße in Bytes; 0 deaktiviert das Limit 26214400 (25 MiB)
MAX_FILE_SIZE Maximale Größe eines S3-Anhangs in Bytes 5242880 (5 MiB)
MAX_SMTP_CLIENTS Maximale parallele SMTP-Verbindungen 50
SMTP_SOCKET_TIMEOUT SMTP-Socket-Timeout in Millisekunden 300000
SMTP_CLOSE_TIMEOUT Timeout für den Verbindungsabbau in Millisekunden 10000
WEBHOOK_CONCURRENCY Parallele Webhook-Jobs 5
WEBHOOK_QUEUE_RETRIES Queue-Wiederholungen bei Fehlern 10
WEBHOOK_QUEUE_RETRY_DELAY Wartezeit zwischen Queue-Wiederholungen in Millisekunden 60000
WEBHOOK_QUEUE_TIMEOUT Maximale Dauer eines Queue-Jobs in Millisekunden 35000
SPOOL_DIR Basisverzeichnis des persistenten Spools /var/lib/smtpwebhook/spool
LOG_DIR Verzeichnis der aktuellen Anwendungslogs /var/lib/smtpwebhook/logs
AWS_REGION AWS-Region keiner
AWS_ACCESS_KEY_ID AWS-Zugangsschlüssel keiner
AWS_SECRET_ACCESS_KEY AWS-Geheimschlüssel keiner
S3_BUCKET_NAME S3-Bucket für Anhänge keiner

Wenn MAX_FILE_SIZE=0 gesetzt ist, werden normale Anhänge nicht nach S3 hochgeladen. Für S3 müssen Bucket, Region und Zugangsdaten korrekt gesetzt sein. Bei SMTP_SECURE=true müssen die TLS-Dateien für den Dienstbenutzer lesbar sein.

Start und Produktion

Für einen Vordergrundstart:

npm start

Die produktive Installation verwendet Supervisor. Der Prozess wird mit /usr/bin/node /opt/inbound-email/server.js unter dem Benutzer smtpwebhook gestartet. Die Konfiguration liegt außerhalb des Repositories unter /etc/supervisor/conf.d/inbound-email.conf.

Nach Änderungen an der Supervisor-Konfiguration:

supervisorctl -c /etc/supervisor/supervisord.conf reread
supervisorctl -c /etc/supervisor/supervisord.conf update inbound-email
supervisorctl -c /etc/supervisor/supervisord.conf status inbound-email

Bei Änderungen an Code oder .env genügt normalerweise:

supervisorctl -c /etc/supervisor/supervisord.conf restart inbound-email

Falls Supervisor nicht verfügbar ist, kann die Anwendung alternativ direkt als systemd-Unit smtpwebhook.service betrieben werden. Eine gehärtete Beispiel- Unit mit EnvironmentFile, User=smtpwebhook, Restart=on-failure, ProtectSystem=strict und persistentem Spool ist in AGENTS.md dokumentiert. Supervisor und die systemd-App-Unit dürfen nicht gleichzeitig dieselbe Instanz starten.

Spool und Zustellung

Die Verzeichnisse haben folgende Bedeutung:

Pfad Zweck
SPOOL_DIR/pending Noch nicht erfolgreich zugestellte Nachrichten
SPOOL_DIR/failed Ungültige Spool-Dateien zur manuellen Prüfung
LOG_DIR Aktuelle JSON-Anwendungslogs

Der Spool wird beim Start und etwa jede Minute erneut eingelesen. Bei einem Webhook-Fehler bleibt die Nachricht in pending; sie wird nicht verworfen. Unlesbare Spool-Dateien werden nach failed verschoben. Die JSON-Datei wird erst nach erfolgreicher Webhook-Antwort gelöscht.

Die Zustellung ist „at least once“. Der Webhook muss doppelte Zustellungen vertragen können, insbesondere bei einem Absturz zwischen erfolgreicher Webhook-Annahme und dem Löschen der Spool-Datei.

Einsatzbeispiele

  • E-Mail-to-Ticket-Systeme
  • Dokumentenverarbeitung mit optionaler S3-Ablage
  • Automatisierte Reports und Benachrichtigungen
  • DMARC- oder andere maschinell erzeugte Reports

Sicherheit und bekannte Grenzen

  • .env, Zugangsdaten, private TLS-Schlüssel, Logs und Spool-Dateien niemals committen.
  • .env produktiv restriktiv schützen, z. B. Besitzer root, Dienstgruppe als Gruppe und Modus 640.
  • TLS-Schlüssel außerhalb des Repositories aufbewahren.
  • SMTP AUTH ist deaktiviert. Bei leerer SMTP_ALLOWED_IPS ist der Listener für alle erreichbaren IPs offen; Firewall oder Allowlist bewusst konfigurieren.
  • Keine zweite Prozessverwaltung wie PM2 parallel zu Supervisor/systemd einsetzen.
  • Rate-Limiting ist derzeit nicht implementiert.

Logging und Fehleranalyse

server.js schreibt strukturierte JSON-Logs nach /var/lib/smtpwebhook/logs/application-YYYY-MM-DD.log. Die Logs rotieren täglich und ab 20 MiB; die Aufbewahrung beträgt ungefähr 90 Tage. Supervisor führt zusätzlich /var/log/inbound-email.out.log und /var/log/inbound-email.err.log.

Die wichtigsten Checks:

supervisorctl -c /etc/supervisor/supervisord.conf status inbound-email
ss -ltnp | grep ':2525'
ps -C node -o user,group,pid,ppid,stat,etime,args
find /var/lib/smtpwebhook/spool -maxdepth 2 -type f -ls

EADDRINUSE bedeutet normalerweise, dass eine zweite oder verwaiste Instanz den Port belegt. Nicht einfach eine weitere Instanz starten, sondern zuerst den Portbesitzer identifizieren. Die alten Logs unter /opt/inbound-email/logs sind historische Daten und nicht der aktuelle Spool.

Entwicklung und Tests

Abhängigkeiten reproduzierbar installieren:

npm ci

Syntaxchecks:

node --check server.js
node --check config.js
git diff --check

Es gibt derzeit keine automatisierten Testfälle. Ein SMTP-EHLO/QUIT-Handshake gegen einen lokalen Testport prüft nur Listener und Protokollannahme; S3 und Webhook werden dadurch nicht getestet. Keine Testmail an ein produktives Webhook-Ziel senden.

Das vorhandene DockerFile klont noch das öffentliche GitHub-Original und bildet die lokale gehärtete Installation nicht automatisch ab. Vor einem produktiven Docker-Einsatz Clone-URL, Branch, Spool-Persistenz und Logging anpassen bzw. prüfen.

Git und weitere Dokumentation

origin zeigt auf das private Repository https://git.hacker.schule/mherrlein/inbound-email; upstream zeigt auf das ursprüngliche GitHub-Projekt kriiv/inbound-email. Keine History per Force-Push überschreiben.

Die detaillierte Referenz für Codex-Instanzen und die vollständige systemd- Beispiel-Unit steht in AGENTS.md.

Lizenz

Dieses Projekt steht unter der MIT-Lizenz. Siehe LICENSE.

S
Description
SMTP server to receive emails, parse content (including headers), store attachments in Amazon S3, and forward email content to a webhook.
Readme MIT
135 KiB
Languages
JavaScript 100%