Mailbox
Versatile email infrastructure that operates on AWS.
Clients
Web
See mailbox-browser
| Dark mode | Light mode | |:---------:|:-----------:| | !Screenshot Dark Mode | !Screenshot Light Mode |
CLI
go install github.com/harryzcy/mailbox-cli
For details, refer to mailbox-cli
Deploy
Deployment is managed with Terraform.
Prerequisites
Two S3 buckets are created outside Terraform, because one must exist before
terraform init can run and the other holds mail that must outlive any stack:
- A state bucket, for Terraform state. Enable versioning so a bad write can
- An email bucket, where SES delivers raw messages.
aws_s3_artifacts_bucket_override: bucket names are global, so
default reliably works. Lambda deployment packages are uploaded there to be
signed, and its contents are rebuildable from a release.
Credentials
The provider sets only a region, so Terraform uses the standard AWS credential chain: environment variables, a named profile, or IAM Identity Center.
Deploying needs write access to IAM, Lambda, API Gateway, CloudWatch Logs, SQS,
Signer, SES, the state and artifact buckets, and — unless
aws_dynamodb_table_override is set — DynamoDB. Signing packages needs
signer:StartSigningJob and read and write on the artifacts bucket. Creating the artifacts bucket also needs s3:CreateBucket and the
s3:Get/s3:Put bucket-configuration actions behind versioning, encryption,
public access block, ownership controls, policy and lifecycle. One more is easy
to miss: iam:PassRole for the Lambda execution role, because the resulting
error names CreateFunction instead.
Attach those permissions to a role and assume it, rather than granting them to a user directly:
# ~/.aws/config
[profile mailbox]
role_arn = arn:aws:iam::<account-id>:role/mailbox-deploy
source_profile = default
region = us-west-2
AWS_PROFILE=mailbox make apply
With IAM Identity Center, aws sso login --profile mailbox instead — no stored
key at all.
CI does not use any of this. It assumes a short-lived, plan-only role through
GitHub OIDC; see oidc.tf.
Configure
The two bucket names are required. Everything else has a working default, and
the remaining variables are optional overrides that each turn a feature on. Set
them as TF_VAR_ environment variables.
| Variable | Purpose |
| --- | --- |
| aws_s3_bucket_override | Required. Names the email bucket. There is no default: bucket names are global, so nothing generated from the project name reliably works. |
| aws_s3_artifacts_bucket_override | Required. Names the artifacts bucket Terraform creates for code signing. Global names again, so again no default. |
| aws_region | Region to deploy into. Defaults to us-west-2. |
| project_name, environment | Name resources. Default to mailbox-v2 and dev. |
| aws_dynamodb_table_override | Use an existing table instead of creating one. |
| aws_dynamodb_point_in_time_recovery | Continuous backups on the managed table. Defaults to true; incurs additional cost. |
| ses_receipt_rule_set_name, ses_receipt_rule_name | Manage an existing SES receipt rule. Both required to enable; otherwise SES is left alone. |
| github_repository, github_oidc_provider_arn | Create a CI role for that repo. Both required to enable. |
Deploy
export TF_STATE_BUCKET=<your-state-bucket>
export TF_VAR_aws_s3_bucket_override=<your-email-bucket>
export TF_VAR_aws_s3_artifacts_bucket_override=<your-artifacts-bucket>
make init
make deploy
make plan previews what deploying the latest release would change, and
make deploy deploys it. Use make apply to deploy binaries built from your
working tree instead.
Configure email receiving
SES applies one active receipt rule set per region, and it may already hold rules unrelated to this project. Terraform therefore manages a single rule inside an existing set rather than the set itself.
Create a rule set and a rule with two actions, in this order:
- Deliver to S3, naming your email bucket.
- Invoke Lambda, selecting
.- -email_receive
ses_receipt_rule_set_name and ses_receipt_rule_name and
import it:
terraform import 'aws_ses_receipt_rule.receive[0]' <rule-set-name>:<rule-name>
Finally, deploy mailbox-browser or use mailbox-cli.
Troubleshooting
See doc/troubleshooting.md, e.g. to replay failed email receives.
API
See doc/API.md
Architecture
It runs on AWS services, including SES, Lambda, API Gateway, DynamoDB, and SQS.
Contributing
Development environment
- Go >= 1.27