CODE WITH SIBIN

Solving Real Problems with Real Code


Sending SMS with AWS SNS in Django

This guide covers:

  • ๐ŸŸฃ Setting up necessary AWS resources (IAM User)
  • ๐ŸŸฃ Finding your AWS Credentials
  • ๐ŸŸฃ Configuring your Django project
  • ๐ŸŸฃ Writing the code to send SMS
  • ๐ŸŸฃ Creating a simple Django API endpoint for testing with Postman

๐ŸŸฃ Prerequisites:

  • An AWS Account
  • A Django project already set up
  • Python and pip installed
  • Postman (or similar API client) for testing

๐ŸŸฃ Step 1: Create an IAM User in AWS for SNS Access

  1. Log in to your AWS Management Console.
  2. Go to IAM (search for it).
  3. Click Users โ†’ Add users.
  4. User Details:
    • Username: django-sns-sms-user
    • Access type: ๐ŸŸฃ Check Programmatic access
  5. Permissions:
    • Choose Attach policies directly
    • Search for and select ๐ŸŸฃ AmazonSNSFullAccess
  6. Click Next, review, and click Create user

๐ŸŸฃ IMPORTANT: For production, consider creating a custom policy allowing only sns:Publish.

๐ŸŸฃ Step 2: Find and Secure Your AWS Credentials

After creating the IAM user:

  • ๐ŸŸฃ Copy the Access key ID and Secret access key
  • ๐ŸŸฃ Click Download .csv
  • ๐Ÿšซ Do NOT expose these in your code

Instead, use environment variables or .env files (more below).

๐ŸŸฃ Step 3: Configure Your Django Project

๐Ÿ”ง Install boto3 and Django REST Framework:

pip install boto3 djangorestframework

๐Ÿ”ง Add to INSTALLED_APPS in settings.py:

INSTALLED_APPS = [
    ...
    'rest_framework',
]

๐Ÿ” Set Environment Variables (locally or via .env)

export AWS_ACCESS_KEY_ID='YOUR_ACCESS_KEY'
export AWS_SECRET_ACCESS_KEY='YOUR_SECRET_KEY'
export AWS_REGION_NAME='us-east-1'

๐ŸŸฃ Use a region that supports SNS SMS (e.g., us-east-1)

๐Ÿ›  Update settings.py:

import os

AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_REGION_NAME = os.environ.get('AWS_REGION_NAME')

if not all([AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION_NAME]):
    print("WARNING: AWS credentials or region not fully configured via environment variables.")

๐ŸŸฃ Step 4: Implement the SMS Sending Function

๐Ÿ“ yourapp/utils.py:

import boto3
from django.conf import settings
import logging
from botocore.exceptions import ClientError

logger = logging.getLogger(__name__)

def send_sms(phone_number: str, message: str) -> bool:
    if not all([settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY, settings.AWS_REGION_NAME]):
        logger.error("AWS SNS credentials or region not configured in settings.")
        return False

    if not phone_number.startswith('+'):
        logger.error(f"Invalid phone number format: {phone_number}. Must be E.164 (e.g., +1XXXXXXXXXX)")
        return False

    try:
        client = boto3.client(
            "sns",
            aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
            aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
            region_name=settings.AWS_REGION_NAME
        )

        response = client.publish(
            PhoneNumber=phone_number,
            Message=message,
            MessageAttributes={
                'AWS.SNS.SMS.SMSType': {
                    'DataType': 'String',
                    'StringValue': 'Transactional'
                }
            }
        )

        logger.info(f"SMS sent successfully to {phone_number}. Message ID: {response.get('MessageId')}")
        return True

    except ClientError as e:
        logger.error(f"AWS ClientError sending SMS: {e.response.get('Error', {}).get('Message')}")
        return False
    except Exception as e:
        logger.error(f"Unexpected error sending SMS: {e}", exc_info=True)
        return False

๐ŸŸฃ Step 5: Create a Django API View and URL for Testing

๐Ÿ“ yourapp/views.py:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .utils import send_sms

class SendSMSAPIView(APIView):
    def post(self, request, *args, **kwargs):
        phone_number = request.data.get('phone_number')
        message = request.data.get('message')

        if not phone_number or not message:
            return Response({"error": "Both 'phone_number' and 'message' are required."},
                            status=status.HTTP_400_BAD_REQUEST)

        if not phone_number.startswith('+') or not phone_number[1:].isdigit():
            return Response({"error": "Invalid phone number format (E.164 required)."},
                            status=status.HTTP_400_BAD_REQUEST)

        if len(message) > 1600:
            return Response({"error": "Message exceeds maximum length."},
                            status=status.HTTP_400_BAD_REQUEST)

        success = send_sms(phone_number, message)

        if success:
            return Response({"message": f"SMS sent to {phone_number}."})
        return Response({"error": "Failed to send SMS."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

๐Ÿ“ yourapp/urls.py:

from django.urls import path
from .views import SendSMSAPIView

urlpatterns = [
    path('send-sms/', SendSMSAPIView.as_view(), name='send_sms_api'),
]

๐Ÿ“ project/urls.py:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('yourapp.urls')),
]

๐ŸŸฃ Step 6: Postman Testing

โ–ถ Run Django

python manage.py runserver

๐Ÿ”ฌ Postman Setup

  • Method: POST
  • URL: http://127.0.0.1:8000/api/send-sms/
  • Headers: Content-Type: application/json
  • Body (raw โ†’ JSON):
{
  "phone_number": "+1XXXXXXXXXX",
  "message": "Hello from Django and AWS SNS!"
}

๐ŸŸฃ If you're in SNS Sandbox, only verified phone numbers will receive the SMS
๐ŸŸฃ To send to any number, request production access via AWS Support

๐ŸŸฃ Youโ€™ve successfully:

  • Created AWS IAM access
  • Secured your credentials
  • Set up SNS SMS in Django
  • Built an API endpoint
  • Tested it via Postman

Leave a Reply

Your email address will not be published. Required fields are marked *