Update project README and deployment guidance
Docker / build (push) Canceled after 0s

This commit is contained in:
2026-09-02 13:04:29 +02:00
parent 1edb326519
commit c1961093d6
+190 -98
View File
@@ -1,147 +1,239 @@
# Inbound Email (SMTP) to Webhook
Author: Martin Krivosija - [LinkedIn](https://linkedin.com/in/martin-alexander-k)
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.
A simple, efficient script that provides an SMTP server to receive emails, parse content (including headers), store attachments in Amazon S3, and forward email content to a webhook. Graceful handling of multiple concurrent SMTP sessions and webhook requests.
Originalentwickler: Martin Krivosija [LinkedIn](https://linkedin.com/in/martin-alexander-k)
## Features
Dieses Repository ist von [`kriiv/inbound-email`](https://github.com/kriiv/inbound-email)
geforkt und wird hier als eigenständige, gehärtete Weiterentwicklung gepflegt.
- SMTP server to receive emails concurrently
- Parses incoming emails using `mailparser`
- Uploads attachments to Amazon S3
- Forwards parsed email content to a specified webhook
- Configurable via environment variables
- Handles large attachments gracefully
- Robust queue system for processing multiple emails and webhook requests simultaneously
Das Repository liegt unter:
## Prerequisites
```text
https://git.hacker.schule/mherrlein/inbound-email
```
- Node.js (v18 or later recommended)
- If saving attachments, an Amazon Web Services (AWS) account with S3 access or a compatible system
- A HTTP(s) webhook endpoint to receive the processed emails
## Funktionsweise
Der Zustellweg lautet:
```text
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
1. Clone this repository:
```
git clone https://github.com/kriiv/inbound-email.git
```bash
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
```
2. Install dependencies:
```
npm install
```
`WEBHOOK_URL` muss gesetzt werden. Für einen lokalen Test kann ein nicht
privilegierter Port verwendet werden:
3. Copy the `.env.example` file to `.env` and set the required configuration: (eg. `mv .env.example .env`)
| Variable | Description | Required | Default |
| --------------------- | --------------------------------------------------------------- | -------- | ----------- |
| `WEBHOOK_URL` | The URL where parsed emails will be sent | Yes | `null` |
| `PORT` | The port for the SMTP server to listen on | No | `25` |
| `SMTP_SECURE` | Set to 'true' for TLS support (requires key/cert setup) | No | `false` |
| `WEBHOOK_CONCURRENCY` | Number of concurrent webhook requests | No | `5` |
| `MAX_FILE_SIZE` | Maximum attachment size in bytes (0 to disable S3 uploads) | No | `5242880` (5MB) |
| `AWS_REGION` | Your AWS region | If saving| `null` |
| `AWS_ACCESS_KEY_ID` | Your AWS access key ID | If saving| `null` |
| `AWS_SECRET_ACCESS_KEY`| Your AWS secret access key | If saving| `null` |
| `S3_BUCKET_NAME` | The name of your S3 bucket for storing attachments | If saving| `null` |
| `TLS_KEY_PATH` | Path to the TLS private key file (if `SMTP_SECURE=true`) | If secure| `null` |
| `TLS_CERT_PATH` | Path to the TLS certificate file (if `SMTP_SECURE=true`) | If secure| `null` |
*Note: S3 credentials (`AWS_*`, `S3_BUCKET_NAME`) are required if `MAX_FILE_SIZE` > 0.*
## Usage
Start the server:
```
```bash
PORT=25252 \
SPOOL_DIR=/tmp/smtpwebhook-spool \
LOG_DIR=/tmp/smtpwebhook-logs \
npm start
```
The SMTP server will start and listen on the specified port (default: 25) on all network interfaces.
Produktive Spool- und Log-Verzeichnisse müssen dem Dienstbenutzer gehören und
restriktiv geschützt sein:
You can use pm2 or supervisor to keep the server running after restart. Example: `pm2 start server.js`
```bash
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
```
## Sample Use Cases
## Konfiguration
1. **Email to Ticket System**: Use this bridge to receive support emails and automatically create tickets in your helpdesk system via the webhook.
Die Anwendung liest `.env` aus dem Arbeitsverzeichnis. `WEBHOOK_URL` ist
zwingend erforderlich und hat keinen öffentlichen Defaultwert.
2. **Document Processing**: Receive emails with document attachments, store them in S3, and trigger a document processing pipeline through the webhook.
| Variable | Bedeutung | Standardwert |
| --- | --- | --- |
| `WEBHOOK_URL` | Ziel-URL für die geparste Nachricht | erforderlich |
| `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 |
3. **Email Marketing Analysis**: Collect incoming emails from a campaign, store any images or attachments, and send the content to an analytics system for processing.
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.
4. **Automated Reporting**: Set up an email address that receives automated reports, stores them in S3, and notifies your team via the webhook.
## Start und Produktion
5. **DMARC Reporting**: Receive DMARC reports via email and store them in S3.
Für einen Vordergrundstart:
Using inbound parse for something interesting? Please let me know, I'd love to hear about it.
```bash
npm start
```
## Todo
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`.
- Rate limiting
- ~~Log Storage~~ (completed)
Nach Änderungen an der Supervisor-Konfiguration:
## Contributing
```bash
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
```
Contributions are welcome! Please feel free to submit a Pull Request or get in touch.
Bei Änderungen an Code oder `.env` genügt normalerweise:
## License
```bash
supervisorctl -c /etc/supervisor/supervisord.conf restart inbound-email
```
This project is licensed under the MIT License. This means you are free to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software, including for commercial purposes.
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](AGENTS.md)
dokumentiert. Supervisor und die systemd-App-Unit dürfen nicht gleichzeitig
dieselbe Instanz starten.
## Disclaimer
## Spool und Zustellung
Please ensure you have the necessary permissions and security measures in place when deploying an SMTP server. Depending on your firewall configuration, you may be exposing this service to the internet.
Die Verzeichnisse haben folgende Bedeutung:
## Security Considerations
| 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 |
When deploying this SMTP server, please keep the following security considerations in mind:
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.
- Ensure that your server is properly secured and that only authorized IPs can access the SMTP port.
- Use strong, unique passwords for your AWS credentials and keep them secure.
- Regularly update the Node.js runtime and all dependencies to their latest versions.
- Consider implementing additional authentication mechanisms for the SMTP server if needed.
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.
## Logging and Monitoring
## Einsatzbeispiele
The server logs information about received emails, webhook responses, and any errors that occur. The current logging setup includes:
- E-Mail-to-Ticket-Systeme
- Dokumentenverarbeitung mit optionaler S3-Ablage
- Automatisierte Reports und Benachrichtigungen
- DMARC- oder andere maschinell erzeugte Reports
- Console output for immediate visibility
- Daily rotating log files for persistent storage
- JSON formatting of log entries for easy parsing
- Timestamp inclusion for each log entry
## Sicherheit und bekannte Grenzen
Logging settings:
- `.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.
- Log files are stored in the `logs/` directory
- Files are named `application-YYYY-MM-DD.log`
- Log files are rotated daily and compressed
- Maximum log file size is set to 20MB
- Log files are kept for 90 days
## Logging und Fehleranalyse
I recommend:
`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`.
- Review log files regularly for errors or unusual patterns.
- Consider setting up log aggregation and analysis tools (e.g., ELK stack, Splunk).
- Implement alerts for critical errors or unusual activity patterns.
- Monitor system resources (CPU, memory, disk space) to ensure smooth operation.
- Set up uptime monitoring for the SMTP server and webhook endpoint.
Die wichtigsten Checks:
## System Requirements
```bash
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
```
- Node.js v18 or later
- Sufficient disk space for temporary storage of attachments before S3 upload and 90 days of logging.
- Outbound internet access for S3 uploads and webhook calls
- Inbound access on the configured SMTP port. (Default: 25, or 587 if `SMTP_SECURE` is set to 'true')
`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.
## Troubleshooting
## Entwicklung und Tests
If you encounter issues:
Abhängigkeiten reproduzierbar installieren:
1. Check the server logs for any error messages.
2. Ensure all environment variables are correctly set.
3. Verify that your AWS credentials have the necessary permissions for S3 operations.
4. Check that the webhook endpoint is accessible and responding correctly.
5. For attachment issues, verify that the `MAX_FILE_SIZE` setting is appropriate for your use case.
```bash
npm ci
```
If problems persist, please open an issue on the GitHub repository with detailed information about the error and your setup.
Syntaxchecks:
```bash
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`](https://github.com/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](AGENTS.md).
## Lizenz
Dieses Projekt steht unter der MIT-Lizenz. Siehe [LICENSE](LICENSE).