{"id":37487587,"url":"https://github.com/mlhpdx/email-delivery","last_synced_at":"2026-01-16T07:33:52.478Z","repository":{"id":145684874,"uuid":"601833076","full_name":"mlhpdx/email-delivery","owner":"mlhpdx","description":"For use receiving email via SES, delivers email to S3, indexes mailboxes in DDB and broadcasts rich inbound email events via EventBridge.","archived":false,"fork":false,"pushed_at":"2025-12-21T03:00:20.000Z","size":36,"stargazers_count":19,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-12-22T21:03:28.408Z","etag":null,"topics":["aws","cost-optimization","email","serverless","smtp"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mlhpdx.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-02-14T23:17:03.000Z","updated_at":"2025-12-21T03:00:23.000Z","dependencies_parsed_at":"2025-02-20T22:24:59.466Z","dependency_job_id":"a2a24583-d6b0-4b92-ba6f-b208266ee830","html_url":"https://github.com/mlhpdx/email-delivery","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mlhpdx/email-delivery","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlhpdx%2Femail-delivery","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlhpdx%2Femail-delivery/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlhpdx%2Femail-delivery/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlhpdx%2Femail-delivery/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mlhpdx","download_url":"https://codeload.github.com/mlhpdx/email-delivery/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mlhpdx%2Femail-delivery/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28478047,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T06:30:42.265Z","status":"ssl_error","status_checked_at":"2026-01-16T06:30:16.248Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","cost-optimization","email","serverless","smtp"],"created_at":"2026-01-16T07:33:52.404Z","updated_at":"2026-01-16T07:33:52.462Z","avatar_url":"https://github.com/mlhpdx.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Automation-Oriented Email with SES, StepFunctions and EventBridge #\n\nThis repository implements robust, low-cost and compliance-oriented email service based on AWS Simple Email Service (SES) and intended for use cases centered on email-based automation (from auto reply to workflow integration). This solution is especially useful for those maintaining multiple domains in a global context, who require email service aligned with priviacy requirements, and who are comfortable getting flexible automation without a graphical user interface.\n\nFor each configured domain, MX records are added with latency-based routing to ensure clients may use the geographically \"local\" regional endpoint, with the email content remaining \"in region\" and a global DynamoDB table with replication to store \"mailbox\" metadata (no PII). SPF, DKIM and DMARC are also configured for each domain to support reliable email delivery. This robust infrastructure ensures that email communication remains functional even in the face of an entire AWS region going down or large-scale internet outages (e.g. a broken undersea cable).\n\nReceived/inbound email generates EventBridge events that may be used to trigger a wide varierty of automated processes. \n\n# Features\n\nThis is a work in progress serverless system for receiving email, and it already has some pretty subsstantial advantages (and obvious disadvantages) over typical \"self hosted\" setups. Here is what you get:\n\n- Very inexpensive (essentially free for low email volumes).\n- Emails arriving at your domains are handled in the \"closest\" region you've configured, parsed and the attachments and embedded parts (images) extracted to your region's S3 bucket.  \n- The location of the message is added to the DDB table along with the date, so there is only one place to look for a record of what emails arrived in each region. \n- The S3 URIs to the message objects and other metadata (subject, sender, to, cc, subject, etc.) are combined into a JSON object which is saved alongside the contents in S3, as well as broadcast to EventBridge for handling in downstream processes.\n- Multi-region deployment and latency-based routing in Route53 ensure industrial-strength availability.\n- Optionally, the region-specific domain name list allows you to control where emails are stored (e.g. keeping all email to your .uk domain in Ireland and your .com domain in the US).\n\nSpeaking of spam, for kicks this repository can use the OpenAI API to summarize the email body. To use this feature you'll need to set up an OpenAI account and add an AWS SecretsManager secret called \"OPENAPI\" with a key \"API_TOKEN\" and the value being your API token (make sure to use the replication feature to easily make it available in the three regions).  If you don't want to use this feature, just put a placeholder in for the token and it'll work just fine.\n\n# Caveats\n\nYou don't get a UI or any kind of client, so instead of using `rmail` you're going to be automatically processing email or using `aws dynamodb query ... | aws s3api ...` commands to read that spam.\n\nAlso please note that while the resources created by this repository are very inexpensive, they are not free, and in certain circumstances can become expensive. Please be aware of the pricing and take it into consideration.\n\nThis solution may not align with your concept of a production-quality stack, as it's a work in progress. It doesn't have managed encryption, relies on AWS for spam protection (which you are responsible for paying for), and doesn't include logging or monitoring, among other things.\n\nUse this solution at your own risk.\n\n# Prerequisities and Deployment (CLI and CodeBuild)\n- ### ForEach Macro\nBefore deploying this solution, you'll need to install the [ForEach cloudformation macro](https://github.com/mlhpdx/cloudformation-macros) in your AWS account. Using this macro makes customizing the list of domains much easier and is worth the effort.\n\n- ### .Net 8 SDK\nThis repository includes a Lambda function using the .Net 8 managed runtime. You'll need to have the .Net 8 SDK installed wherever you're building it (locally and/or in CodeBuild).\n\n- ### Decide which Regions to Deploy\nThis service may deploy to any combination of the [AWS regions that support SES email receiving](https://docs.aws.amazon.com/ses/latest/dg/regions.html#region-receive-email) (the default is `us-west-2`, `us-east-1`, and `eu-west-1`). SES email receiving is not available in all regions, so you'll need to choose from the available regions. The resources created by this solution are inexpensive but please be aware of the pricing and take it into consideration.\n\nSet the environment variable `DEPLOY_TO_REGIONS` to a space-separated list of regions you want to deploy to (either in your CLI or CodeBuild).\n\n```bash\n\u003e export DEPLOY_TO_REGIONS=\"us-west-2 us-east-1 ca-central-1 ap-northeast-1 eu-west-1\"\n```\n\n- ### Registered Domain Names in SSM\nYou must have control of the domain names you want to use with this service, and have DNS service for them provided by AWS Route53.\n\nThe domain names to enabled with email receiving are defined in a ParameterStore value called `/config/prod/email-delivery/DOMAIN_NAMES`. Add your list of domains to that value *in each region* as a comma-separated (no spaces) list. The lists can be the same or different in each region.\n\n```bash\n\u003e export DOMAIN_NAMES=foo.com,bar.com,baz.com\n\n\u003e for REGION in us-west-2 us-east-1 eu-west-1; do aws ssm put-parameter --name \"/config/prod/email-delivery/DOMAIN_NAMES\" --value $DOMAIN_NAMES --type String --region $REGION; done  \n```\n\n- ### Hosted Zones\nBefore the deployment, you'll need hosted zones in Route 53 for the domain names you're using. Create them if you don't already have them. Default, empty zones are fine.\n\n```bash\n\u003e for DOMAIN in $(echo $DOMAIN_NAMES | tr \",\" \" \"); do aws route53 create-hosted-zone --name $DOMAIN --caller-reference \"create for email delivery\"; done\n```\n\n- ### Buckets for Deployment in Each Region\nUsing AWS SAM means having a bucket to hold the built artifacts before they can be sent to CloudFormation.  You probably have such a bucket, but you may not have one in each region following a prefix/region naming pattern.\n\n```bash\n\u003e export BUCKET_NAME_PREFIX=my-build-bucket-name\n\n\u003e for REGION in $DEPLOY_TO_REGIONS; do aws s3 create-bucket --bucket $BUCKET_NAME_PREFIX-$REGION --region $REGION; done\n```\n\n- ### API Gateway CloudWatch Logs Role ARN is Set\nSee: https://www.chrisarmstrong.dev/posts/setting-up-api-gateway-cloudwatch-logging-for-your-aws-account\n\n## CodeBuild (optional)\nThis repository contains structured (nested) AWS SAM templates and includes buildspecs to use with CodeBuild. If you want to use this method of ci/cd, you'll need to set up a CodeBuild project in region `us-west-2` configured for \"batch\" builds and point it to this repo (or your own fork). The service role for that CodeBuild project will need permissions for IAM, DDB, Step Functions, Route53, S3, and probably more. \n\nIf you wish to support regions other than the default, set the environment variable `DEPLOY_TO_REGIONS` on the code build project to a space-separated list of regions (e.g. `us-west-2 us-east-1 eu-west-1 eu-west-2`).\n\n## Deployment Scripts\nYou can also deploy this solution from the command line if you have the AWS CLI version 2 installed and appropriate credentials configured. The scripts folder contains everything you need, and is probably easier than CodeBuild if you're just \"having a look\". \n\nTo run the scripts locally you'll need to:\n\n- Install `cfn-lint` (e.g. `pip install cfn-lint`).\n- Set the `BUCKET_NAME_PREFIX` environment variable to the prefix of the name of the buckets you want to use for the deployment artifacts (the region will be added automatically as a suffix).\n- Set the `BUCKET_KEY_PREFIX` environment variable to the prefix of the key you want to use for the deployment artifacts (a suffix will be appended of the artifacts created for each deploy by `sam deploy`).\n- If not already set, set the `DOMAIN_NAMES` environment variable to your comma-separated (no spaces) list of domain names.\n- Optionally, set the `DEPLOY_TO_REGIONS` environment variable to a space-separated list of regions you want to deploy to (e.g. `us-west-2 us-east-1 eu-west-1`).\n\nNote that the scripts assume that they'll be run from the repository root:\n\n```bash\n\u003e ./scripts/checks.sh \u0026\u0026 ./scripts/deploy-global.sh \u0026\u0026 ./scripts/deploy-region.sh\n```\n\nOnce you run the scripts, the global resources will be created in a stack called email-delivery-global, and a stack called `email-delivery` will be ready in `us-west-1`, `us-east-2` and `eu-west-1`.\n\n## Activate SES Rule Sets\n\nAfter the first deployment is finished you'll need to go to each SES region and manually activate the rule sets under \"Email Receiving\" in the SES Console. You only need to do this once when initially setting-up the stacks (not with each subsequent deployment).  As far as I know this can't be done via CloudFormation.\n\n# License\nThis code is available under the MIT license. If you find it helpful, please consider sending me a note or giving me credit. Enjoy!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmlhpdx%2Femail-delivery","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmlhpdx%2Femail-delivery","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmlhpdx%2Femail-delivery/lists"}