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-abc123 pod on node A uses IP 168.119.62.98

  • Email from postfix-def456 pod on node B uses IP 49.13.2.15

  • Recipients 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:

  1. PTR record must match HELO hostname (mail.kup6s.com)

  2. Forward DNS (A record) should resolve back to the IP

  3. 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