- Shell 86%
- Dockerfile 7.7%
- Go Template 6.3%
- Implementierung weg von turgon37/smtp-relay zu einer eigenen moderneren Implementierung - Kompletter neu Aufbau - Meldung bei einer Nichtzustellung in ein Zammad Ticket |
||
|---|---|---|
| rootfs | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| README.md | ||
| release.sh | ||
📬 Postfix SMTP Relay Docker
This project provides a minimal, modern, and debuggable Postfix-based SMTP relay packaged as a Docker container. It is designed to act as a reliable infrastructure component, relaying mail from internal systems to an upstream SMTP server with TLS and SASL authentication.
The image focuses on:
- correctness
- clear logging via
docker logs - predictable sender handling
- zero open-relay risk
In addition, it includes built-in alerting for delivery and identity failures, with optional integration into Zammad as tickets instead of sending alert emails.
🚀 Features
- Postfix-based SMTP relay (no mailbox storage)
- TLS-secured relay to upstream SMTP (port 587)
- SASL authentication via Docker secrets
- Forced sender rewriting (prevents upstream rejections)
- Clean, full mail logs available via
docker logs - Safe defaults (no open relay)
- Alerting on delivery failures and identity issues
- Optional Zammad ticket creation for alerts
- Designed for internal infrastructure use
🐳 Usage (Docker Compose)
version: "3.9"
services:
mailrelay:
build: .
container_name: mailrelay
restart: unless-stopped
ports:
- "25:25" # expose only on trusted/internal networks
environment:
HOSTNAME_FQDN: "mailrelay.example.local"
# Fixed sender handling
DEFAULT_FROM: "user@example.local"
FORCE_DEFAULT_FROM: "1"
# Relay target
RELAY_HOST: "smtp.example.local"
RELAY_PORT: "587"
RELAY_TLS: "required"
# Allowed client networks
MYNETWORKS: "127.0.0.0/8,10.0.0.0/8,192.168.0.0/16"
# SASL authentication
RELAY_SASL_USER: "loginuser@example.local"
RELAY_SASL_PASS_FILE: "/run/secrets/relay_sasl_pass"
# Alerting
ALERT_ENABLED: "1"
ALERT_MATCH: "invalid_user,sendas_denied,postfix_bounced,postfix_deferred"
# Zammad integration
ALERT_ZAMMAD_ENABLED: "1"
ZAMMAD_BASE_URL: "https://zammad.example.com"
ZAMMAD_TOKEN_FILE: "/run/secrets/zammad_token"
ZAMMAD_GROUP: "Support"
ZAMMAD_STATE: "new"
ZAMMAD_PRIORITY_ID: "2" # 1=low, 2=normal, 3=high
ZAMMAD_CUSTOMER_EMAIL: "mailrelay@example.local"
ZAMMAD_TAGS: "mailrelay,postfix,alert"
# Debugging
DEBUG: "1"
secrets:
- relay_sasl_pass
- zammad_token
volumes:
- postfix_spool:/var/spool/postfix
- postfix_state:/var/lib/postfix
- /etc/ssl/certs:/etc/ssl/certs:ro
secrets:
relay_sasl_pass:
file: ./secrets/relay_sasl_pass.txt
zammad_token:
file: ./secrets/zammad_token.txt
volumes:
postfix_spool:
postfix_state:
🔐 Secrets
relay_sasl_pass.txt
The secret file must contain only the password (no username):
super-secret-password
The username is configured via RELAY_SASL_USER.
zammad_token.txt
Contains a Zammad API token with permission to create tickets:
zammad-api-token-here
✉️ Sender Handling (Important)
Many SMTP relays reject mails if the sender does not match the authenticated user.
This image enforces a safe default:
- If
DEFAULT_FROMis set → local senders are rewritten to this address - Otherwise → fallback to
RELAY_SASL_USER
This avoids errors like:
553 5.7.1 Sender address rejected: not owned by user
Sender rewriting is applied only to local / infrastructure senders (e.g. root, daemon, host-based senders).
🚨 Alerting & Monitoring
The container continuously monitors Postfix logs and triggers alerts on actionable failures, including:
invalid_user– upstream mailbox or identity does not existsendas_denied– sender not permitted to send as this addresspostfix_bounced– delivery permanently failedpostfix_deferred– delivery temporarily failed
Alert detection is regex-based and operates directly on the Postfix log stream.
Alert Flow
- Postfix writes a failure to the log
- The internal watcher matches the error
- Context (queue ID, sender, recipient, reason) is extracted
- A Zammad ticket is created with full diagnostic details
Alerts are throttled to avoid flooding during repeated failures.
🎟 Zammad Ticket Details
Each alert creates an internal Zammad ticket containing:
- Failure type (e.g.
postfix_bounced,ErrorInvalidUser) - Affected sender and recipient (best effort)
- Queue ID
- Full Postfix error reason
- Recent log context
- Fix hints for common identity problems
This makes the relay suitable for production use without silent mail loss.
🧪 Testing the Relay
Recommended: swaks
docker exec -it mailrelay swaks \
--to admin@example.com \
--from test@example.com \
--server 127.0.0.1 \
--port 25 \
--header "Subject: Relay test" \
--data "Hello from mailrelay"
Using sendmail
docker exec -i mailrelay sendmail admin@example.com <<EOF
From: test@example.com
To: admin@example.com
Subject: Relay test
Hello from mailrelay
EOF
⚠️ Do not use sendmail -v unless you want delivery status notifications sent back to you.
📜 Logs
All Postfix logs are written to a file and streamed to stdout:
docker logs -f mailrelay
This makes it possible to audit delivery and alerting via Docker logs alone.
🔒 Security Notes
- This container is not a public mail server
- Never expose port 25 to the internet
- Always restrict
MYNETWORKS - No mailboxes are stored; this is a pure relay
🧑💻 Author
Michael Kleger OneSystems GmbH
📝 License
MIT License – free for commercial and private use.