Minimalistic Postfix mail server with TLS and relay support
9.9K
Lightweight Postfix mail relay with built-in DKIM signing, TLS support, and flexible delivery modes.
linux/amd64 and linux/arm64docker run -d --name postfix \
-e DOMAIN=example.com \
-e MAILNAME=mail.example.com \
-p 25:25 -p 587:587 \
-v dkim_keys:/etc/ssl/dkim \
01it/postfix:latest
On first startup, the container will:
Check logs for the DKIM public key:
docker logs postfix 2>&1 | grep -A2 "DKIM PUBLIC KEY"
Mail is delivered directly to recipient MX servers over port 25. This is the default when RELAY_HOST is not set.
Requirements:
Mail is forwarded through an external SMTP provider. Activated by setting RELAY_HOST.
environment:
- RELAY_HOST=[smtp.example.com]:587
- SMTP_USERNAME=your-username
- SMTP_PASSWORD=your-password
Port 587 always requires a SASL account from SMTP_AUTH_USERS, including
clients inside MY_NETWORKS. Trusted networks can still relay without a
login on port 25.
environment:
- SMTP_AUTH_USERS=alice:s3cret,bob:hunter2
ports:
- "587:587"
Clients authenticate over STARTTLS with the bare username (e.g. alice) and
password. Accounts are re-provisioned from the environment on every start, so
update the variable and recreate the container to change credentials.
| Variable | Default | Description |
|---|---|---|
DOMAIN | example.com | Domain for DKIM signing |
MAILNAME | mail.example.com | Postfix hostname (myhostname) and Let's Encrypt certificate name |
MY_NETWORKS | 127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 | Trusted networks allowed to relay on port 25 |
MY_DESTINATION_DOMAINS | — | Additional local destination domains |
SMTP_AUTH_USERS | — | Submission (587) login accounts, user1:pass1,user2:pass2 |
| Variable | Default | Description |
|---|---|---|
DKIM_SELECTOR | mail | DKIM selector (used in DNS record name) |
DKIM_KEY_DIR | /etc/ssl/dkim | Directory for DKIM key storage |
DKIM_EXTRA_DOMAINS | — | Comma-separated extra domains to DKIM-sign (same key) |
| Variable | Default | Description |
|---|---|---|
RELAY_HOST | — | External SMTP relay (e.g., [smtp.gmail.com]:587) |
SMTP_USERNAME | — | Relay authentication username |
SMTP_PASSWORD | — | Relay authentication password |
FALLBACK_RELAY_HOST | — | Fallback relay when primary delivery fails (e.g., [backup-smtp.example.com]:587) |
FALLBACK_SMTP_USERNAME | — | Fallback relay authentication username |
FALLBACK_SMTP_PASSWORD | — | Fallback relay authentication password |
| Variable | Default | Description |
|---|---|---|
LETSENCRYPT_EMAIL | — | Enables Let's Encrypt; email for account registration |
LETSENCRYPT_EXTRA_DOMAINS | — | Comma-separated extra domains for the certificate (SANs) |
SSL_COUNTRY | US | Self-signed certificate country |
SSL_STATE | State | Self-signed certificate state |
SSL_LOCALITY | City | Self-signed certificate locality |
SSL_ORGANIZATION | Organization | Self-signed certificate organization |
SSL_ORGANIZATIONAL_UNIT | IT | Self-signed certificate OU |
Any Postfix directive can be set via POSTFIX_ prefix:
environment:
- POSTFIX_message_size_limit=52428800
- POSTFIX_smtp_helo_name=mail.example.com
For reliable mail delivery, configure these DNS records for your domain:
Your server's IP must have a PTR record matching MAILNAME. Set this at your hosting provider.
203.0.113.1 → mail.example.com
Authorizes your server to send mail for your domain.
example.com. IN TXT "v=spf1 mx ip4:203.0.113.1 -all"
The container prints the DKIM public key on first startup. Add it as a TXT record:
mail._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=<PUBLIC_KEY>"
Replace mail with your DKIM_SELECTOR if different.
Controls how receivers handle authentication failures.
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]"
For production use, real TLS certificates improve deliverability. Set LETSENCRYPT_EMAIL to enable:
environment:
- [email protected]
- MAILNAME=mail.example.com
- LETSENCRYPT_EXTRA_DOMAINS=smtp.example.com
ports:
- "80:80" # Required for HTTP-01 challenge
- "25:25"
- "587:587"
volumes:
- letsencrypt:/etc/letsencrypt
The certificate is issued for MAILNAME, plus any LETSENCRYPT_EXTRA_DOMAINS. DOMAIN is not added automatically: it is the DKIM domain, and HTTP-01 fails when that name is behind a CDN. Every name on the certificate must have DNS that reaches this host on port 80 and must not be proxied. Certificates are issued with acme.sh (HTTP-01, standalone). Mount the letsencrypt volume to persist the acme.sh account and certificates across restarts. If issuance fails, the container falls back to self-signed certificates.
| Volume | Path | Description |
|---|---|---|
postfix_data | /var/spool/postfix | Mail queue and spool data |
postfix_certs | /etc/ssl/postfix | Self-signed TLS certificates |
dkim_keys | /etc/ssl/dkim | DKIM private/public key pair |
letsencrypt | /etc/letsencrypt | Let's Encrypt certificates (optional) |
| Port | Protocol | Description |
|---|---|---|
| 25 | SMTP | Standard mail delivery (direct mode) and receiving |
| 587 | Submission | Authenticated submission with STARTTLS |
Most cloud providers block outbound port 25 by default:
If port 25 is blocked, use relay mode with an external SMTP provider.
SMTP_AUTH_USERS over STARTTLS. Port 25 still relays for MY_NETWORKS without a login.All logs go to stdout:
docker logs -f postfix
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
Content type
Image
Digest
sha256:12d4ba30f…
Size
488 Bytes
Last updated
40 minutes ago
docker pull 01it/postfix:sha256-cf3cb44b27180c0ffadebfdcae348767e6f8ac194e3aee0bc9b05a0260efdf8f.sig