An SMTP front-end for Amazon SES that authenticates with an IAM role, not stored credentials.
Point any application that speaks SMTP at this relay and its mail goes out through the Amazon SES v2 API — no SMTP username/password, no AWS secret in the app. Credentials come from the standard AWS provider chain (EC2 instance role, ECS/EKS task role, or environment).
This image is a fully static binary on a distroless non-root base
(gcr.io/distroless/static): no shell, no package manager, minimal attack
surface. Multi-arch: linux/amd64 + linux/arm64.
The relay reads AWS credentials from the environment. On EC2/ECS/EKS the
instance/task role is picked up automatically; locally, pass the usual AWS env
vars or mount ~/.aws.
docker pull hardikaws/aws-ses-relay:latest
# Listen on :1025, relay through SES in eu-west-1 using an IAM role.
docker run --rm -p 1025:1025 -p 9090:9090 \
-e AWS_REGION=eu-west-1 \
hardikaws/aws-ses-relay
Then send through it like any SMTP server:
swaks --server localhost:1025 --from [email protected] --to [email protected]
Every flag has a SES_RELAY_* environment-variable equivalent, so the relay
can be configured entirely through the environment in a container.
| Env var | Flag | Default | Description |
|---|---|---|---|
SES_RELAY_ADDR | -a | :1025 | TCP listen address |
SES_RELAY_HOSTNAME | -h | (none) | Hostname advertised in EHLO |
SES_RELAY_CONFIG_SET | -e | (none) | SES configuration set name |
SES_RELAY_ALLOWED_IPS | -i | (empty = all) | Allowed client IPs/CIDRs (comma-separated) |
SES_RELAY_ALLOW_FROM | -l | (none) | Allowed-sender regex |
SES_RELAY_DENY_TO | -d | (none) | Denied-recipient regex |
SES_RELAY_STARTTLS | -s | false | Require STARTTLS |
SES_RELAY_TLS_ONLY | -t | false | Implicit TLS listener only |
SES_RELAY_TLS_CERT | -c | (none) | TLS cert file |
SES_RELAY_TLS_KEY | -k | (none) | TLS key file |
SES_RELAY_MAX_SIZE | -size | 10485760 | Max message size (bytes) |
SES_RELAY_TIMEOUT | -timeout | 30s | Per-connection idle timeout |
SES_RELAY_ADMIN_ADDR | -admin | :9090 | Admin HTTP addr (health/metrics); empty disables |
SES_RELAY_RATE | -rate | 0 (off) | Per-IP messages/sec |
SES_RELAY_BURST | -burst | 10 | Per-IP rate-limit burst |
SES_RELAY_QUOTA_GUARD | -quota-guard | false | Block sends near the SES 24h quota |
SES_RELAY_QUOTA_THRESHOLD | -quota-threshold | 0.95 | Fraction of quota at which to block |
SES_RELAY_SHUTDOWN_TIMEOUT | -shutdown-timeout | 20s | Grace period for in-flight sends |
Run docker run --rm hardikaws/aws-ses-relay -version for the build banner, or
--help for the full flag list.
| Port | Purpose |
|---|---|
1025 | SMTP submission |
9090 | Admin HTTP: /healthz, /readyz, /metrics (Prometheus) |
Keep
9090on a private interface — it exposes metrics and health with no auth. Bind it with-e SES_RELAY_ADMIN_ADDR=127.0.0.1:9090or restrict it at the network layer.
The relay needs ses:SendEmail (and ses:GetAccount if the quota guard is on):
{
"Version": "2012-10-17",
"Statement": [
{ "Effect": "Allow", "Action": ["ses:SendEmail", "ses:GetAccount"], "Resource": "*" }
]
}
The relay exposes metrics at /metrics and works as an Alertmanager
smtp_smarthost, letting Alertmanager deliver email alerts through SES without
storing SES SMTP credentials. See the
repository README
for the full setup. A pre-configured Grafana dashboard is also provided in the repository at grafana/aws-ses-relay.json.
Full documentation, architecture diagram, and license: https://github.com/hardik-aws/aws-ses-relay
Content type
Image
Digest
sha256:e853165c0…
Size
6.6 MB
Last updated
3 months ago
docker pull hardikaws/aws-ses-relay