Back to GitHub Projects
    Open Source · Go

    aws-ses-relay

    A Go SMTP front-end for Amazon SES that authenticates with an IAM role instead of static SMTP credentials or AWS secret keys. Apps and alerting tools speak plain SMTP; the relay forwards through the SES v2 API with an IP allowlist, sender and recipient filters, per-IP rate limiting, a send-quota guard, and Prometheus metrics.

    AWS
    SES
    Go
    Observability
    View on GitHub
    Architecture
    architecture-diagram.png
    aws-ses-relay Architecture

    About

    aws-ses-relay is a small Go service that lets any SMTP-speaking client send mail through Amazon SES without handling AWS credentials itself. It listens for SMTP submission on port 1025 and forwards each message through the SES v2 API using the AWS default credential chain, so on EC2, ECS, or EKS it picks up the instance or task IAM role and needs no static SMTP username, password, or AWS secret key on the client side. Around that core it adds the controls you want before pointing production traffic at it: an IP/CIDR allowlist enforced when a connection is accepted, sender and recipient regular-expression filters, a per-IP token-bucket rate limiter, and a send-quota guard that polls the SES account limit and backs off before you hit the 24-hour cap. A separate admin port serves health, readiness, and Prometheus metrics. The published image is distroless and runs as a non-root user.

    Key Features

    SMTP submission on :1025, forwarded to Amazon SES over the SES v2 API
    Authenticates with the AWS default credential chain — uses the EC2/ECS/EKS IAM role, no static SMTP or AWS keys
    IP and CIDR allowlist enforced at connection accept time
    Sender and recipient regex filters (allow-from / deny-to)
    Per-IP token-bucket rate limiting to blunt abuse
    Send-quota guard polls ses:GetAccount and backs off near the 24-hour cap
    Injection-safe SMTP replies and graceful shutdown on SIGTERM
    Prometheus metrics, health, and readiness on a separate admin port (:9090)
    Configurable by CLI flags or SES_RELAY_* environment variables
    Optional STARTTLS / implicit TLS on the submission listener
    Distroless multi-arch image (amd64 + arm64) running as non-root uid 65532

    Engineering Challenges

    Bridging a stateless SMTP conversation to the SES v2 send API without leaking AWS credentials to clients
    Enforcing send limits locally by tracking the SES 24-hour quota before SES itself rejects the request
    Hardening an internet-adjacent SMTP listener against injection and abuse (CRLF-safe replies, IP allowlist, rate limiting)
    Keeping the container attack surface minimal — distroless, non-root, no shell

    Results & Impact

    Alertmanager and app services send mail with no SMTP passwords or AWS secret keys to rotate
    Credentials come from an IAM role scoped with an ses:FromAddress condition, so a leaked config sends nothing
    Operators get send, deny, and error counts plus send latency as Prometheus metrics out of the box
    One small container drops in front of SES for any tool that can already speak SMTP