Skip to content

Mailu

Audience

PLANA staff handling email infrastructure. Customer email is not sent or received via this server — customers use their own email provider.

PLANA's email server is Mailu, the open-source email stack (Postfix + Dovecot + Rspamd + a web admin UI + webmail). It is the only thing on plana.cloud and is the only PLANA service that does NOT run on the SKS cluster.

Why a separate box

Email is unforgiving:

  • IP reputation is hard to rebuild once burned
  • Reverse DNS must match HELO
  • SPF, DKIM, DMARC all need to align
  • Outbound rate limits, blocklist watching, abuse reports — operational weight is real

Running it inside the K8s cluster with rotating pod IPs would guarantee bad email reputation within a week. So Mailu runs on a dedicated Hetzner box with a static IP, careful reverse DNS, and warm sender reputation.

The box

PropertyValue
ProviderHetzner Online (Falkenstein, Germany)
Hostmail01
IP194.182.177.165
Domainplana.cloud (DNS)
User-facing hostnamesmail.planapulse.com, webmail.planapulse.com, smtp.planapulse.com
StackMailu (Docker Compose)
TLSLet's Encrypt (per-domain, on-box certbot)
BackupsDaily encrypted dump to SOS

The box is operated by hand — no GitOps, no Flux. Mailu's release cadence is slow, configuration changes are infrequent, and the operations are too email-specific for our K8s tooling.

Runbook: infra/docs/runbooks/mailu.md.

What it serves

Address patternUse
*@plana.solutionsPLANA staff email
*@planapulse.aiTransactional emails sent by PLANA services
bills@<workspace>.planapulse.appOCR-enabled bill ingestion
noreply@planapulse.comAutomated platform notifications

It does not serve mail for customer tenants' own domains.

SMTP relay for services

Cluster services that need to send email (welcome emails, password reset, alert notifications) use Mailu as their SMTP relay:

SMTP host: smtp.planapulse.com
SMTP port: 587 (submission, STARTTLS)
SMTP user: <per-service>
SMTP password: <SOPS-encrypted>

The credentials are per-service so we can revoke or audit individually.

Hairpin-NAT consideration

The Exoscale NLB doesn't hairpin — a pod inside the SKS cluster can't reach mail.planapulse.com over the LB IP. For mail, the in-cluster SMTP traffic goes directly to the Mailu box's internet-routable IP (194.182.177.165), not via the LB. So hairpin isn't a problem for SMTP.

For receiving the bill-ingestion emails (bills@<workspace>...), an inbound webhook from Mailu posts to the tenant's pulse-account-api endpoint — see pulse-account-api.

Email reputation hygiene

PracticeWhy
Static IPReputation is per-IP; rotating would reset every week
Reverse DNS matches HELOReceivers reject mail without it
SPF, DKIM, DMARC publishedStandard expectations
No mass mailing from the relayMarketing campaigns go via dedicated marketing senders, not Mailu
Bounce monitoringBounce rate over 2% is a yellow flag, over 5% is critical

What "do not touch from the cluster" means

Operationally:

  • No Ansible / Flux / Crossplane resource targets the Hetzner box
  • No kubectl operation reaches it
  • The only cluster → Hetzner connections are SMTP submissions on 587 and the bill-ingestion webhook back into the cluster (which is initiated FROM the cluster's HTTPRoute, not from Mailu)

If you need to change Mailu config, SSH into the box and edit by hand, per the runbook.

Where to read more

© PLANA Digital Ltd.