Frequently Asked Questions
Use the AWS SDK v3 for SNS within a NestJS service. Create a PublishCommand with the recipient's phone number and message content, then use the SNSClient to send the command. Ensure your AWS credentials are configured correctly via environment variables, profiles, or IAM roles.
Real-time callbacks provide immediate feedback on whether an SMS message was successfully delivered, failed, or encountered an issue. This enables reliable workflows, improves user experience, and aids troubleshooting by providing insights into delivery issues.
AWS SNS needs a public HTTPS URL to push delivery status notifications to your application. This is how SNS communicates delivery updates asynchronously. During development, tools like Ngrok can create a tunnel to expose a local endpoint, but a stable public domain is essential for production.
Use 'Transactional' for mission-critical messages requiring high reliability, like one-time passwords or delivery confirmations. 'Promotional' is suitable for marketing or informational messages where slightly lower delivery rates are acceptable, often at a lower cost.
Ngrok's free tier provides temporary URLs and has limitations, making it suitable only for development and testing SMS delivery callbacks. For production, deploy your application with a stable public HTTPS domain for reliable callback handling.
Use the SetSMSAttributesCommand to configure your SNS SMS preferences. Set the `DeliveryStatusSuccessSamplingRate` to 100 and provide the ARN of your dedicated SNS topic for both `SuccessfulFeedbackRoleArn` and `FailureFeedbackRoleArn` parameters. This routes status updates to your topic.
The `sns-validator` library is crucial for verifying the authenticity and integrity of incoming SNS messages. It confirms that the message originated from AWS SNS, preventing security risks from spoofed or manipulated callbacks. Always validate the signature before processing the message content.
Create a secure NestJS controller endpoint publicly accessible via HTTPS. AWS SNS will POST delivery status notifications to this URL. Use `@Req() req: RawBodyRequest` along with the `rawBody: true` option in `main.ts` to get the raw body needed for signature verification with `sns-validator`.
The 'Message' field contains a JSON string with the actual delivery status details. It includes the original message ID, recipient number, status (SUCCESS, FAILURE, or other status strings), timestamp, and provider-specific information.
SNS sends various message types: 'SubscriptionConfirmation', 'Notification', and 'UnsubscribeConfirmation'. Use a switch statement to differentiate them. Confirm subscriptions via the SubscribeURL, process delivery updates from 'Notification' messages, and manage unsubscriptions as needed.
A 'SubscriptionConfirmation' signifies that AWS SNS is attempting to verify your callback endpoint. You *must* visit the provided SubscribeURL to activate the subscription. This confirms that you control the endpoint and authorizes SNS to send notifications there.
Validating the Topic ARN adds an extra layer of security. It ensures that the received notification originates from the expected SNS topic, reducing the risk of processing messages from unauthorized sources.
Do *not* process the message if validation fails. Return a 200 OK response to prevent SNS from retrying the invalid message repeatedly. Log the validation error internally for investigation.
Install necessary packages like `@aws-sdk/client-sns`, `@nestjs/config`, `class-validator`, `class-transformer`, and `sns-validator`. Set up environment variables for AWS credentials, region, and the callback topic ARN. Create a NestJS module and controller to handle sending messages and the callback logic.
Tracking the delivery status of SMS messages is crucial for applications relying on timely communication. Simply sending a message isn't enough; knowing whether it reached the recipient's handset successfully, failed, or encountered an issue is vital for reliable workflows, user experience, and troubleshooting.
This guide provides a complete walkthrough for building a production-ready system within a Node.js NestJS application to send SMS messages via AWS Simple Notification Service (SNS) and receive real-time delivery status callbacks directly from SNS. We will configure AWS SNS to push status updates to a dedicated SNS topic, which will then notify a secure HTTPS endpoint in our NestJS application.
Project Goals:
Technologies Used:
System Architecture:
Note: Ensure the Mermaid diagram renders correctly on your publishing platform. Verification may be required.
Prerequisites:
npm install -g @nestjs/cli
).By the end of this guide, you'll have a robust NestJS application capable of sending SMS messages and reliably tracking their delivery status through direct callbacks from AWS SNS.
1. Setting up the NestJS Project
Let's initialize a new NestJS project and install the necessary dependencies.
1. Create NestJS Project:
Open your terminal and run:
Choose your preferred package manager (npm or yarn) when prompted.
2. Install Dependencies:
We need the AWS SDK v3 for SNS, configuration management, validation, and the SNS message validator.
@aws-sdk/client-sns
: AWS SDK v3 client for SNS.@nestjs/config
: For managing environment variables.class-validator
,class-transformer
: For request payload validation (DTOs).sns-validator
: To verify the authenticity of incoming SNS messages (crucial for security).3. Configure Environment Variables:
Create a
.env
file in the project root:Security Best Practice - AWS Credentials: While listing
AWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
directly in.env
works for local development, it's strongly discouraged for security reasons, especially if the file could be accidentally committed. Never commit files containing credentials to version control. Add.env
to your.gitignore
immediately. Preferred Alternatives:~/.aws/credentials
and~/.aws/config
. The SDK can use these automatically (setAWS_PROFILE
environment variable).4. Setup Configuration Module:
Modify
src/app.module.ts
to load the environment variables using@nestjs/config
.5. Project Structure:
We'll organize our SMS-related logic into a dedicated
sms
module.Create the
sms
directory and its subdirectories. We will populate the files in the following steps.2. Implementing Core Functionality: Sending SMS
Let's create the service responsible for interacting with AWS SNS to send messages.
1. Create AWS SNS Client Provider (Optional but Recommended):
For better organization and testability, we can create a provider for the SNS client.
2. Create
SmsService
:This service will encapsulate the logic for sending SMS messages and processing status updates.
Explanation:
SNSClient
andConfigService
.sendSms
Method:phoneNumber
andmessage
.BadRequestException
if invalid.PublishCommandInput
.this.snsClient.send()
.MessageId
. Includes placeholder for DB persistence.processDeliveryStatus
Method: A preliminary placeholder. It currently just logs the raw payload received. This method will be significantly updated in Section 6 (Database Integration) to parse the specific fields (messageId
,status
, etc.) and interact with the database repository.configureSmsDeliveryStatusAttributes
Method: Utility to set SNS attributes for delivery status. RequiresDELIVERY_STATUS_TOPIC_ARN
from.env
. Sets sampling rate and specifies the target Topic ARN for success/failure notifications using theSuccessfulFeedbackRoleArn
andFailureFeedbackRoleArn
parameters (despite their confusing names). Requiressns:SetSMSAttributes
permission.3. Building the API Layer (Sending SMS & Receiving Callbacks)
Now, let's create the controller to expose an endpoint for sending SMS and another for receiving the status callbacks from SNS.
1. Create
SendSmsDto
:Define a Data Transfer Object (DTO) for validating the incoming request payload when sending an SMS.
2. Define SNS Notification Interface:
Create an interface for better type safety when handling incoming SNS notifications. The structure can be complex; this covers the key parts. Refer to AWS SNS documentation for the definitive structure. Note the ambiguity in
messageId
location within theMessage
field, which the code needs to handle.3. Create
SmsController
:This controller will handle both sending SMS messages and receiving status callbacks.
4. Enable Raw Body Parsing:
The
sns-validator
requires the raw, unparsed request body to verify the signature. Modifysrc/main.ts
to enable this globally.