
Smart Notification Routing on AWS with SNS, Lambda, and CDK
Build a smart alert routing solution on AWS using Amazon SNS, AWS Lambda, and AWS CDK. Using SNS filter policies and message attributes, notifications are automatically routed based on team and severity levels (INFO, WARNING, CRITICAL). This serverless approach reduces infrastructure complexity while ensuring the right people receive the right alerts at the right time.
Introduction
When multiple teams and applications start sending alerts on AWS, managing notifications can quickly become messy. Creating separate SNS topics for every alert type, severity, or team often leads to duplicated configurations and infrastructure that becomes difficult to maintain over time.
In this project, we’ll build a simpler and more scalable solution using Amazon SNS filter policies, AWS Lambda, and AWS CDK. Instead of creating many SNS topics, we’ll use a single centralized topic and route alerts automatically based on attributes like severity (INFO, WARNING, CRITICAL) and team name.
The result is a clean serverless alerting system where developers only receive relevant alerts, while critical notifications can still be sent to everyone when needed.
We’ll show you how to do this in the following steps:
- Step 1: Create the CDK project
- Step 2: Install Project Dependencies
- Step 3: Create the SNS Topic and Subscriptions
- Step 4: Create the Lambda Publisher Function
- Step 5: Add the Lambda Function to the CDK Stack
- Step 6: Configure the CDK Application Entry Point
- Step 7: Bootstrap and Deploy the Infrastructure
- Step 8: Test the Alert Routing System
Architecture
The AWS solution we are building provides:
- Operational Excellence: This solution improves operational excellence by centralizing alert management and automating notification routing using SNS filter policies. Using AWS CDK also enables consistent and repeatable infrastructure deployments.
- Performance Efficiency: Using lightweight serverless services allows the solution to scale automatically based on alert traffic. SNS filter policies also reduce unnecessary notifications and processing overhead.
- Cost Optimization: A centralized SNS topic reduces infrastructure complexity and avoids creating multiple topics for every alert type. Since the solution is fully serverless, costs remain low with pay-per-use pricing.
Here’s an architecture diagram of what we’ll implement:

Key concepts
Before beginning the practical steps, let’s understand the main AWS services and concepts used in this solution.
- SNS Filter Policies: SNS filter policies allow subscriptions to receive only specific messages based on message attributes. Instead of creating multiple SNS topics, we can use a single topic and automatically route alerts depending on attributes such as severity, team, or environment.
- Message Attributes: Message attributes are metadata attached to SNS messages. In this solution, attributes like severity=CRITICAL or team=dev are used by SNS filter policies to determine which subscribers should receive each alert.
- AWS CDK: AWS Cloud Development Kit (CDK) is an Infrastructure as Code (IaC) framework that allows AWS resources to be defined using programming languages such as Python. We will use CDK to provision the SNS topic, subscriptions, filter policies, and Lambda function.
Now that we’ve covered the core components, let’s see how they all fit together.
Steps
Step 1: Create the CDK Project
In this step, we initialize a new AWS CDK application using Python. This project will contain all the infrastructure code required to deploy the SNS topic, Lambda function, subscriptions, and filter policies. Organizing the project from the beginning helps keep the infrastructure modular and easier to maintain as the solution grows.
Bash
mkdir alerting-systemcd alerting-systemcdk init app --language python
Output:

After running the command, the following folders are created:
plaintext
+---alerting-system| | .gitignore| | app.py| | cdk.json| | README.md| | requirements-dev.txt| | requirements.txt| | source.bat| || +---alerting_system| | alerting_system_stack.py| | __init__.py| || \---tests| | __init__.py| || \---unit| test_alerting_system_stack.py| __init__.py|
Step 2: Install Project Dependencies
Before writing any infrastructure code, we need to install the AWS CDK libraries and required Python packages. These dependencies provide the constructs and modules used to define AWS resources programmatically.
Run the following command to install dependencies:
Bash
pip install aws-cdk-lib constructs
Output:

Step 3: Create the SNS Topic and Subscriptions
Here, we create a centralized SNS topic that will handle all alerts in the system. We also configure email subscriptions with SNS filter policies so that notifications are routed only to the appropriate recipients based on attributes like severity or team name.
For the filter policies, we want developers to receive all notifications regardless of their severity ("INFO", "WARNING", or "CRITICAL"). As long as the message contains the attribute "team=dev", it should be delivered to the development team.
For the rest of the stakeholders, such as Operations and Managers, we only want to notify them when immediate attention is required. To achieve this, we'll configure a filter policy that only delivers messages where the "severity" attribute is set to "CRITICAL".
Create stacks/alerts_stack.py
Python
from aws_cdk import (Stack,aws_sns as sns,aws_sns_subscriptions as subs,)from constructs import Constructclass AlertsStack(Stack):def __init__(self,scope: Construct,construct_id: str,developer_emails: list[str],everyone_emails: list[str],**kwargs):super().__init__(scope, construct_id, **kwargs)alerts_topic = sns.Topic(self,"CentralAlertsTopic",topic_name="central-alerts-topic")# Developers subscriptionfor email in developer_emails:alerts_topic.add_subscription(subs.EmailSubscription(email,filter_policy={"team": sns.SubscriptionFilter.string_filter(allowlist=["dev"])}))# Everyone receives CRITICAL alertsfor email in everyone_emails:alerts_topic.add_subscription(subs.EmailSubscription(email,filter_policy={"severity": sns.SubscriptionFilter.string_filter(allowlist=["CRITICAL"])}))
Step 4: Create the Lambda Publisher Function
In this step, we build the Lambda function responsible for publishing messages to the SNS topic. The function receives alert details such as severity, environment, and team, then attaches them as SNS message attributes for filtering and routing.
Create Lambda Directory
Bash
mkdir -p lambda/publisher
Create lambda/publisher/handler.py
Python
import osimport jsonimport boto3from botocore.exceptions import ClientErrorsns = boto3.client("sns")TOPIC_ARN = os.environ["TOPIC_ARN"]def lambda_handler(event, context):try:response = sns.publish(TopicArn=TOPIC_ARN,Subject=event["subject"],Message=event["message"],MessageAttributes={"severity": {"DataType": "String","StringValue": event["severity"]},"team": {"DataType": "String","StringValue": event["team"]},"environment": {"DataType": "String","StringValue": event["environment"]}})return {"statusCode": 200}except ClientError as e:print(f"SNS publish failed: {e}")return {"statusCode": 500,"body": json.dumps({"error": str(e)})}except Exception as e:print(f"Unexpected error: {e}")return {"statusCode": 500,"body": json.dumps({"error": "Unexpected error occurred"})}
Step 5: Add the Lambda Function to the CDK Stack
Now we need to connect the Lambda function to the infrastructure stack and grant it permission to publish messages to the SNS topic.
Update stacks/alerts_stack.py
Python
from aws_cdk import (Stack,aws_sns as sns,aws_sns_subscriptions as subs,Duration,aws_lambda as _lambda,)from constructs import Constructclass AlertsStack(Stack):…# Lambda function to publish alertspublisher_lambda = _lambda.Function(self,"AlertsPublisherLambda",runtime=_lambda.Runtime.PYTHON_3_12,handler="handler.lambda_handler",code=_lambda.Code.from_asset("lambda/publisher"),timeout=Duration.seconds(30),environment={"TOPIC_ARN": alerts_topic.topic_arn})# Grant the Lambda function permissions to publish to the SNS topicalerts_topic.grant_publish(publisher_lambda)
Step 6: Configure the CDK Application Entry Point
The CDK application entry point connects all infrastructure components together. This file initializes the stack and prepares the project for synthesis and deployment into the AWS account.
Update app.py
Python
#!/usr/bin/env python3import aws_cdk as cdkfrom stacks.alerts_stack import AlertsStackapp = cdk.App()developer_emails = (app.node.try_get_context("developerEmails")or "developer@example.com").split(",")everyone_emails = (app.node.try_get_context("everyoneEmails")or "everyone@example.com").split(",")AlertsStack(app,"AlertsStack",developer_emails=developer_emails,everyone_emails=everyone_emails)app.synth()
Step 7: Bootstrap and Deploy the Infrastructure
Before deploying CDK applications for the first time, AWS requires a bootstrap process. After bootstrapping, we can deploy the entire serverless alerting solution directly from the terminal.
This creates:
- S3 bucket for CDK assets
- IAM roles for deployments
- CloudFormation stack
- Bootstrap AWS Environment:
Bash
cdk bootstrap
Output:

From the Console, a new Cloudformation stack was created:

- Deploy the Stack:
Bash
cdk deploy \-c developerEmails=dev1@example.com,dev2@example.com \-c everyoneEmails=all@example.com,manager@example.com
Output:

After deployment, SNS will send email confirmation links to subscribers. The email subscription requires the recipient to click a confirmation link. Until confirmed, the subscription remains in a pending state.
>> Result: The developers and the manager, will all receive the following email

Step 8: Test the Alert Routing System
Finally, we test the solution by invoking the Lambda function with different alert payloads. This validates that SNS filter policies are correctly routing notifications based on message attributes.
- Test CRITICAL Alert
Note update the function-name from what the CDK generated
Bash
aws lambda invoke \--function-name AlertsStack-AlertsPublisherLambda \--cli-binary-format raw-in-base64-out \--payload '{"subject":"Production Outage","message":"Payments API is down","severity":"CRITICAL","team":"dev","environment":"prod"}' \response.json
Output:

>> Result: All the subscribers received this email

- Test Dev Alert
Bash
aws lambda invoke \--function-name AlertsStack-AlertsPublisherLambda \--cli-binary-format raw-in-base64-out \--payload '{"subject":"ETL Completed","message":"Daily ETL succeeded","severity":"INFO","team":"dev","environment":"prod"}' \response.json
Output:

>> Result: Only dev team received this email notifications

Conclusion
In this article, we built a smart alert routing solution using AWS Lambda, Amazon SNS, SNS filter policies, and AWS CDK. By using a single SNS topic and message attributes, we were able to route notifications to the right audience based on severity and team, while keeping the architecture simple and scalable.
This approach reduces infrastructure complexity, lowers operational overhead, and provides a flexible foundation that can easily be extended as notification requirements grow.
References
- What is Amazon SNS? https://docs.aws.amazon.com/sns/latest/dg/welcome.html
- What is AWS Lambda? https://docs.aws.amazon.com/lambda/latest/dg/welcome.html
- Create your first Lambda function https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html
- What is Event-Driven Architecture? https://aws.amazon.com/event-driven-architecture/
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article