Forwards inbound emails received by any AWS SES verified domain to any destination address. It can also handle emails from multiple domains.
Architecture: SES → S3 (stores raw email) → Lambda → SES (forward)
First time? See SETUP.md for a complete step-by-step installation guide.
aws-ses-lambda/
├── src/
│ ├── lambda_function.py # Lambda handler
│ └── requirements.txt # empty — boto3 is pre-installed in Lambda
├── tests/
│ ├── conftest.py # shared fixtures
│ └── test_lambda_function.py # unit tests (mocked boto3, no real AWS calls)
├── template.yaml # AWS SAM template
├── samconfig.toml.example # SAM deploy config template
├── .env.example # env var reference
├── .gitignore
├── requirements-dev.txt # pytest, boto3 for local dev
├── SETUP.md # step-by-step installation guide
└── AGENTS.md # instructions for AI agents
All configuration is via environment variables set as CloudFormation parameters in samconfig.toml.
| Variable | Required | Default | Description |
|---|---|---|---|
EMAIL_BUCKET |
yes | — | S3 bucket where SES stores raw inbound emails |
EMAIL_KEY_PREFIX |
no | "" |
S3 key prefix, e.g. email/ (include trailing slash) |
FORWARD_MAPPING |
yes | — | JSON: {"addr@domain.com": ["dest@gmail.com"]} |
FROM_EMAIL |
no | "" |
Verified SES sender address; falls back to original recipient if blank |
SUBJECT_PREFIX |
no | "" |
String prepended to the Subject header |
ALLOW_PLUS_SIGN |
no | false |
Strip +tag from recipient before mapping lookup |
For each inbound recipient address, the mapping is checked in this order:
- Exact match —
"you@domain.com": [...] - Domain match —
"@domain.com": [...] - User match —
"you": [...](matchesyou@on any domain) - Catch-all —
"@": [...]
Example:
{
"you@example.com": ["you@gmail.com"],
"bob@example.com": ["bob@gmail.com"],
"@example.com": ["fallback@gmail.com"],
"@": ["admin@gmail.com"]
}python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements-dev.txt
pytest tests/ -vAll 24 unit tests run with mocked boto3 — no AWS credentials required.
- SES receives an inbound email and stores the raw message to S3
- SES triggers the Lambda with an event containing the message ID and recipient list
- Lambda looks up each recipient in
FORWARD_MAPPING - If a match is found, Lambda downloads the raw email from S3 and rewrites the headers:
- Adds
Reply-TofromFrom(if absent) - Replaces
Fromwith the verified sender, preserving the original display name - Optionally prepends
SUBJECT_PREFIXto the subject - Removes
Return-Path,Sender,Message-ID, andDKIM-Signature
- Adds
- Lambda sends the rewritten email via SES
SendRawEmailto the destination(s)