Egress Gateway for SPF Compliance¶
The Problem: Dynamic Source IPs Break SPF¶
When Mailu pods send outbound email, Kubernetes uses the node’s IP address where the pod is running as the source IP. In a multi-node cluster, this means:
Email from
postfix-abc123pod on node A uses IP168.119.62.98Email from
postfix-def456pod on node B uses IP49.13.2.15Recipients see emails from different IPs for the same domain
Why This Breaks Email Delivery¶
SPF (Sender Policy Framework) is a DNS record that tells receiving mail servers which IPs are authorized to send email for your domain. When your SPF record says:
v=spf1 mx a:mail.kup6s.com ~all
But your emails come from random node IPs (168.119.62.98, 49.13.2.15, etc.), recipients’ mail servers see:
❌ SPF: softfail - “This IP is not authorized”
🚫 Lower reputation score (mail-tester.com: 5/10 instead of 10/10)
📬 Emails may land in spam folders
The Inflexible Solution: Add All Node IPs to SPF¶
You could add all node IPs to your SPF record:
v=spf1 mx a:mail.kup6s.com ip4:168.119.62.98 ip4:49.13.2.15 ip4:... ~all
Problems:
Adding/removing nodes requires DNS updates
SPF records have size limits (10 DNS lookups max)
Brittle and error-prone
The Solution: Cilium Egress Gateway¶
Cilium egress gateway routes all traffic from selected pods through a designated node, ensuring a consistent source IP for all outbound email.
How It Works¶
Internet
(Gmail, etc)
▲
│ Outbound mail
│ (Egress path)
│
┌────────┴─────────┐
│ Egress Gateway │ (control-fsn1 node)
│ IP: 5.75.247.168│ ← Single consistent source IP
└────────┬─────────┘
│
▼
┌─────────────┐
│ Mailu Pods │ (any node)
│ - postfix │
│ - dovecot │
└─────────────┘
▲
│ Inbound mail
│ (Ingress path)
│
┌────────┴─────────┐
│ Traefik Ingress │ (LoadBalancer)
│ mail.kup6s.com │
└────────┬─────────┘
│
▼
Internet
(Senders)
Result: All outbound emails appear to come from 5.75.247.168, matching your SPF record.
Architecture Decisions¶
Server IP vs Floating IP¶
We use the server’s native IP (5.75.247.168) instead of a Hetzner Floating IP because:
Advantages:
✅ Zero additional cost (Floating IP: €1.19/month)
✅ Simpler infrastructure (one less resource)
✅ Adequate for mail server use case
Trade-offs:
⚠️ IP is tied to the node - if node is replaced, IP changes
⚠️ Requires manual DNS updates after node replacement
⚠️ No automatic failover to another node
When to use Floating IP instead:
High-availability requirements (automatic failover)
Frequent node replacements
Multiple services requiring IP stability
For a mail server that’s rarely rebuilt, the server IP is sufficient.
IPv4 vs IPv6 Handling¶
IPv4: Fully supported via egress gateway
All Mailu pods → 5.75.247.168 (control-fsn1)
Consistent source IP guaranteed
IPv6: Limited egress gateway support
Cilium 1.17.0 doesn’t support IPv6 egress gateway policies
IPv6 traffic uses node’s native address (2a01:4f8:c012:f3f0::1)
Still consistent because control-fsn1 is the designated egress node
PTR Records (Reverse DNS)¶
Email servers check reverse DNS (PTR records) to verify the sending server’s identity:
5.75.247.168 → mail.kup6s.com (PTR record)
Requirements:
PTR record must match HELO hostname (
mail.kup6s.com)Forward DNS (A record) should resolve back to the IP
Set manually in Hetzner Cloud Console (Servers → Networking → Reverse DNS)
Why it matters: Mismatched PTR records cause yellow warnings in mail-tester.com and may reduce deliverability.
Benefits¶
After implementing egress gateway:
✅ SPF passes: All emails from authorized IP (5.75.247.168)
✅ Consistent sender reputation: Recipients see stable sending IP
✅ mail-tester.com score: 10/10 (up from 5/10)
✅ Better deliverability: Lower spam risk
✅ Flexible pod placement: Mailu pods can run on any node without SPF changes
See Also¶
Configure Egress Gateway (How-to) - Step-by-step setup guide
Traefik TLS Termination Pattern - Inbound TLS architecture for mail protocols