SNS Topic with Email and SQS Subscriptions
Scenario
Your application needs to send notifications when a critical event occurs — for example, when a deployment succeeds or fails. You want two things to happen simultaneously: an email alert to the on-call engineer, and a message pushed to an SQS queue for automated downstream processing. This is the classic fan-out pattern with SNS.
- Create an aws_sns_topic with KMS encryption enabled.
- Add an email subscription using aws_sns_topic_subscription with protocol email.
- Add an SQS subscription pointing to an existing SQS queue ARN (supplied as a variable), enabling the fan-out pattern where one message triggers both an email and a queue entry.
- Attach a topic policy granting the current account publish access.
- Output the topic ARN.
Additional Context
After terraform apply, the email subscription will be in PendingConfirmation state. AWS sends a confirmation email to the address you provided — you must click the link in it to activate the subscription. Terraform does not manage this manual confirmation step. The SQS subscription activates immediately.
For the SQS subscription to receive SNS messages, the SQS queue must have a queue policy that allows SNS to write to it. You will add a Condition in the queue policy using aws:SourceArn to restrict it to only this topic.
versions.tf
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
}variables.tf
variable "aws_region" { type = string; default = "us-east-1" }
variable "topic_name" { type = string; default = "deployment-events" }
variable "alert_email" { type = string; description = "Email address for critical alerts." }
variable "sqs_queue_arn" { type = string; description = "ARN of the SQS queue to fan messages to." }
variable "environment" { type = string; default = "dev" }main.tf
# main.tf
provider "aws" {
region = var.aws_region
}
data "aws_caller_identity" "current" {}
# SNS Topic — the central message bus.
resource "aws_sns_topic" "events" {
name = "${var.topic_name}-${var.environment}"
kms_master_key_id = "alias/aws/sns" # AWS-managed SNS encryption key
tags = { Environment = var.environment, ManagedBy = "terraform" }
}
# Topic policy — who can publish to and subscribe from this topic.
data "aws_iam_policy_document" "sns_policy" {
statement {
sid = "AllowAccountPublish"
effect = "Allow"
principals {
type = "AWS"
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
}
actions = ["sns:Publish", "sns:Subscribe", "sns:GetTopicAttributes"]
resources = [aws_sns_topic.events.arn]
}
}
resource "aws_sns_topic_policy" "events" {
arn = aws_sns_topic.events.arn
policy = data.aws_iam_policy_document.sns_policy.json
}
# Email subscription — sends an email when a message is published.
# Note: AWS sends a confirmation email; the subscription is pending until confirmed.
resource "aws_sns_topic_subscription" "email_alert" {
topic_arn = aws_sns_topic.events.arn
protocol = "email"
endpoint = var.alert_email
}
# SQS subscription — fans the same message to an SQS queue.
# Enables asynchronous, automated processing alongside the human email alert.
resource "aws_sns_topic_subscription" "sqs_fanout" {
topic_arn = aws_sns_topic.events.arn
protocol = "sqs"
endpoint = var.sqs_queue_arn
# raw_message_delivery = false means SQS receives the full SNS envelope (default).
# Set to true if your consumer expects plain JSON without the SNS wrapper.
raw_message_delivery = false
}
# Allow SNS to write messages to the SQS queue.
# Without this, the SQS queue will reject SNS delivery attempts.
data "aws_iam_policy_document" "sqs_allow_sns" {
statement {
sid = "AllowSNSToSendMessage"
effect = "Allow"
principals {
type = "Service"
identifiers = ["sns.amazonaws.com"]
}
actions = ["sqs:SendMessage"]
resources = [var.sqs_queue_arn]
condition {
test = "ArnEquals"
variable = "aws:SourceArn"
values = [aws_sns_topic.events.arn]
}
}
}
resource "aws_sqs_queue_policy" "allow_sns" {
queue_url = var.sqs_queue_arn
policy = data.aws_iam_policy_document.sqs_allow_sns.json
}outputs.tf
output "topic_arn" { value = aws_sns_topic.events.arn }
output "topic_name" { value = aws_sns_topic.events.name }Workflow Commands
terraform init
terraform apply \
-var="[email protected]" \
-var="sqs_queue_arn=$(cd ../lab07 && terraform output -raw queue_arn)"
# Publish a test notification
aws sns publish \
--topic-arn $(terraform output -raw topic_arn) \
--subject "Deployment Result" \
--message '{"status":"success","version":"1.4.2"}'
# Check the SQS queue for the fan-out message
aws sqs receive-message \
--queue-url YOUR_SQS_QUEUE_URL
terraform destroy -var="[email protected]" -var="sqs_queue_arn=..."Apply complete! Resources: 4 added, 0 changed, 0 destroyed. Outputs: topic_arn = "arn:aws:sns:us-east-1:123456789012:deployment-events-dev" topic_name = "deployment-events-dev" Note: Check your email for the SNS subscription confirmation link.

