Course outline

13.4

SNS, Fan-Out and Message Filtering

Pub/sub topics, SNS + SQS fan-out, filter policies and FIFO topics.

24 min Reading + animations

Tip: tap or hover any dotted-underlined term to see what it means.

By the end of this lesson you will be able to

  • Explain why sending one event to many receivers with direct calls couples the sender to every receiver, and how the publish/subscribe model of Amazon SNS removes that coupling.
  • Describe a topic, its publishers and its subscriptions, list the subscriber types (SQS, Lambda, Firehose, HTTP/S, email, SMS, mobile push) and the AWS services that publish to SNS, and know the limits that matter.
  • Build the SNS + SQS fan-out pattern correctly: queue access policies, KMS keys, cross-Region and cross-account queues, raw message delivery, and use it for S3 events and for archiving to S3 through Firehose.
  • Choose FIFO topics when order and deduplication matter, and predict their throughput, subscriber and replay behaviour.
  • Write subscription filter policies (attribute-based and payload-based) and predict exactly which subscriptions receive a message.
  • Explain how SNS retries failed deliveries, when a message is lost, and how a subscription dead-letter queue keeps it.

#One event, many receivers

#Direct calls tie the sender to everyone

Lessons 13.1 to 13.3 used a queue: one producer, one kind of consumer, and each message is processed once. Many events are different. When a customer places an order, several parts of the business must hear about it: the warehouse, the notification service, the fraud team, analytics. The same message must reach many receivers.

The direct way is for the order service to call each receiver itself, one after another. The slides draw this as a buying service calling an email notification, a fraud service, a shipping service and an SQS queue. It works on day one and hurts every day after:

  • Slow. The order service waits for every call, so each receiver adds its delay to the customer’s checkout.
  • Fragile. If one receiver is down or slow, the order service must decide whether to fail the order, retry or give up on that receiver. One weak receiver hurts every order.
  • Coupled. A new receiver means changing and redeploying the order service. The sender has to know every receiver’s address, protocol and quirks.

#Publish/subscribe

In the publish/subscribe (pub/sub) model, the sender does not talk to receivers at all. It publishes a message once to a topic, and every receiver that subscribed to the topic gets its own copy. The sender does not know who the receivers are, how many there are, or what they do with the message. Receivers can be added and removed without the sender noticing.

One order, many receivers

A Dhaka food-delivery app must tell the rider service, the fraud check and the customer about every new order. Compare calling each one directly with publishing once to an SNS topic.

Scenario

No topic: the order service knows every receiver and calls them one by one.

Order servicepublisher
SQS queuerider service
Lambdafraud check
Email / SMScustomer
call 1
Step 1 of 4
1

Without a topic, the order service has to call every receiver itself. First the rider service.

#Amazon SNS: topics, publishers and subscribers

Amazon Simple Notification Service (SNS) is AWS’s fully managed, push-based pub/sub messaging service. You do not run servers or brokers; you create topics and subscriptions, and SNS scales the delivery.

#The three parts

PartWhat it isExample
TopicA named, logical access point (a channel). Publishers send to it; it has an ARNarn:aws:sns:ap-southeast-1:111122223333:order-placed-example
PublisherAnything that sends a message to the topic: your application through the SDK or CLI, or an AWS servicethe order service, an S3 bucket, a CloudWatch alarm
SubscriptionOne endpoint registered on the topic, with its protocol and settings (filter policy, DLQ, raw delivery)an SQS queue, a Lambda function, an email address

Push vs pull is the first exam distinction. SQS is pull: consumers call ReceiveMessage and take messages when they are ready (lesson 13.1). SNS is push: it delivers to each endpoint as soon as the message is published, and nobody has to ask.

SNS is not a store. Once a message has been delivered (or retries run out), a standard topic keeps nothing. If a receiver needs to process later, retry its own work or survive a long outage, it should be an SQS queue subscribed to the topic. That is the fan-out pattern, below.

#Who publishes to SNS

Your own code publishes with the SDK or CLI, but many AWS services can publish to a topic directly, which is why SNS is the “notification bus” of AWS. The slides list a typical set:

  • CloudWatch alarms (“CPU above 80 %” → on-call email and SMS; lesson 19.3),
  • AWS Budgets (the billing alert from lesson 1.4),
  • Auto Scaling group notifications (instance launched, terminated or failed, lesson 6.5),
  • S3 event notifications (lesson 10.7),
  • Lambda (from your function code, or as an asynchronous invocation destination),
  • CloudFormation stack state changes, AWS DMS replication events, RDS event subscriptions (failover, backup, maintenance), DynamoDB (for example through CloudWatch alarms), and many more.

A service that publishes to your topic needs permission in the topic’s access policy (see security, below).

#Who can subscribe

GroupSubscriber (protocol)Typical use
AWS services (application-to-application, A2A)Amazon SQS queueDurable fan-out to workers; the most important one
AWS Lambda functionRun code on every message, invoked asynchronously
Amazon Data Firehose streamStore messages in S3, Redshift, OpenSearch, Splunk…
Custom endpointsHTTP / HTTPSWebhooks, partner or third-party APIs
People (application-to-person, A2P)Email / email-JSONAlerts to an inbox
SMS text messagesOTPs, order status, alerts to phones
Mobile pushNotifications to iOS, Android and Fire apps through APNs, FCM, ADM and others

Things that cannot subscribe directly: S3 buckets (use Firehose), Kinesis Data Streams, DynamoDB tables, EC2 instances (give them an HTTP endpoint or, better, an SQS queue). The exam likes to offer these as wrong answers.

Some details people miss:

  • Email and HTTP/S subscriptions must be confirmed. SNS sends a confirmation message; until someone clicks the link (or the endpoint calls ConfirmSubscription), the subscription is pending confirmation and receives nothing.
  • Email is for operational alerts, not for marketing or customer email at scale: it is limited to 10 messages per second per email subscription, and the sender address and format are SNS’s. For real customer email, use Amazon Simple Email Service.
  • SMS is delivered through AWS End User Messaging SMS (formerly Amazon Pinpoint SMS). New accounts start in an SMS sandbox with a $1 monthly spend limit, and many countries require a registered sender ID or number before messages are delivered.

#Standard and FIFO topics

Like SQS, SNS has two topic types:

  • Standard topics: nearly unlimited throughput, at-least-once delivery and best-effort ordering. Every subscriber type is supported. This is the default and the right answer for notifications and most fan-out.
  • FIFO topics (name ends in .fifo): strict ordering per message group and deduplication, at limited throughput, and only SQS queues as subscribers. They get their own section below.

#Limits worth knowing

ItemStandard topicFIFO topic
Topics per account100,0001,000
Subscriptions per topic12,500,000100
Message size256 KiB by default (body + attributes)same
Messages per PublishBatch call1010
Publish throughputA soft per-account quota per Region (for example 30,000 messages/s in us-east-1, 1,500 in Mumbai or Singapore)300 messages/s per message group; 3,000 messages/s or 20 MB/s per topic by default
Filter policies200 per topic, 10,000 per accountsame

Side note, verified in the AWS docs: since September 2026 a topic can accept payloads up to 1 MiB if you raise its MaximumMessageSize attribute, but only when every subscription is SQS, Lambda or Firehose and there are at most 100 subscriptions. Beyond that, the SNS Extended Client Library (Java, Python) stores the payload in S3 and publishes a pointer, up to 2 GB. For the exam, the SNS message limit is still 256 KB.

#How to publish

The slides name two ways:

  1. Topic publish (the normal case, with the SDK or CLI): create a topic, create one or many subscriptions, publish to the topic. Every subscription gets a copy. PublishBatch sends up to 10 messages in one call, which cuts API calls and cost.
  2. Direct publish (mobile apps): create a platform application with your credentials for a push service (APNs for Apple, FCM for Google, ADM for Amazon devices, plus Baidu and Windows push services), register each device token as a platform endpoint, then publish straight to one endpoint’s ARN, with no topic. This is how you send “your rider is outside” to one customer’s phone. Mobile endpoints can also be subscribed to a topic for broadcasts (“Eid offer: 20 % off”).

Each published message can carry up to 10 message attributes (name, type String, String.Array, Number or Binary, and value). Attributes are metadata outside the body; filter policies, below, use them.

Pricing, roughly: about $0.50 per million publish requests for standard topics (each 64 KB chunk counts as one request), no per-message charge for delivery to SQS and Lambda, and per-delivery prices for HTTP, email, SMS and mobile push. Attribute-based filtering is free; payload-based filtering is billed per GB scanned.

#SNS security

The slides group SNS security into encryption and access control; it mirrors SQS (lesson 13.1) and S3 (lessons 10.2 and 10.8).

Encryption

  • In flight: the SNS API is HTTPS. You can force it with a topic policy that denies requests where aws:SecureTransport is false. Topics with server-side encryption accept only HTTPS requests anyway.
  • At rest: server-side encryption with KMS keys (the AWS managed key aws/sns, or a customer managed key). It is off by default on standard topics, unlike SQS, which encrypts new queues with SSE-SQS by default. SSE encrypts the message body only: topic metadata and message attributes are not encrypted, so never put secrets in attributes. (That is also why filtering on attributes works on an encrypted topic.)
  • Client-side encryption: if the client wants to encrypt and decrypt the payload itself, SNS just carries ciphertext.

Access control

  • IAM policies on users and roles decide who may call the SNS API (sns:Publish, sns:Subscribe, sns:CreateTopic…), as in chapter 2.
  • SNS access policies are resource-based policies on the topic, similar to S3 bucket policies (lesson 2.2 on resource-based policies). You need them for:
    • cross-account access: another account publishing to, or subscribing to, your topic;
    • AWS services that publish to the topic, such as S3, CloudWatch or Budgets: allow the service principal (for example s3.amazonaws.com) and limit it with aws:SourceArn and aws:SourceAccount.
  • If the topic uses a KMS key, a publishing service also needs kms:GenerateDataKey and kms:Decrypt on that key. You cannot edit the policy of the AWS managed key aws/sns, so a topic that S3 or CloudWatch publishes to needs a customer managed key.

Side note: message data protection (2022) lets a topic policy audit, mask or block sensitive data such as card numbers or national ID numbers in messages as they pass through. It is useful for compliance, and it is not a substitute for encryption.

#SNS + SQS: the fan-out pattern

#Push once, receive in every queue

Fan-out is the most popular SNS architecture and one of the most tested patterns in the exam. A publisher sends a message once to an SNS topic; several SQS queues are subscribed; SNS pushes a copy into every queue at the same moment; each queue’s own workers process their copy asynchronously and in parallel. Like an electric fan, the same air goes in every direction at once.

Fan-out: one topic, three queues

An online shop publishes “order placed” once. Three SQS queues are subscribed: inventory, notifications and fraud. Each queue has its own workers.

Scenario

Push once into SNS, receive in every subscribed queue, process in parallel.

Shoppublisher
SNS topicorders
Inventoryqueue
Workerstock
Notifyqueue
Workeremail + SMS
Fraudqueue
Workerfraud
order 1036
Step 1 of 4
1

The shop publishes one “order placed” message, order 1036. It makes one call, whatever the number of teams that care about orders.

#What the queues add

SNS alone delivers and forgets. Putting an SQS queue behind each subscription adds what SNS does not have (the slides list the first three):

  • Persistence: the message waits in the queue (4 days by default, up to 14) until a worker processes it. A consumer that crashes loses nothing; this is the “no data loss” of the notes.
  • Delayed processing: each consumer works at its own pace, and a delay queue or a nightly batch is fine.
  • Retries of work: a worker that fails simply does not delete the message; it reappears after the visibility timeout, and after maxReceiveCount attempts it goes to the queue’s own DLQ (lesson 13.2).
  • Independent scaling: each queue can drive its own Auto Scaling group or Lambda concurrency (lesson 13.1).
  • New consumers over time: a new team subscribes a new queue; publisher and existing queues stay as they are.

SNS → SQS delivery itself is very reliable: SQS is an AWS-managed endpoint, retried for up to 23 days (see “Delivery, retries and dead-letter queues”).

#The queue must allow the topic to write

An SQS queue only accepts messages from principals its access policy allows. When you subscribe a queue in the console, the console adds the statement; when you use the CLI, CloudFormation or Terraform, you must add it, or every delivery to that queue fails with “access denied”:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "AllowOrdersTopic",
    "Effect": "Allow",
    "Principal": { "Service": "sns.amazonaws.com" },
    "Action": "sqs:SendMessage",
    "Resource": "arn:aws:sqs:ap-southeast-1:111122223333:inventory-example",
    "Condition": { "ArnEquals": { "aws:SourceArn": "arn:aws:sns:ap-southeast-1:111122223333:orders-example" } }
  }]
}

The aws:SourceArn condition matters: without it, any SNS topic in any account could write to your queue.

If the queue is encrypted with SSE-KMS, SNS must also be able to use the key. The AWS managed key aws/sqs cannot be shared, so use a customer managed key whose key policy allows sns.amazonaws.com to call kms:GenerateDataKey and kms:Decrypt. (A queue with the default SSE-SQS encryption needs nothing extra.)

#Across Regions and accounts

  • Cross-Region delivery works for SQS queues and Lambda functions: the topic in ap-southeast-1 can deliver to a queue in eu-west-1. You run the subscribe command in the topic’s Region, and pay normal inter-Region data transfer. (Opt-in Regions such as Bahrain or Hong Kong need a Region-specific service principal in the queue policy.)
  • Cross-account fan-out needs two permissions: the topic policy must allow the other account to sns:Subscribe (or the topic owner subscribes the queue), and the queue policy must allow the topic to sqs:SendMessage. A subscription created by the topic owner for a queue in another account must be confirmed by the queue’s owner; one created by the queue’s owner needs no confirmation.

#Raw message delivery

By default, SNS wraps your message in a JSON envelope (Type, MessageId, TopicArn, Timestamp, Message, MessageAttributes, signature fields), so an SQS consumer finds your order JSON as an escaped string inside the Message field. Turn on raw message delivery on the subscription (for SQS, HTTP/S and Firehose) and the queue receives exactly what was published, with SNS message attributes turned into SQS message attributes. Consumers that were written for messages sent straight to SQS then work unchanged.

#Two classic fan-out applications

#S3 events to many queues

Lesson 10.7 explained S3 event notifications and their overlap rule: two rules for the same event type with overlapping prefix and suffix (for example ObjectCreated on images/) cannot both exist, so native notifications send one event to one destination. If several queues or functions need the same event, point the one rule at a standard SNS topic in the same Region and subscribe them all: that is fan-out. The topic’s access policy must allow s3.amazonaws.com to publish, limited to the bucket with aws:SourceArn and aws:SourceAccount. (A FIFO topic cannot be an S3 destination. The other modern answer is to turn on EventBridge for the bucket, where any number of rules can match the same event; chapter 19.)

The notes’ classic question belongs here too: “send an email immediately when a file is uploaded to S3” → an S3 event notification to an SNS topic with an email subscription.

#SNS to S3 through Firehose

SNS cannot write to S3 itself, and S3 is not a subscriber type. But Amazon Data Firehose (called Kinesis Data Firehose on the slides; renamed in 2024) is. A Firehose subscription lets SNS push every message into a Firehose stream, which buffers them (by size or time) and writes them as objects to S3, or to any Firehose destination: Redshift, OpenSearch, Splunk, HTTP endpoints, Apache Iceberg tables (lesson 13.6). This is the standard way to archive a topic’s messages for audit or analytics.

  • The subscription needs an IAM role that lets SNS write to the stream (firehose:PutRecord and related actions).
  • A standard topic can have up to 5 Firehose subscriptions per subscription owner.
  • Turn on raw message delivery to store only your payload, not the SNS envelope.
  • Firehose delivery is near real time (buffering), not instant.

S3 events to many targets, and SNS into S3

A Dhaka hospital uploads scan images to a bucket. Two teams need every upload event, and compliance wants every message archived in S3.

Scenario

Native S3 notifications: one event type and prefix, one destination.

Scans bucketscans/
SQS queuethumbnails
Lambdavirus scan
object created
Step 1 of 2
1

The thumbnail team adds a notification rule: object-created events on scans/ to their SQS queue. Every upload now lands in the queue.

#FIFO topics

#Order and deduplication, end to end

A standard topic may deliver a message twice and in a different order from publishing. For many notifications that is fine. For a ledger, a stock count or the steps of a payment, it is not. An SNS FIFO topic (the name must end in .fifo) brings the guarantees of SQS FIFO (lesson 13.3) to pub/sub:

  • Ordering by message group ID. Every message carries a MessageGroupId; messages in the same group are delivered in the order they were published. Different groups are independent and are delivered in parallel.
  • Deduplication. A message with the same message deduplication ID as one published in the last 5 minutes is accepted but not delivered again. With content-based deduplication turned on, SNS uses a hash of the message body as the deduplication ID, so you do not have to set one.
  • Subscribers: SQS only. FIFO topics deliver to SQS FIFO queues and, since 2023, to SQS standard queues too. They cannot deliver to Lambda, HTTP/S, email, SMS, mobile push or Firehose. A Lambda consumer reads a FIFO queue instead.
  • A standard queue behind a FIFO topic receives the messages in order, but a standard queue does not keep order or prevent duplicates for its consumer. Use it for subscribers that do not care.

#SNS FIFO + SQS FIFO fan-out

When you need fan-out + ordering + deduplication, the slides’ answer is an SNS FIFO topic with SQS FIFO queues subscribed. Each queue receives every message of every group in order and exactly once (within the deduplication window), and each team’s consumers process their own copy in order.

#Throughput

The slides say FIFO topics have “the same throughput as SQS FIFO”. The current numbers:

  • 300 messages per second per message group, and by default 3,000 messages per second (or 20 MB/s) per topic, with deduplication checked across the whole topic.
  • High-throughput mode (January 2025): set the topic’s FifoThroughputScope to MessageGroup. Ordering stays per group, deduplication becomes per group, and the topic can use the account’s Regional publish quota (for example 30,000 messages/s in us-east-1). Spread messages over many groups to use it.
  • A FIFO topic has at most 100 subscriptions.

So throughput grows with the number of groups: with 5 busy groups, at most 5 × 300 = 1,500 messages/s; with 20 groups, the 3,000 per topic default becomes the limit.

#Archive and replay

Side note (October 2023): a FIFO topic can archive every message it receives for 1 to 365 days (an archive policy on the topic), and a subscriber can replay archived messages from a chosen start time (a replay policy on its subscription). A team that corrupted its data with a bug can rebuild it; a new subscriber can catch up on history. Replay costs extra and works only for FIFO topics (application-to-application). For the exam, “replay a stream of data” still points to Kinesis (lesson 13.5).

FIFO topic: order and no duplicates

A mobile wallet publishes the events of each payment in order: created, paid, settled. The ledger must apply them exactly in that order and exactly once.

Scenario

All events of one payment share a message group ID, so they stay in order end to end.

Wallet APIpublisher
FIFO topicpayments.fifo
LedgerFIFO queue
Ledger worker
Notifystandard queue
Notify worker
3 · 2 · 1
Step 1 of 3
1

The wallet publishes three events for payment P-77 with message group ID P-77: 1 created, 2 paid, 3 settled.

Self-checkQuestion

A payments platform publishes created, paid and settled events for each payment. Three teams must each receive every event, in order per payment, with no duplicates, and each team processes at its own pace. What should the architect use?

#Message filtering

#Why filter

Normally every subscription of a topic receives every message. Often that is not what you want: the refunds team does not care about placed orders, the premium desk only wants premium ones. Without filtering, each consumer must receive everything, check in its own code whether the message is relevant, and delete the rest. That wastes compute, SQS requests and money, and it spreads routing logic over many code bases.

Message filtering lets each subscription say which messages it wants. SNS checks every message against the subscription’s filter policy and delivers only the matching ones. Messages that do not match are simply not delivered to that subscription (they still go to the others).

#Attributes and filter policies

  1. The publisher adds message attributes to each message, metadata outside the body, for example state = placed and order_type = premium.
  2. Each subscription gets a filter policy: a small JSON document with the attribute names it cares about and the values it accepts.
{
  "state": ["placed"],
  "order_type": ["premium", "gold"],
  "amount": [{ "numeric": [">=", 10000] }],
  "city": [{ "anything-but": ["Dhaka"] }]
}

The matching rules:

  • No policy → every message. The slides make this point: a subscription without a filter policy receives everything.
  • AND across keys: every key in the policy must match.
  • OR inside a list: any one of the values listed for a key is enough (premium or gold). An $or operator can also combine whole alternative conditions.
  • A missing attribute never matches a key, except with {"exists": false}.
  • String matching is case-sensitive: Placed does not match placed (unless you use equals-ignore-case).
  • Attributes that the policy does not mention are ignored.
OperatorExampleMatches
Exact string"state": ["placed"]state is exactly placed
anything-but"city": [{"anything-but": ["Dhaka"]}]city exists and is not Dhaka
prefix / suffix"sku": [{"prefix": "MED-"}]values starting with MED-
equals-ignore-case"state": [{"equals-ignore-case": "placed"}]placed, Placed, PLACED
numeric"amount": [{"numeric": [">", 0, "<=", 5000]}]0 < amount ≤ 5,000
exists"coupon": [{"exists": true}]the attribute is present
IP address"source_ip": [{"cidr": "10.0.0.0/24"}]addresses in that range
wildcard"file": [{"wildcard": "*.jpg"}]values matching the pattern

Constraints to remember: at most 5 keys per policy, at most 150 combinations (multiply the number of values of each key: 3 × 5 × 10 = 150 is the limit), 256 KB per policy, 200 policies per topic. A new or changed policy can take up to 15 minutes to take full effect. Filter policies work on standard and FIFO topics.

#Attribute-based and payload-based filtering

  • Attribute-based (the default; the subscription’s FilterPolicyScope is MessageAttributes): the policy is matched against the message attributes only, String, String.Array and Number types. Policies cannot be nested. This is what exam questions usually describe.
  • Payload-based (since November 2022; FilterPolicyScope = MessageBody): the policy is matched against the JSON body itself, including nested keys, for example {"order": {"state": ["placed"]}}. Use it when publishers you do not control (another team, an AWS service) put everything in the body and set no attributes. The body must be valid JSON, and it costs a small fee per GB scanned.

Filter policies: each subscriber picks its messages

Every order event carries attributes. The placed queue has the policy state = placed, the cancelled queue state = cancelled, and the analytics queue has no policy at all.

Scenario

SNS checks the message against each subscription’s policy and delivers only where it matches.

Order service
SNS topicorders
Placedstate = placed
Cancelledstate = cancelled
Analyticsno policy
state=placed

Message attributes

order

1036

state

placed

order_type

premium

Step 1 of 3
1

The order service publishes order 1036 with the attributes state = placed and order_type = premium. The body is the full order; the attributes are a small label on the outside.

Try the rules yourself: build a message and see which of the eight subscriptions receive it.

Filter policy lab

Build one order message for the orders topic and see which of its eight subscriptions receive it. Try the traps: a capital letter, a missing attribute, the fields only in the body.

1. The message

state
order_type
amount
city
Fields sent as

2. Who receives it

Pick values above; nothing is sent until you change one.

#One topic with filters, or many topics?

  • One topic + filter policies when the messages are the same kind of event and receivers want different subsets. Publishers stay simple (one topic), and new subsets are just new policies.
  • Separate topics when the events are really different (orders vs inventory alarms), have different owners or permissions, or need different topic types (standard vs FIFO).
  • If routing rules become complex (many sources, content transformation, schedules, SaaS sources), EventBridge rules (chapter 19) are the bigger tool; SNS filtering is for fast, simple, high-volume fan-out.

#Delivery, retries and dead-letter queues

#How SNS retries

When a delivery fails because the endpoint is unavailable (a server-side error: HTTP 5xx, 429, a throttled Lambda), SNS retries according to a delivery policy that depends on the protocol:

EndpointRetry policyCan you change it?
SQS, Lambda (AWS-managed endpoints)3 immediate, 2 at 1 s, 10 with backoff up to 20 s, then 100,000 at 20 s: 100,015 attempts over 23 daysNo
Email, SMS, mobile push50 attempts over 6 hoursNo
HTTP / HTTPSDefault: 3 retries, 20 s apart. Custom policy on the topic or subscription: up to 100 retries, backoff function (linear, arithmetic, geometric, exponential), total retry time at most 1 hour, plus an optional throttle (maxReceivesPerSecond)Yes, only this one

When the delivery policy is used up, SNS discards the message, unless the subscription has a dead-letter queue.

Client-side errors are different: the endpoint was deleted, the queue or function policy no longer allows SNS, the KMS key is unusable, or an HTTP endpoint answers 4xx (other than 429). SNS does not retry these at all, because a retry would fail the same way.

Retries mean an endpoint can receive the same message more than once (standard topics are at-least-once): make consumers idempotent, for example by remembering the MessageId.

#Subscription dead-letter queues

A dead-letter queue (DLQ) for SNS is an ordinary SQS queue attached to a subscription (not to the topic) with a redrive policy (deadLetterTargetArn). Messages that fail with a client-side error, or that run out of retries, go there instead of being lost. Rules:

  • The DLQ must be in the same account and Region as the subscription.
  • A FIFO topic’s subscription needs a FIFO DLQ; a standard topic’s, a standard queue.
  • The DLQ’s access policy must allow SNS to send, and if it is encrypted, a customer managed KMS key must allow SNS.
  • Set the DLQ’s retention to the maximum, 14 days, and put a CloudWatch alarm on its ApproximateNumberOfMessagesVisible.
  • Failed deliveries do not disable a subscription. Watch the NumberOfNotificationsFailed metric, and turn on delivery status logging (to CloudWatch Logs, for SQS, Lambda, HTTP/S, Firehose, SMS and mobile push).

This is the “SNS also has DLQs” of the notes’ DLQ section: SQS has DLQs for messages consumers keep failing (lesson 13.2), SNS for messages it could not deliver, and Lambda for asynchronous invocations that keep failing (chapter 15).

When delivery fails: retries and the subscription DLQ

A courier partner receives order events on an HTTPS webhook. Watch what SNS does when the webhook is down, when it never comes back, and when the error is on your side.

Scenario

Server-side errors (5xx, 429) are retried according to the delivery policy.

Order service
SNS topic
Courier webhookHTTPS
DLQon the subscription
Publish
Step 1 of 5
1

An order is published. The topic has an HTTPS subscription for the courier partner’s webhook.

#SNS and SQS side by side

The notes end their SQS and SNS part with a recap for the night before the exam. Here it is, with the details from lessons 13.1–13.4:

SQSSNS
ModelQueue: each message to one consumerPub/sub: each message to every subscription
DeliveryPull (consumers poll)Push
Keeps messagesYes, up to 14 days, until deletedNo (standard); FIFO topics can archive for replay
Typical wordsDecouple, buffer, absorb spikes, asynchronous, workerNotify, alerts, email/SMS, push notifications, many subscribers
Failure handlingVisibility timeout, maxReceiveCount, DLQDelivery retries per protocol, subscription DLQ
OrderingStandard: best effort; FIFO: per groupStandard: best effort; FIFO: per group
TogetherFan-out: 1 SNS topic → many SQS queues (parallel processing)Filtering: each subscription receives only matching messages (saves compute)

Kinesis, the third model (a replayable stream), is lesson 13.5, and the full SQS vs SNS vs Kinesis comparison is lesson 13.7.

#What goes wrong

SymptomLikely causeFix
A subscribed SQS queue never receives messagesThe queue’s access policy does not allow sns.amazonaws.com (subscribed with CLI/IaC)Add sqs:SendMessage for the SNS principal with aws:SourceArn = topic
Deliveries to an encrypted queue failQueue uses the AWS managed key aws/sqs, which SNS cannot useCustomer managed key whose policy allows SNS kms:GenerateDataKey and kms:Decrypt
S3 cannot save a notification to the topicTopic policy does not allow s3.amazonaws.com; topic is FIFO; topic in another Region; KMS key policyFix the topic policy; use a standard topic in the bucket’s Region; customer managed key
Email subscribers get nothingSubscription still pending confirmationClick the confirmation link; check spam
The consumer cannot parse the messageSNS envelope: the payload is a string inside MessageTurn on raw message delivery, or unwrap the envelope
A queue with a filter policy receives nothingAttribute missing, wrong type, wrong case, or the fields are only in the bodySet the attributes; match case; use payload-based filtering; wait up to 15 minutes after a change
Messages to an HTTP endpoint were lost during an outageDefault HTTP policy (3 retries, 20 s) ran out; no DLQSubscription DLQ; custom delivery policy; SQS queue in between
A webhook processes the same order twiceAt-least-once delivery and retries after timeoutsIdempotent consumer keyed on MessageId; or FIFO topic + FIFO queue
Publish to a FIFO topic is throttled300 messages/s per group, 3,000 per topicMore message groups; high-throughput mode; batching
Lambda cannot be subscribed to a FIFO topicFIFO topics deliver only to SQSSubscribe an SQS FIFO queue and trigger Lambda from it
Publish fails with InvalidParameter on large messagesPayload over 256 KiB (body + attributes)Extended Client Library with S3; or raise MaximumMessageSize if subscribers allow
SMS not delivered abroadSandbox, spend limit, or no registered sender ID or numberLeave the sandbox, raise the limit, register an origination identity

#SNS in system design

  • Notifications to people. CloudWatch alarms, Budgets and ASG events → a topic → email, SMS, chat tools through Lambda or HTTPS. The most common first use of SNS in every account.
  • Event fan-out between services. One domain event (order-placed) → a standard topic → one SQS queue per consuming service. Producers and consumers deploy and scale independently; the classic choreography style of microservices.
  • Fan-out + filtering. One topic per kind of event, with filter policies so each service gets only its share. Cheaper and simpler than many topics.
  • Ordered fan-out. FIFO topic + FIFO queues for ledgers, inventory and state machines; group ID = entity ID.
  • Multi-Region and multi-account. A topic in one Region delivering to queues in a DR Region or in other accounts (cross-account policies on both sides).
  • Archiving. A Firehose subscription for an audit trail in S3; FIFO archive and replay when consumers must rebuild state.
  • Buffer fragile endpoints. Put SQS between SNS and anything that can be down for long: a partner webhook, an on-premises system.
  • Know when to pick something else. Many sources, rich routing and schemas → EventBridge (chapter 19). Replay and many readers of a high-volume stream → Kinesis (lesson 13.5). Legacy apps speaking AMQP or MQTT → Amazon MQ (lesson 13.7).

#Try it yourself

All commands run in ap-southeast-1; names end in -example. Output is shortened.

# 1. A standard topic and two queues
aws sns create-topic --name orders-example
#   { "TopicArn": "arn:aws:sns:ap-southeast-1:111122223333:orders-example" }
aws sqs create-queue --queue-name inventory-example
aws sqs create-queue --queue-name refunds-example
#   { "QueueUrl": "https://sqs.ap-southeast-1.amazonaws.com/111122223333/inventory-example" }

# 2. Let the topic write to each queue (policy.json is the queue policy shown in the lesson)
aws sqs set-queue-attributes \
  --queue-url https://sqs.ap-southeast-1.amazonaws.com/111122223333/inventory-example \
  --attributes file://inventory-policy.json

# 3. Subscribe the queues: raw delivery, and a filter policy on the refunds queue
aws sns subscribe --topic-arn arn:aws:sns:ap-southeast-1:111122223333:orders-example \
  --protocol sqs --notification-endpoint arn:aws:sqs:ap-southeast-1:111122223333:inventory-example \
  --attributes RawMessageDelivery=true
aws sns subscribe --topic-arn arn:aws:sns:ap-southeast-1:111122223333:orders-example \
  --protocol sqs --notification-endpoint arn:aws:sqs:ap-southeast-1:111122223333:refunds-example \
  --attributes '{"RawMessageDelivery":"true","FilterPolicy":"{\"state\":[\"cancelled\",\"declined\"]}"}'
#   { "SubscriptionArn": "arn:aws:sns:ap-southeast-1:111122223333:orders-example:6b0e71bd-7e97-4d97-80ce-4a0994e55286" }

# 4. An email subscription stays pending until the link is clicked
aws sns subscribe --topic-arn arn:aws:sns:ap-southeast-1:111122223333:orders-example \
  --protocol email --notification-endpoint ops@example.com
#   { "SubscriptionArn": "pending confirmation" }

# 5. Publish a placed order with attributes: inventory gets it, refunds does not
aws sns publish --topic-arn arn:aws:sns:ap-southeast-1:111122223333:orders-example \
  --message '{"order":1036,"item":"pencil","qty":4}' \
  --message-attributes '{"state":{"DataType":"String","StringValue":"placed"}}'
#   { "MessageId": "f1d0a8e2-3c51-5f1a-9b8e-2a7c4d0e9b11" }
aws sqs receive-message --wait-time-seconds 10 \
  --queue-url https://sqs.ap-southeast-1.amazonaws.com/111122223333/inventory-example
#   "Body": "{\"order\":1036,\"item\":\"pencil\",\"qty\":4}"   (raw: no SNS envelope)
aws sqs receive-message --wait-time-seconds 10 \
  --queue-url https://sqs.ap-southeast-1.amazonaws.com/111122223333/refunds-example
#   (no output: filtered out)

# 6. Switch a subscription to payload-based filtering, and give it a DLQ
aws sns set-subscription-attributes --subscription-arn <refunds-subscription-arn> \
  --attribute-name FilterPolicyScope --attribute-value MessageBody
aws sns set-subscription-attributes --subscription-arn <refunds-subscription-arn> \
  --attribute-name RedrivePolicy \
  --attribute-value '{"deadLetterTargetArn":"arn:aws:sqs:ap-southeast-1:111122223333:refunds-dlq-example"}'

# 7. A FIFO topic with content-based deduplication, and an ordered publish
aws sns create-topic --name payments-example.fifo \
  --attributes FifoTopic=true,ContentBasedDeduplication=true
aws sns publish --topic-arn arn:aws:sns:ap-southeast-1:111122223333:payments-example.fifo \
  --message '{"payment":"P-77","event":"paid"}' --message-group-id P-77
#   { "MessageId": "…", "SequenceNumber": "10000000000000003000" }

# 8. See every subscription and its state
aws sns list-subscriptions-by-topic \
  --topic-arn arn:aws:sns:ap-southeast-1:111122223333:orders-example

Things to notice: step 5 shows filtering and raw delivery together (try it without RawMessageDelivery and compare the envelope); step 4 shows why email alerts sometimes “do not work”; and publishing the same body twice within 5 minutes to the FIFO topic in step 7 delivers it only once.

#Summary

Key takeaways

  • Direct calls to many receivers are slow, fragile and coupled. SNS is AWS’s managed, push-based pub/sub service: a publisher sends once to a topic, and every subscription gets a copy. Like a YouTube channel and its subscribers.
  • Subscribers: SQS, Lambda, Data Firehose (A2A); HTTP/S; email, SMS, mobile push (A2P). Not S3, Kinesis Data Streams or EC2 directly. Email and HTTP/S must be confirmed. Many AWS services publish to SNS (CloudWatch alarms, Budgets, ASG, S3 events, RDS, DMS, CloudFormation…).
  • Limits: 12,500,000 subscriptions per standard topic (100 for FIFO), 100,000 topics per account (1,000 FIFO), 256 KB messages (1 MiB opt-in since 2026 for SQS/Lambda/Firehose-only topics; Extended Client Library to 2 GB).
  • Publish: topic publish (SDK/CLI, PublishBatch of 10) or direct publish to a mobile platform endpoint (APNs, FCM, ADM…).
  • Security: HTTPS in flight; SSE with KMS at rest (off by default, body only, attributes not encrypted); client-side encryption; IAM for API calls; topic access policies for cross-account and AWS services such as S3.
  • Fan-out: SNS topic → many SQS queues: fully decoupled, no data loss, persistence, delayed processing, retries, add queues later. The queue access policy must allow the topic; encrypted queues need a customer managed key; works cross-Region and cross-account; raw message delivery removes the envelope.
  • Applications: S3 events to many targets (one rule → topic), and SNS → Firehose → S3 for archiving.
  • FIFO topics: order per message group ID, deduplication (5 minutes, ID or content-based), SQS-only subscribers (FIFO or standard), 300/s per group and 3,000/s per topic (high-throughput mode for more), archive and replay. SNS FIFO + SQS FIFO = fan-out + ordering + deduplication.
  • Filtering: a JSON filter policy per subscription; no policy = everything; AND across keys, OR within a list; case-sensitive; missing attribute = no match; attribute-based (default) or payload-based. Saves compute and moves routing out of consumer code.
  • Retries: SQS/Lambda 100,015 attempts over 23 days; email/SMS/push 50 over 6 hours; HTTP/S default 3 retries, customizable up to an hour. Client-side errors are not retried. A subscription DLQ (SQS, same account and Region) keeps what would be lost.