RepletoryLib.Communication.Sms 1.0.0

dotnet add package RepletoryLib.Communication.Sms --version 1.0.0
                    
NuGet\Install-Package RepletoryLib.Communication.Sms -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RepletoryLib.Communication.Sms" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RepletoryLib.Communication.Sms" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="RepletoryLib.Communication.Sms" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RepletoryLib.Communication.Sms --version 1.0.0
                    
#r "nuget: RepletoryLib.Communication.Sms, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RepletoryLib.Communication.Sms@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RepletoryLib.Communication.Sms&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=RepletoryLib.Communication.Sms&version=1.0.0
                    
Install as a Cake Tool

RepletoryLib.Communication.Sms

AWS SNS SMS service implementation with sender ID support and transactional/promotional message routing.

Part of the RepletoryLib ecosystem -- standalone, reusable .NET 10 libraries with zero business logic.

NuGet .NET 10 License: MIT


Overview

RepletoryLib.Communication.Sms provides an AWS Simple Notification Service (SNS) implementation of the ISmsService interface from RepletoryLib.Communication.Abstractions. It sends SMS messages via the SNS Publish API to E.164-formatted phone numbers, with configurable sender IDs and transactional/promotional message type routing.

The service sets SNS message attributes for AWS.SNS.SMS.SMSType and AWS.SNS.SMS.SenderID, allowing carrier-level routing differentiation. It also automatically registers the unified ICommunicationService facade so messages can be routed across channels.

Key Features

  • Single SMS -- Send individual SMS messages to E.164 phone numbers
  • Bulk SMS -- Send multiple messages with per-message success/failure tracking
  • Sender ID -- Configurable default sender ID with per-message override
  • SMS type routing -- Transactional (OTP, alerts) or Promotional (marketing) via SNS message attributes
  • Flexible authentication -- Explicit access/secret keys or default AWS credential chain
  • Unified routing -- Automatically registers ICommunicationService for cross-channel messaging

Installation

dotnet add package RepletoryLib.Communication.Sms

Or add to your .csproj:

<PackageReference Include="RepletoryLib.Communication.Sms" Version="1.0.0" />

Note: RepletoryLib packages are published to a local BaGet feed. See the main repository README for feed configuration.

Dependencies

Package Type
RepletoryLib.Communication.Abstractions RepletoryLib
AWSSDK.SimpleNotificationService NuGet (3.7.400.98)
Microsoft.Extensions.Configuration.Binder NuGet (10.0.0)
Microsoft.Extensions.DependencyInjection.Abstractions NuGet (10.0.0)
Microsoft.Extensions.Logging.Abstractions NuGet (10.0.0)
Microsoft.Extensions.Options.ConfigurationExtensions NuGet (10.0.0)

Prerequisites

  • AWS account with SNS SMS sending enabled
  • SMS sending quota approved in the target AWS region
  • AWS credentials (access key/secret key or IAM role)
  • Phone numbers must be in E.164 format (e.g., +27821234567)

Quick Start

using RepletoryLib.Communication.Sms;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRepletrySms(builder.Configuration);
{
  "Communication": {
    "Sms": {
      "Region": "af-south-1",
      "AccessKey": "AKIAIOSFODNN7EXAMPLE",
      "SecretKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
      "SenderId": "MyApp",
      "DefaultSmsType": "Transactional"
    }
  }
}

Configuration

SnsOptions

Property Type Default Description
Region string "af-south-1" AWS region endpoint for SNS
AccessKey string? null AWS access key. When null, the default AWS credential chain is used
SecretKey string? null AWS secret key. When null, the default AWS credential chain is used
SenderId string? null Default sender ID displayed on the recipient's device. Can be overridden per message
DefaultSmsType SmsType Transactional Default SMS type for carrier routing (Transactional or Promotional)

Section name: "Communication:Sms"


Usage Examples

Register Services

using RepletoryLib.Communication.Sms;

var builder = WebApplication.CreateBuilder(args);

// Register the SNS SMS service
builder.Services.AddRepletrySms(builder.Configuration);

var app = builder.Build();

Send a Single SMS

using RepletoryLib.Communication.Abstractions.Interfaces;
using RepletoryLib.Communication.Abstractions.Models.Sms;

public class OtpService
{
    private readonly ISmsService _smsService;

    public OtpService(ISmsService smsService) => _smsService = smsService;

    public async Task SendOtpAsync(string phoneNumber, string otpCode)
    {
        var result = await _smsService.SendAsync(new SmsMessage
        {
            To = phoneNumber,         // E.164 format: "+27821234567"
            Body = $"Your verification code is: {otpCode}. Valid for 5 minutes."
        });

        if (!result.Success)
            throw new InvalidOperationException($"Failed to send OTP: {result.Error}");

        Console.WriteLine($"OTP sent. MessageId: {result.MessageId}");
    }
}

Send SMS with Custom Sender ID

var result = await _smsService.SendAsync(new SmsMessage
{
    To = "+27821234567",
    Body = "Your order #12345 has been shipped!",
    SenderId = "ShopName"   // Overrides the default SenderId from SnsOptions
});

Bulk Send

var messages = phoneNumbers.Select(phone => new SmsMessage
{
    To = phone,
    Body = "Reminder: Your appointment is tomorrow at 10:00 AM."
});

var bulkResult = await _smsService.SendBulkAsync(messages);

Console.WriteLine($"Sent: {bulkResult.SuccessCount}, Failed: {bulkResult.FailureCount}");

foreach (var failure in bulkResult.Results.Where(r => !r.Success))
{
    Console.WriteLine($"Failed: {failure.Error}");
}

Using the Unified Communication Facade

using RepletoryLib.Communication.Abstractions.Enums;
using RepletoryLib.Communication.Abstractions.Interfaces;
using RepletoryLib.Communication.Abstractions.Models.Common;

public class AlertService
{
    private readonly ICommunicationService _communication;

    public AlertService(ICommunicationService communication) => _communication = communication;

    public async Task SendSmsAlertAsync(string phoneNumber, string message)
    {
        var result = await _communication.SendAsync(new CommunicationMessage
        {
            Channel = CommunicationChannel.Sms,
            Recipient = phoneNumber,
            Body = message
        });
    }
}

Multi-Channel Registration

using RepletoryLib.Communication.Email;
using RepletoryLib.Communication.Sms;

var builder = WebApplication.CreateBuilder(args);

// Register both email and SMS -- ICommunicationService routes to both
builder.Services.AddRepletoryEmail(builder.Configuration);
builder.Services.AddRepletrySms(builder.Configuration);

API Reference

ServiceCollectionExtensions

Method Returns Description
AddRepletrySms(configuration) IServiceCollection Registers IAmazonSimpleNotificationService (singleton), ISmsService (scoped), and ICommunicationService (scoped)

SnsSmsService (implements ISmsService)

Method Returns Description
SendAsync(SmsMessage, ct) Task<SendResult> Sends a single SMS via SNS Publish API
SendBulkAsync(IEnumerable<SmsMessage>, ct) Task<BulkSendResult> Sends multiple SMS messages with per-message results

SnsOptions

Property Type Default Description
Region string "af-south-1" AWS region endpoint
AccessKey string? null AWS access key (optional)
SecretKey string? null AWS secret key (optional)
SenderId string? null Default sender ID
DefaultSmsType SmsType Transactional SMS type for carrier routing

SNS Message Attributes

The service automatically sets the following SNS message attributes on each publish request:

Attribute Value Description
AWS.SNS.SMS.SMSType "Transactional" or "Promotional" Controls carrier routing priority
AWS.SNS.SMS.SenderID Sender ID string Displayed on recipient's device (when set)

Integration with Other RepletoryLib Packages

Package Relationship
RepletoryLib.Communication.Abstractions Direct dependency -- provides ISmsService, SmsMessage, SendResult
RepletoryLib.Communication.Email Combine with email for multi-channel notifications
RepletoryLib.Communication.WhatsApp Combine with WhatsApp for multi-channel notifications
RepletoryLib.Communication.Push Combine with push for multi-channel notifications
RepletoryLib.Common Transitive dependency via Abstractions

Testing

using Moq;
using Amazon.SimpleNotificationService;
using Amazon.SimpleNotificationService.Model;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using RepletoryLib.Communication.Abstractions.Enums;
using RepletoryLib.Communication.Abstractions.Models.Sms;
using RepletoryLib.Communication.Sms.Options;
using RepletoryLib.Communication.Sms.Services;

[Fact]
public async Task SendAsync_returns_success_with_message_id()
{
    var mockSns = new Mock<IAmazonSimpleNotificationService>();
    mockSns
        .Setup(s => s.PublishAsync(It.IsAny<PublishRequest>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync(new PublishResponse { MessageId = "sns-msg-001" });

    var options = Options.Create(new SnsOptions
    {
        Region = "af-south-1",
        SenderId = "TestApp",
        DefaultSmsType = SmsType.Transactional
    });

    var service = new SnsSmsService(mockSns.Object, options, NullLogger<SnsSmsService>.Instance);

    var result = await service.SendAsync(new SmsMessage
    {
        To = "+27821234567",
        Body = "Your OTP is 123456"
    });

    result.Success.Should().BeTrue();
    result.MessageId.Should().Be("sns-msg-001");
    result.Channel.Should().Be(CommunicationChannel.Sms);

    mockSns.Verify(s => s.PublishAsync(
        It.Is<PublishRequest>(r =>
            r.PhoneNumber == "+27821234567" &&
            r.Message == "Your OTP is 123456" &&
            r.MessageAttributes["AWS.SNS.SMS.SMSType"].StringValue == "Transactional" &&
            r.MessageAttributes["AWS.SNS.SMS.SenderID"].StringValue == "TestApp"),
        It.IsAny<CancellationToken>()), Times.Once);
}

Troubleshooting

Issue Solution
AmazonSimpleNotificationServiceException: Access Denied Verify your AWS credentials and ensure the IAM role/user has sns:Publish permissions
SMS not delivered Check the AWS SNS delivery status logs. Ensure the phone number is in E.164 format (e.g., +27821234567)
Sender ID not appearing Sender IDs are not supported in all countries (e.g., the US). Check AWS SNS regional support
DefaultSmsType not working Ensure the value is either Transactional or Promotional (case-sensitive in config)
Rate limiting errors AWS SNS has regional SMS sending quotas. Request a quota increase via the AWS console
SendResult.Error says "SMS service is not registered" Ensure AddRepletrySms(configuration) is called in Program.cs

License

This project is licensed under the MIT License.

Copyright (c) 2024-2026 Repletory.


For complete documentation, infrastructure setup, and configuration reference, see the RepletoryLib main repository.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 71 3/2/2026