Package: ses-email-forwarding
@seeebiii/ses-email-forwardingThisAWS CDKconstruct allows you to setup email forwarding mappings inAWS SESto 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 domainexample.organd want to receive emails forhello@example.organdprivacy@example.org, you can forward emails towhatever@provider.com.
This is achieved by using a Lambda function that forwards the emails usingaws-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 theArchitecturesection below if you want to know more about the details.ExamplesForward all emails received underhello@example.orgtowhatever+hello@provider.com:newEmailForwardingRuleSet(this,'EmailForwardingRuleSet',{// make the underlying rule set the active oneenableRuleSet:true,// define how emails are being forwardedemailForwardingProps:[{// your domain name you want to use for receiving and sending emailsdomainName:'example.org',// a prefix that is used for the From email address to forward your mailsfromPrefix:'noreply',// a list of mappings between a prefix and target email addressemailMappings:[{// the prefix matching the receiver address as <prefix>@<domainName>receivePrefix:'hello',// the target email address(es) that you want to forward emails totargetEmails:['whatever+hello@provider.com']}]}]});Forward all emails for a domainexample.orgtowhatever+hello@provider.com:newEmailForwardingRuleSet(this,'EmailForwardingRuleSet',{// make the underlying rule set the active oneenableRuleSet:true,// define how emails are being forwardedemailForwardingProps:[{// your domain name you want to use for receiving and sending emailsdomainName:'example.org',// a prefix that is used for the From email address to forward your mailsfromPrefix:'noreply',// a list of mappings between a prefix and target email addressemailMappings:[{// matches all email addresses for 'example.org'receiveEmail:'@example.org',// the target email address(es) that you want to forward emails totargetEmails:['whatever+hello@provider.com']}]}]});Forward all emails tohello@example.orgtowhatever+hello@provider.comand verify the domainexample.orgin SES:newEmailForwardingRuleSet(this,'EmailForwardingRuleSet',{emailForwardingProps:[{domainName:'example.org',// let the construct automatically verify your domainverifyDomain:true,fromPrefix:'noreply',emailMappings:[{receivePrefix:'hello',targetEmails:['whatever+hello@provider.com']}]}]});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 propertyverifyTargetEmailAddressesin this case and set it totrue.For a full & up-to-date reference of the available options, please look at the source code ofEmailForwardingRuleSetandEmailForwardingRule.NoteSince 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:constapp=newcdk.App();classEmailForwardingSetupStackextendscdk.Stack{constructor(scope:cdk.Construct,id:string,props?:cdk.StackProps){super(scope,id,props);newEmailForwardingRuleSet(this,'EmailForwardingRuleSet',{//defineyourconfighere});}}newEmailForwardingSetupStack(app,'EmailForwardingSetupStack',{env:{account:'<account-id>',region:'<region>'}});Use CasesBuild 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 :)Installnpmnpmi-D@seeebiii/ses-email-forwardingTake a look atpackage.jsonto make sure you're installing the correct version compatible with your current AWS CDK version.
See more details on npmjs.com:https://www.npmjs.com/package/@seeebiii/ses-email-forwardingMaven<dependency><groupId>de.sebastianhesse.cdk-constructs</groupId><artifactId>ses-email-forwarding</artifactId><version>4.0.1</version></dependency>See more details on mvnrepository.com:https://mvnrepository.com/artifact/de.sebastianhesse.cdk-constructs/ses-email-forwarding/Example Codepackagecom.example;importde.sebastianhesse.cdk.ses.email.forwarding.EmailForwardingProps;importde.sebastianhesse.cdk.ses.email.forwarding.EmailForwardingRuleSet;importde.sebastianhesse.cdk.ses.email.forwarding.EmailMapping;importjava.util.Arrays;importsoftware.amazon.awscdk.core.App;importsoftware.amazon.awscdk.core.Construct;importsoftware.amazon.awscdk.core.Environment;importsoftware.amazon.awscdk.core.Stack;importsoftware.amazon.awscdk.core.StackProps;publicclassSesEmailForwardingJavaTestApp{publicstaticvoidmain(finalString[]args){Appapp=newApp();newSesEmailForwardingJavaTestStack(app,"CdkEmailForwardingJavaTestStack",StackProps.builder().env(Environment.builder().account("123456789")// TODO: replace with your account id.region("us-east-1")// TODO: replace with your region.build()).build());app.synth();}staticclassSesEmailForwardingJavaTestStackextendsStack{publicSesEmailForwardingJavaTestStack(finalConstructscope,finalStringid){this(scope,id,null);}publicSesEmailForwardingJavaTestStack(finalConstructscope,finalStringid,finalStackPropsprops){super(scope,id,props);EmailForwardingPropsexampleProperties=EmailForwardingProps.builder().domainName("example.org")// true if you own the domain in Route53, false if you need to manually verify it.verifyDomain(true).fromPrefix("noreply").emailMappings(Arrays.asList(EmailMapping.builder().receiveEmail("hello@example.org").targetEmails(Arrays.asList("email+hello@provider.com")).build(),EmailMapping.builder().receiveEmail("privacy@example.org").targetEmails(Arrays.asList("email+privacy@provider.com")).build())).build();EmailForwardingRuleSet.Builder.create(this,"example-rule-set").ruleSetName("example-rule-set").emailForwardingProps(Arrays.asList(exampleProperties)).build();}}}Pythonpipinstallses-email-forwardingSee 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# Create a new directorymkdirExampleApplication&&cdExampleApplication# Scaffold a C# CDK projectcdkinit--languagecsharp# Add dependenciescdsrc/ExampleApplication
dotnetaddpackageSes.Email.Forwarding
dotnetaddpackageAmazon.CDK.AWS.SNS.Subscriptions# Remove example stack and global suppressions (silenced by way of using discards)rmExampleApplicationStack.csGlobalSuppressions.csExample UsageusingAmazon.CDK;usingAmazon.CDK.AWS.SNS;usingAmazon.CDK.AWS.SNS.Subscriptions;usingSebastianHesse.CdkConstructs;usingConstruct=Constructs.Construct;namespaceExampleApplication{publicsealedclassProgram{publicstaticvoidMain(){varapp=newApp();_=newMailboxStack(app,nameof(MailboxStack),newStackProps{Env=newEnvironment{// Replace with desired accountAccount="000000000000",// Replace with desired regionRegion="us-east-1"}});app.Synth();}}publicsealedclassMailboxStack:Stack{publicMailboxStack(Constructscope,stringid,IStackPropsprops=null):base(scope,id,props){varnotificationTopic=newTopic(this,nameof(EmailForwardingProps.NotificationTopic));// 'Bounce' and 'Complaint' notification types, in association with the domain being verified, will be sent// to this email addressnotificationTopic.AddSubscription(newEmailSubscription("admin@provider.com"));_=newEmailForwardingRuleSet(this,nameof(EmailForwardingRuleSet),newEmailForwardingRuleSetProps{EmailForwardingProps=newIEmailForwardingProps[]{newEmailForwardingProps{// If your domain name has already been verified as a domain identity in SES, this does not// need to be toggled onVerifyDomain=true,// This is the prefix that will be used in the email address used to forward emailsFromPrefix="noreply",// This domain name will be used to send and receive emailsDomainName="example.org",// A list of mappings between a prefix and target email addressesEmailMappings=newIEmailMapping[]{newEmailMapping{// Emails received by hello@example.org will be forwardedReceivePrefix="hello",// Emails will be forwarded to admin+hello@provider.comTargetEmails=new[]{"admin+hello@provider.com"}}},// This notification topic be published to when events in association with 'Bounce' and// 'Complaint' notification types occurNotificationTopic=notificationTopic}}});}}}UsageThis package provides two constructs:EmailForwardingRuleSetandEmailForwardingRule.
TheEmailForwardingRuleSetis a wrapper aroundReceiptRuleSetbut adds a bit more magic to e.g. verify a domain or target email address.
Similarly,EmailForwardingRuleis a wrapper aroundReceiptRulebut adds two SES rule actions to forward the email addresses appropriately.This means if you want the full flexibility, you can use theEmailForwardingRuleconstruct in your stack.Sending E-Mails over SMTPYou 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 theEmailForwardingRuleSetConstruct:Set theverifyDomainorverifyTargetEmailAddressestotrue.Create SMTP credentials in AWS SESand save them somewhere.Setup your email program or application to use the SMTP settings.ArchitectureTheEmailForwardingRuleSetcreates aEmailForwardingRulefor each forward mapping.
Each rule contains anS3Actionto 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 theaws-lambda-ses-forwarderlibrary.
Since this library expects a JSON config with the email mappings, theEmailForwardingRulewill 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, theEmailForwardingRuleSetconstruct is using the package@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.TODOEncrypt email files on S3 bucket by either using S3 bucket encryption (server side) or enable client encryption using SES actionsContributingI'm happy to receive any contributions!
Just open an issue or pull request :)These commands should help you while developing:npx projeninitprojenand synthesize changes in.projenrc.jsto the projectyarn buildcompile typescript to jsyarn watchwatch for changes and compileyarn testperform the jest unit testsyarn eslintvalidate code against best practicesThanksThanks a lot toarithmetricfor providing the NPM packageaws-lambda-ses-forwarder.
This CDK construct is using it in the Lambda function to forward the emails.AuthorSebastian Hesse- Freelancer for serverless cloud projects on AWS.LicenseMIT LicenseCopyright (c) 2022Sebastian HessePermission 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.