Email Forwarding with AWS SES and Terraform
Every project needs a contact address. Every domain deserves its own inbox. But running a mail server just to forward hello@yourdomain.com to your existing inbox is overkill.
We built terraform-aws-ses-email-forwarder to solve this in one terraform apply.
The Problem
You register a domain. You want hello@yourdomain.com to land in your existing Gmail or company inbox. Your options:
- Google Workspace / Microsoft 365 — $6+/month per user for a mailbox you don’t need
- Self-hosted mail server — Postfix, DKIM, SPF, DMARC, spam filtering, maintenance forever
- Third-party forwarding services — Another vendor, another bill, another dependency
None of these make sense for a simple forwarding use case.
The Solution
Amazon SES can receive email. A Lambda function can forward it. Terraform can wire it all together.
Internet
↓
Amazon SES (inbound receiving)
↓
SES receipt rule
↓
S3 (raw message storage)
↓
Lambda forwarder (Go, ARM64)
↓
Your existing inbox
The module handles everything: domain verification, DKIM, MX records, S3 bucket, receipt rules, Lambda function, and IAM permissions.
Usage
module "email" {
source = "git::https://github.com/ql4b/terraform-aws-ses-email-forwarder.git?ref=v1.0.0"
namespace = "cloudless"
name = "email"
domain_name = "example.com"
recipients = [
"hello@example.com",
"contact@example.com",
]
forward_to = [
"carlo@example.com",
]
route53_zone_id = data.aws_route53_zone.cloudless.zone_id
}
That’s it. After terraform apply, emails to hello@example.com arrive in your existing inbox.
How the Forwarder Works
SES doesn’t pass the full raw email to Lambda directly. The receipt rule stores the message in S3 first, then triggers the forwarder.
The Go Lambda function:
- Reads the raw email from S3
- Adds a
Reply-Toheader with the original sender - Rewrites
Fromto use the verified domain (SES requirement) - Strips headers that break forwarding (DKIM signatures, Message-ID, Return-Path)
- Sends via
SendRawEmailto the destination
This preserves the original message content while satisfying SES sending requirements.
Why Go
The forwarder is a compiled Go binary running on provided.al2023 (ARM64). The binary ships pre-compiled in the module — no build step required for consumers.
Why not Node.js? AWS stopped bundling the SDK in Lambda runtimes after Node 16. A Node.js forwarder would require npm install inside .terraform/modules/ before every apply. That’s impractical for a Terraform module.
Go gives us:
- Zero runtime dependencies — single static binary
- Ships with the module — no build step for consumers
- ~4.7MB zip — fast cold starts
- ARM64 — cheapest Lambda pricing
Design Decisions
No SPF record creation. Domains often have existing TXT records (Google site verification, etc.) that would conflict. SPF is documented as a manual recommendation instead.
Pre-compiled binary. The module consumer experience is just terraform apply. The Makefile exists for maintainers who need to rebuild.
Single receipt rule. S3 action + Lambda action in one rule. No validation step, no DynamoDB, no API Gateway. This module does one thing.
CloudPosse context. Consistent naming via cloudposse/label/null — same pattern as our other modules.
What It Costs
At low volume (< 1000 emails/month):
- SES receiving: free (first 1000 messages)
- SES sending (forwarding): $0.10 per 1000 emails
- S3 storage: negligible (messages expire after 30 days)
- Lambda: negligible (milliseconds per invocation)
Effectively free for most use cases.
When to Use This
Good for:
- Contact address for a static website
- Project inbox forwarded to a team mailbox
- Domain aliases that forward to one or more real inboxes
- Lightweight inbound email for small services
Not for:
- Full email hosting
- High-volume transactional email
- Complex routing rules
- Inbox management with read/unread state
SES Receiving Region
SES inbound email receiving is available in most AWS regions. Deploy this module in a region that supports SES receiving and the MX record will point to the corresponding regional endpoint automatically.
The Bigger Picture
This module is part of our approach to infrastructure: solve real problems with minimal, composable tools.
We needed hello@ourdomain.com to work. We didn’t need a mail server. Now it’s a single Terraform module that anyone can use.
terraform-aws-ses-email-forwarder is open source and available on GitHub.