FigJam Diagram: Email Gateway — SMTP Relay Flow (expires 2026-04-13)
Centralized outbound SMTP relay for all cluster services. Routes email through AWS SES using Postfix with TLS enforcement.
| Namespace | email-gateway |
| Image | boky/postfix:v5.1.0 |
| SMTP | email-gateway.email-gateway.svc.cluster.local:587 |
| Relay | AWS SES email-smtp.us-east-1.amazonaws.com:587 |
| Domains | strommen.systems, zolty.systems |
| Exposure | Internal only — ClusterIP, no Ingress |
| PSS level | baseline (Postfix master process runs as root) |
| Setting | Value | Notes |
|---|---|---|
RELAYHOST |
email-smtp.us-east-1.amazonaws.com:587 |
AWS SES SMTP endpoint |
ALLOWED_SENDER_DOMAINS |
strommen.systems zolty.systems |
Rejects other sender domains |
POSTFIX_myhostname |
email-gateway.k3s.internal.strommen.systems |
HELO identity |
POSTFIX_smtp_tls_security_level |
encrypt |
TLS required to SES (no plaintext) |
LOG_FORMAT |
json |
Structured logging for Loki |
POSTFIX_message_size_limit |
10485760 |
10 MB (AWS SES limit) |
| Secret | Keys | Purpose |
|---|---|---|
ses-smtp-credentials |
RELAYHOST_USERNAME, RELAYHOST_PASSWORD |
AWS SES SMTP credentials (IAM-based) |
SES SMTP credentials are provisioned by Terraform (terraform/environments/aws). After terraform apply, read them from Terraform output:
kubectl create secret generic ses-smtp-credentials \
--namespace email-gateway \
--from-literal=RELAYHOST_USERNAME=$(terraform -chdir=terraform/environments/aws output -raw ses_smtp_access_key_id) \
--from-literal=RELAYHOST_PASSWORD=$(terraform -chdir=terraform/environments/aws output -raw ses_smtp_password) \
--dry-run=client -o yaml | kubectl apply -f -
If provisioning manually: create an IAM user with ses:SendRawEmail permission, then generate SMTP credentials in the AWS SES console (under Account Dashboard → SMTP settings → Create SMTP credentials).
| CPU | request 50m / limit 200m |
| Memory | request 64Mi / limit 256Mi |
| Liveness | tcpSocket :587 (after 30s, every 30s) |
| Readiness | tcpSocket :587 (after 15s, every 10s) |
| Strategy | Recreate (single replica) |
Any pod in the cluster can use email-gateway.email-gateway.svc.cluster.local:587 as an SMTP relay. No in-cluster authentication required — Postfix uses ALLOWED_SENDER_DOMAINS for filtering.
Example (Python):
import smtplib
smtp = smtplib.SMTP("email-gateway.email-gateway.svc.cluster.local", 587)
smtp.sendmail("noreply@strommen.systems", ["recipient@example.com"], msg)
AlertManager config (prometheus-helm-values.yaml):
email_configs:
- to: mstrommen+k3s-alerts@gmail.com
from: alertmanager@strommen.systems
smarthost: email-gateway.email-gateway.svc.cluster.local:587
require_tls: false
No Prometheus metrics:
boky/postfix:v5.1.0does not include a Prometheus exporter. Port 9154 is declared in the manifest (for future use) but not served by the container. The ServiceMonitor is commented out to prevent false-positiveTargetDownalerts. To enable metrics, add akumina/postfix-exportersidecar sharing/var/spool/postfixvia emptyDir volume.
kubernetes/apps/email-gateway/
email-gateway.yaml -- Namespace (baseline PSS), ServiceAccount, RBAC (ConfigMap read-only),
ConfigMap (relay config), Deployment, Service (SMTP :587 + metrics :9154),
ServiceMonitor (commented out — no exporter)
terraform/environments/aws/
ses.tf -- SES domain identity, DKIM, IAM SMTP user + credentials