项目作者: seeebiii

项目描述 :
AWS CDK constructs to receive emails with SES and forward them to any other email address.
高级语言: TypeScript
项目地址: git://github.com/seeebiii/ses-email-forwarding.git
创建时间: 2021-01-14T10:35:54Z
项目社区:https://github.com/seeebiii/ses-email-forwarding

开源协议:MIT License

下载


@seeebiii/ses-email-forwarding

This AWS CDK construct allows you to setup email forwarding mappings in AWS SES to receive emails from your domain and forward them to another email address.
All of this is possible without hosting your own email server, you just need a domain.

For example, if you own a domain example.org and want to receive emails for hello@example.org and privacy@example.org, you can forward emails to whatever@provider.com.
This is achieved by using a Lambda function that forwards the emails using aws-lambda-ses-forwarder.

This construct is creating quite a few resources under the hood and can also automatically verify your domain and email addresses in SES.
Consider reading the Architecture section below if you want to know more about the details.

Examples

Forward all emails received under hello@example.org to whatever+hello@provider.com:

  1. new EmailForwardingRuleSet(this, 'EmailForwardingRuleSet', {
  2. // make the underlying rule set the active one
  3. enableRuleSet: true,
  4. // define how emails are being forwarded
  5. emailForwardingProps: [{
  6. // your domain name you want to use for receiving and sending emails
  7. domainName: 'example.org',
  8. // a prefix that is used for the From email address to forward your mails
  9. fromPrefix: 'noreply',
  10. // a list of mappings between a prefix and target email address
  11. emailMappings: [{
  12. // the prefix matching the receiver address as <prefix>@<domainName>
  13. receivePrefix: 'hello',
  14. // the target email address(es) that you want to forward emails to
  15. targetEmails: ['whatever+hello@provider.com']
  16. }]
  17. }]
  18. });

Forward all emails for a domain example.org to whatever+hello@provider.com:

  1. new EmailForwardingRuleSet(this, 'EmailForwardingRuleSet', {
  2. // make the underlying rule set the active one
  3. enableRuleSet: true,
  4. // define how emails are being forwarded
  5. emailForwardingProps: [{
  6. // your domain name you want to use for receiving and sending emails
  7. domainName: 'example.org',
  8. // a prefix that is used for the From email address to forward your mails
  9. fromPrefix: 'noreply',
  10. // a list of mappings between a prefix and target email address
  11. emailMappings: [{
  12. // matches all email addresses for 'example.org'
  13. receiveEmail: '@example.org',
  14. // the target email address(es) that you want to forward emails to
  15. targetEmails: ['whatever+hello@provider.com']
  16. }]
  17. }]
  18. });

Forward all emails to hello@example.org to whatever+hello@provider.com and verify the domain example.org in SES:

  1. new EmailForwardingRuleSet(this, 'EmailForwardingRuleSet', {
  2. emailForwardingProps: [{
  3. domainName: 'example.org',
  4. // let the construct automatically verify your domain
  5. verifyDomain: true,
  6. fromPrefix: 'noreply',
  7. emailMappings: [{
  8. receivePrefix: 'hello',
  9. targetEmails: ['whatever+hello@provider.com']
  10. }]
  11. }]
  12. });

If you don’t want to verify your domain in SES or you are in the SES sandbox, you can still send emails to verified email addresses.
Use the property verifyTargetEmailAddresses in this case and set it to true.

For a full & up-to-date reference of the available options, please look at the source code of EmailForwardingRuleSet and EmailForwardingRule.

Note

Since the verification of domains requires to lookup the Route53 domains in your account, you need to define your AWS account and region.
You can do it like this in your CDK stack:

  1. const app = new cdk.App();
  2. class EmailForwardingSetupStack extends cdk.Stack {
  3. constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
  4. super(scope, id, props);
  5. new EmailForwardingRuleSet(this, 'EmailForwardingRuleSet', {
  6. // define your config here
  7. });
  8. }
  9. }
  10. new EmailForwardingSetupStack(app, 'EmailForwardingSetupStack', {
  11. env: {
  12. account: '<account-id>',
  13. region: '<region>'
  14. }
  15. });

Use Cases

  • Build a landing page on AWS and offer an email address to contact you.
  • Use various aliases to register for different services and forward all mails to the same target email address.

There are probably more - happy to hear them :)

Install

npm

  1. npm i -D @seeebiii/ses-email-forwarding

Take a look at package.json to make sure you’re installing the correct version compatible with your current AWS CDK version.
See more details on npmjs.com: @seeebiii/ses-email-forwarding"">https://www.npmjs.com/package/@seeebiii/ses-email-forwarding

Maven

  1. <dependency>
  2. <groupId>de.sebastianhesse.cdk-constructs</groupId>
  3. <artifactId>ses-email-forwarding</artifactId>
  4. <version>4.0.1</version>
  5. </dependency>

See more details on mvnrepository.com: https://mvnrepository.com/artifact/de.sebastianhesse.cdk-constructs/ses-email-forwarding/

Example Code

  1. package com.example;
  2. import de.sebastianhesse.cdk.ses.email.forwarding.EmailForwardingProps;
  3. import de.sebastianhesse.cdk.ses.email.forwarding.EmailForwardingRuleSet;
  4. import de.sebastianhesse.cdk.ses.email.forwarding.EmailMapping;
  5. import java.util.Arrays;
  6. import software.amazon.awscdk.core.App;
  7. import software.amazon.awscdk.core.Construct;
  8. import software.amazon.awscdk.core.Environment;
  9. import software.amazon.awscdk.core.Stack;
  10. import software.amazon.awscdk.core.StackProps;
  11. public class SesEmailForwardingJavaTestApp {
  12. public static void main(final String[] args) {
  13. App app = new App();
  14. new SesEmailForwardingJavaTestStack(app, "CdkEmailForwardingJavaTestStack", StackProps.builder()
  15. .env(Environment.builder()
  16. .account("123456789") // TODO: replace with your account id
  17. .region("us-east-1") // TODO: replace with your region
  18. .build()
  19. )
  20. .build());
  21. app.synth();
  22. }
  23. static class SesEmailForwardingJavaTestStack extends Stack {
  24. public SesEmailForwardingJavaTestStack(final Construct scope, final String id) {
  25. this(scope, id, null);
  26. }
  27. public SesEmailForwardingJavaTestStack(final Construct scope, final String id, final StackProps props) {
  28. super(scope, id, props);
  29. EmailForwardingProps exampleProperties = EmailForwardingProps.builder()
  30. .domainName("example.org")
  31. // true if you own the domain in Route53, false if you need to manually verify it
  32. .verifyDomain(true)
  33. .fromPrefix("noreply")
  34. .emailMappings(Arrays.asList(
  35. EmailMapping.builder()
  36. .receiveEmail("hello@example.org")
  37. .targetEmails(Arrays.asList("email+hello@provider.com"))
  38. .build(),
  39. EmailMapping.builder()
  40. .receiveEmail("privacy@example.org")
  41. .targetEmails(Arrays.asList("email+privacy@provider.com"))
  42. .build()
  43. )
  44. )
  45. .build();
  46. EmailForwardingRuleSet.Builder.create(this, "example-rule-set")
  47. .ruleSetName("example-rule-set")
  48. .emailForwardingProps(Arrays.asList(exampleProperties))
  49. .build();
  50. }
  51. }
  52. }

Python

  1. pip install ses-email-forwarding

See more details on PyPi: https://pypi.org/project/ses-email-forwarding/

.NET / C

An artifact is pushed up to NuGet.org: https://www.nuget.org/packages/Ses.Email.Forwarding/

Project Scaffolding & Installation

  1. # Create a new directory
  2. mkdir ExampleApplication && cd ExampleApplication
  3. # Scaffold a C# CDK project
  4. cdk init --language csharp
  5. # Add dependencies
  6. cd src/ExampleApplication
  7. dotnet add package Ses.Email.Forwarding
  8. dotnet add package Amazon.CDK.AWS.SNS.Subscriptions
  9. # Remove example stack and global suppressions (silenced by way of using discards)
  10. rm ExampleApplicationStack.cs GlobalSuppressions.cs

Example Usage

  1. using Amazon.CDK;
  2. using Amazon.CDK.AWS.SNS;
  3. using Amazon.CDK.AWS.SNS.Subscriptions;
  4. using SebastianHesse.CdkConstructs;
  5. using Construct = Constructs.Construct;
  6. namespace ExampleApplication
  7. {
  8. public sealed class Program
  9. {
  10. public static void Main()
  11. {
  12. var app = new App();
  13. _ = new MailboxStack(app, nameof(MailboxStack), new StackProps
  14. {
  15. Env = new Environment
  16. {
  17. // Replace with desired account
  18. Account = "000000000000",
  19. // Replace with desired region
  20. Region = "us-east-1"
  21. }
  22. });
  23. app.Synth();
  24. }
  25. }
  26. public sealed class MailboxStack : Stack
  27. {
  28. public MailboxStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
  29. {
  30. var notificationTopic = new Topic(this, nameof(EmailForwardingProps.NotificationTopic));
  31. // 'Bounce' and 'Complaint' notification types, in association with the domain being verified, will be sent
  32. // to this email address
  33. notificationTopic.AddSubscription(new EmailSubscription("admin@provider.com"));
  34. _ = new EmailForwardingRuleSet(this, nameof(EmailForwardingRuleSet), new EmailForwardingRuleSetProps
  35. {
  36. EmailForwardingProps = new IEmailForwardingProps[]
  37. {
  38. new EmailForwardingProps
  39. {
  40. // If your domain name has already been verified as a domain identity in SES, this does not
  41. // need to be toggled on
  42. VerifyDomain = true,
  43. // This is the prefix that will be used in the email address used to forward emails
  44. FromPrefix = "noreply",
  45. // This domain name will be used to send and receive emails
  46. DomainName = "example.org",
  47. // A list of mappings between a prefix and target email addresses
  48. EmailMappings = new IEmailMapping[]
  49. {
  50. new EmailMapping
  51. {
  52. // Emails received by hello@example.org will be forwarded
  53. ReceivePrefix = "hello",
  54. // Emails will be forwarded to admin+hello@provider.com
  55. TargetEmails = new []
  56. {
  57. "admin+hello@provider.com"
  58. }
  59. }
  60. },
  61. // This notification topic be published to when events in association with 'Bounce' and
  62. // 'Complaint' notification types occur
  63. NotificationTopic = notificationTopic
  64. }
  65. }
  66. });
  67. }
  68. }
  69. }

Usage

This package provides two constructs: EmailForwardingRuleSet and EmailForwardingRule.
The EmailForwardingRuleSet is a wrapper around ReceiptRuleSet but adds a bit more magic to e.g. verify a domain or target email address.
Similarly, EmailForwardingRule is a wrapper around ReceiptRule but adds two SES rule actions to forward the email addresses appropriately.

This means if you want the full flexibility, you can use the EmailForwardingRule construct in your stack.

Sending E-Mails over SMTP

You can also send emails over SES using this construct because it provides the basics for sending emails: a verified SES domain or email address identity.
You need to do the following if you’re using the EmailForwardingRuleSetConstruct:

  1. Set the verifyDomain or verifyTargetEmailAddresses to true.
  2. Create SMTP credentials in AWS SES and save them somewhere.
  3. Setup your email program or application to use the SMTP settings.

Architecture

The EmailForwardingRuleSet creates a EmailForwardingRule for each forward mapping.
Each rule contains an S3Action to store the incoming emails and a Lambda Function to forward the emails to the target email addresses.
The Lambda function is just a thin wrapper around the aws-lambda-ses-forwarder library.
Since this library expects a JSON config with the email mappings, the EmailForwardingRule will create an SSM parameter to store the config.
(Note: this is not ideal because an SSM parameter is limited in the size and hence, this might be changed later)
The Lambda function receives a reference to this parameter as an environment variable (and a bit more) and forwards everything to the library.

In order to verify a domain or email address, the EmailForwardingRuleSet construct is using the package @seeebiii/ses-verify-identities"">@seeebiii/ses-verify-identities.
It provides constructs to verify the SES identities.
For domains, it creates appropriate Route53 records like MX, TXT and Cname (for DKIM).
For email addresses, it calls the AWS API to initiate email address verification.

TODO

  • Encrypt email files on S3 bucket by either using S3 bucket encryption (server side) or enable client encryption using SES actions

Contributing

I’m happy to receive any contributions!
Just open an issue or pull request :)

These commands should help you while developing:

  • npx projen init projen and synthesize changes in .projenrc.js to the project
  • yarn build compile typescript to js
  • yarn watch watch for changes and compile
  • yarn test perform the jest unit tests
  • yarn eslint validate code against best practices

Thanks

Thanks a lot to arithmetric for providing the NPM package aws-lambda-ses-forwarder.
This CDK construct is using it in the Lambda function to forward the emails.

Author

Sebastian Hesse - Freelancer for serverless cloud projects on AWS.

License

MIT License

Copyright (c) 2022 Sebastian Hesse

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.