In this blog post, we’ll discuss how to trigger a Typescript AWS Lambda function when you receive an email in AWS SES. We’ll be using SST V2 in this example, but it’s easily convertible to CDK if needed.
As a prerequisite, you’ll need to set up a verified identity and inbound rule in Route 53 for this to work. The docs found here are pretty straightforward.
Infrastructure as Code (IAC)
First, we need to set up the stack and IAC for the inbound rule and function.
import { StackContext, Function, use } from "sst/constructs"; | |
import * as ses from "aws-cdk-lib/aws-ses"; | |
import { Lambda, LambdaInvocationType } from "aws-cdk-lib/aws-ses-actions"; | |
export function Email({ stack }: StackContext) { | |
const emailReceivingFunction = new Function( | |
stack, | |
"email-receiving-function", | |
{ | |
handler: "path-to-your-function.handler", | |
} | |
); | |
new ses.ReceiptRuleSet(stack, `InboundEmailRuleset`, { | |
rules: [ | |
{ | |
enabled: true, | |
receiptRuleName: "InboundEmailLambda", | |
recipients: ["your-domain.com"], | |
actions: [ | |
new Lambda({ | |
function: emailReceivingFunction, | |
invocationType: LambdaInvocationType.EVENT, | |
}), | |
], | |
// Enable this to block spam emails if needed for your use case | |
// scanEnabled: true, | |
}, | |
], | |
}); | |
} |
Ensure to change the inbound domain and function path to fit your project. This will route all traffic from the domain to your lambda function.
We also need to go into the console and mark this inbound rule as active. Note you can only have one active rule per region per account — but nothing is stopping you from adding more domains to the recipients array. We’ll cover how to route to your desired operation below.
AWS Lambda Typescript Handler
Next, we need to set up the handler to perform whatever operation we need.
import { SESHandler } from "aws-lambda"; | |
// EXAMPLE FUNCTION | |
const unsubscribeFromEmails = async (email: string) => { | |
// Unsubscribe the user from emails in your system | |
}; | |
export const handler: SESHandler = async (event) => { | |
console.log("event", event); | |
await Promise.all( | |
event.Records.map(async ({ ses }) => { | |
const destination = ses.mail.destination[0]; | |
const sender = ses.mail.source; | |
if (!destination) { | |
console.log("No destination found for event", ses); | |
return; | |
} | |
// Here you can route the email based on the destination | |
// and use the email of the sender as per your requirements | |
const emailPrefix = destination.split("@")[0]; | |
switch (emailPrefix) { | |
case "unsubscribe": | |
return unsubscribeFromEmails(sender); | |
default: | |
console.log("No action found for email", destination); | |
return; | |
} | |
}) | |
); | |
}; |
With this function, we can perform whatever operation we need within our Typescript code.
Thanks for reading!
Top comments (0)