RepletoryLib.Communication.Abstractions 1.0.0

dotnet add package RepletoryLib.Communication.Abstractions --version 1.0.0
                    
NuGet\Install-Package RepletoryLib.Communication.Abstractions -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.Abstractions" 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.Abstractions" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="RepletoryLib.Communication.Abstractions" />
                    
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.Abstractions --version 1.0.0
                    
#r "nuget: RepletoryLib.Communication.Abstractions, 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.Abstractions@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.Abstractions&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=RepletoryLib.Communication.Abstractions&version=1.0.0
                    
Install as a Cake Tool

RepletoryLib.Communication.Abstractions

Communication abstractions and interfaces for email, SMS, WhatsApp, and push notifications with a unified routing facade.

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

NuGet .NET 10 License: MIT


Overview

RepletoryLib.Communication.Abstractions defines the contracts, models, enums, and options shared across all RepletoryLib communication channels. It includes interfaces for email (IEmailService), SMS (ISmsService), WhatsApp (IWhatsAppService), and push notifications (IPushNotificationService), along with a unified ICommunicationService facade that routes messages to the appropriate channel-specific service at runtime.

This package is the foundation of the communication stack. Reference it when you need the interfaces or models without taking a dependency on a specific provider (e.g., AWS SES, AWS SNS, 360Dialog).

Key Features

  • IEmailService -- Send single emails, bulk emails, and templated emails
  • ISmsService -- Send single and bulk SMS messages
  • IWhatsAppService -- Send text, template, and media messages via WhatsApp
  • IPushNotificationService -- Send device-targeted and topic-based push notifications
  • ICommunicationService -- Unified facade that routes CommunicationMessage to the correct channel
  • CommunicationService -- Default routing implementation with optional channel services resolved from DI
  • Rich models -- EmailMessage, SmsMessage, WhatsAppTextMessage, PushNotification, and more
  • Result types -- SendResult and BulkSendResult with per-message success/failure tracking
  • Enums -- CommunicationChannel, PushProvider, WhatsAppMediaType, SmsType

Installation

dotnet add package RepletoryLib.Communication.Abstractions

Or add to your .csproj:

<PackageReference Include="RepletoryLib.Communication.Abstractions" 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.Common RepletoryLib

Quick Start

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

public class NotificationService
{
    private readonly ICommunicationService _communication;

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

    public async Task<SendResult> NotifyUserAsync(string email, string message)
    {
        return await _communication.SendAsync(new CommunicationMessage
        {
            Channel = CommunicationChannel.Email,
            Recipient = email,
            Subject = "Notification",
            Body = message
        });
    }
}

Configuration

CommunicationOptions

Property Type Default Description
DefaultFromEmail string "" Default sender email address
DefaultFromName string "" Default sender display name
DefaultSmsSenderId string "" Default SMS sender ID
BulkBatchSize int 50 Batch size for bulk send operations
RetryCount int 3 Number of retry attempts for failed sends

Section name: "Communication"

{
  "Communication": {
    "DefaultFromEmail": "noreply@example.com",
    "DefaultFromName": "My Application",
    "DefaultSmsSenderId": "MyApp",
    "BulkBatchSize": 50,
    "RetryCount": 3
  }
}

Usage Examples

Sending via the Unified 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;

    // Send an email
    public async Task SendEmailAlertAsync(string email, string subject, string htmlBody)
    {
        var result = await _communication.SendAsync(new CommunicationMessage
        {
            Channel = CommunicationChannel.Email,
            Recipient = email,
            Subject = subject,
            Body = htmlBody
        });

        if (!result.Success)
            throw new InvalidOperationException($"Email failed: {result.Error}");
    }

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

    // Send a WhatsApp message
    public async Task SendWhatsAppAlertAsync(string phoneNumber, string message)
    {
        var result = await _communication.SendAsync(new CommunicationMessage
        {
            Channel = CommunicationChannel.WhatsApp,
            Recipient = phoneNumber,
            Body = message
        });
    }

    // Send a push notification
    public async Task SendPushAlertAsync(string deviceToken, string title, string body)
    {
        var result = await _communication.SendAsync(new CommunicationMessage
        {
            Channel = CommunicationChannel.Push,
            Recipient = deviceToken,
            Subject = title,
            Body = body,
            Metadata = new Dictionary<string, string> { ["action"] = "open_alerts" }
        });
    }
}

Bulk Send Across Multiple Channels

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

public class BroadcastService
{
    private readonly ICommunicationService _communication;

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

    public async Task BroadcastAsync(
        string subject,
        string body,
        IEnumerable<(CommunicationChannel Channel, string Recipient)> targets)
    {
        var messages = targets.Select(t => new CommunicationMessage
        {
            Channel = t.Channel,
            Recipient = t.Recipient,
            Subject = subject,
            Body = body
        });

        var result = await _communication.SendBulkAsync(messages);

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

Using Channel-Specific Services Directly

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

public class WelcomeEmailService
{
    private readonly IEmailService _emailService;

    public WelcomeEmailService(IEmailService emailService) => _emailService = emailService;

    public async Task SendWelcomeAsync(string email, string name)
    {
        var result = await _emailService.SendAsync(new EmailMessage
        {
            To = [email],
            Subject = $"Welcome, {name}!",
            HtmlBody = $"<h1>Hello {name}</h1><p>Thanks for joining us.</p>",
            TextBody = $"Hello {name}\n\nThanks for joining us."
        });

        if (!result.Success)
            throw new InvalidOperationException($"Welcome email failed: {result.Error}");
    }

    public async Task SendTemplatedWelcomeAsync(string email, string name)
    {
        var result = await _emailService.SendTemplateAsync(new TemplatedEmailMessage
        {
            To = [email],
            TemplateName = "WelcomeTemplate",
            TemplateData = new Dictionary<string, string>
            {
                ["name"] = name,
                ["year"] = DateTime.UtcNow.Year.ToString()
            }
        });
    }
}

Working with SendResult and BulkSendResult

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

// SendResult factory methods
var success = SendResult.Succeeded(CommunicationChannel.Email, "msg-12345");
var failure = SendResult.Failed(CommunicationChannel.Sms, "Rate limit exceeded");

// Inspect the result
if (success.Success)
    Console.WriteLine($"Message sent: {success.MessageId}");

if (!failure.Success)
    Console.WriteLine($"Send failed on {failure.Channel}: {failure.Error}");

// BulkSendResult aggregation
var bulk = new BulkSendResult
{
    Results = [success, failure]
};

Console.WriteLine($"Total: {bulk.Results.Count}, OK: {bulk.SuccessCount}, Failed: {bulk.FailureCount}");

API Reference

Interfaces

IEmailService
Method Returns Description
SendAsync(EmailMessage, ct) Task<SendResult> Sends a single email message
SendBulkAsync(IEnumerable<EmailMessage>, ct) Task<BulkSendResult> Sends multiple emails with per-message results
SendTemplateAsync(TemplatedEmailMessage, ct) Task<SendResult> Sends an email using a provider-hosted template
ISmsService
Method Returns Description
SendAsync(SmsMessage, ct) Task<SendResult> Sends a single SMS message
SendBulkAsync(IEnumerable<SmsMessage>, ct) Task<BulkSendResult> Sends multiple SMS messages with per-message results
IWhatsAppService
Method Returns Description
SendTextAsync(WhatsAppTextMessage, ct) Task<SendResult> Sends a text message via WhatsApp
SendTemplateAsync(WhatsAppTemplateMessage, ct) Task<SendResult> Sends a pre-approved template message via WhatsApp
SendMediaAsync(WhatsAppMediaMessage, ct) Task<SendResult> Sends a media message (image, video, audio, document) via WhatsApp
SendBulkAsync(IEnumerable<WhatsAppTextMessage>, ct) Task<BulkSendResult> Sends multiple text messages with per-message results
IPushNotificationService
Method Returns Description
SendToDeviceAsync(PushNotification, ct) Task<SendResult> Sends a push notification to a specific device
SendToTopicAsync(TopicPushNotification, ct) Task<SendResult> Sends a push notification to all subscribers of a topic
SendBulkAsync(IEnumerable<PushNotification>, ct) Task<BulkSendResult> Sends multiple push notifications with per-message results
ICommunicationService
Method Returns Description
SendAsync(CommunicationMessage, ct) Task<SendResult> Routes and sends a message via the specified channel
SendBulkAsync(IEnumerable<CommunicationMessage>, ct) Task<BulkSendResult> Routes and sends multiple messages across potentially different channels

Models

EmailMessage
Property Type Required Description
To List<string> Yes Primary recipient email addresses
Cc List<string>? No CC recipient email addresses
Bcc List<string>? No BCC recipient email addresses
Subject string Yes Email subject line
HtmlBody string? No HTML body content
TextBody string? No Plain text body content
ReplyTo string? No Reply-to email address
Attachments List<EmailAttachment>? No File attachments
Headers Dictionary<string, string>? No Custom email headers
TemplatedEmailMessage
Property Type Required Description
To List<string> Yes Primary recipient email addresses
TemplateName string Yes Template name or identifier
TemplateData Dictionary<string, string> No Template data for placeholder substitution
Cc List<string>? No CC recipient email addresses
Bcc List<string>? No BCC recipient email addresses
EmailAttachment
Property Type Required Description
FileName string Yes Attachment file name
ContentType string Yes MIME content type
Content byte[] Yes Attachment content as byte array
SmsMessage
Property Type Required Description
To string Yes Recipient phone number in E.164 format
Body string Yes Message body text
SenderId string? No Sender ID displayed on recipient's device
WhatsAppTextMessage
Property Type Required Description
To string Yes Recipient phone number in E.164 format
Body string Yes Message body text
WhatsAppTemplateMessage
Property Type Required Description
To string Yes Recipient phone number in E.164 format
TemplateName string Yes Template name as registered with WhatsApp Business
LanguageCode string Yes Language code (e.g., "en", "en_US")
Parameters List<string>? No Template parameter values for placeholder substitution
WhatsAppMediaMessage
Property Type Required Description
To string Yes Recipient phone number in E.164 format
MediaType WhatsAppMediaType Yes Type of media (Image, Video, Audio, Document)
MediaUrl string Yes URL of the media to send
Caption string? No Optional caption for the media
PushNotification
Property Type Required Description
DeviceToken string Yes Device token or registration ID
Title string Yes Notification title
Body string Yes Notification body text
Data Dictionary<string, string>? No Custom data payload
ImageUrl string? No Image URL for rich notifications
Badge int? No Badge count on app icon
Sound string? No Notification sound name
ChannelId string? No Android notification channel ID
Provider PushProvider No Push provider to use (Firebase, Expo, WebPush)
TopicPushNotification
Property Type Required Description
Topic string Yes Topic name to send the notification to
Title string Yes Notification title
Body string Yes Notification body text
Data Dictionary<string, string>? No Custom data payload
Provider PushProvider No Push provider to use
CommunicationMessage
Property Type Required Description
Channel CommunicationChannel Yes Communication channel to use
Recipient string Yes Recipient address (email, phone, device token)
Subject string No Message subject (email subject / push title)
Body string Yes Message body
Metadata Dictionary<string, string>? No Optional metadata for channel-specific features
SendResult
Property Type Description
Success bool Whether the send operation succeeded
MessageId string? Provider-assigned message identifier
Error string? Error message if the send failed
Channel CommunicationChannel Communication channel used
Static Method Returns Description
Succeeded(channel, messageId?) SendResult Creates a successful result
Failed(channel, error) SendResult Creates a failed result
BulkSendResult
Property Type Description
Results List<SendResult> Individual results for each message
SuccessCount int Number of successfully sent messages
FailureCount int Number of failed messages

Enums

CommunicationChannel
Value Description
Email Email via SMTP or cloud email service
Sms SMS text message
WhatsApp WhatsApp messaging
Push Push notification to mobile or web devices
PushProvider
Value Description
Firebase Firebase Cloud Messaging (FCM)
Expo Expo Push Notification service
WebPush Web Push using VAPID protocol
WhatsAppMediaType
Value Description
Image Image file (JPEG, PNG)
Video Video file (MP4)
Audio Audio file (MP3, OGG)
Document Document file (PDF, DOCX)
SmsType
Value Description
Transactional Transactional SMS (OTP, alerts, confirmations). Higher delivery priority
Promotional Promotional SMS (marketing, offers). Subject to opt-in regulations

Integration with Other RepletoryLib Packages

Package Relationship
RepletoryLib.Common Direct dependency -- base models and utilities
RepletoryLib.Communication.Email AWS SES implementation of IEmailService
RepletoryLib.Communication.Sms AWS SNS implementation of ISmsService
RepletoryLib.Communication.WhatsApp 360Dialog implementation of IWhatsAppService
RepletoryLib.Communication.Push Firebase/Expo/WebPush implementation of IPushNotificationService

Testing

using Moq;
using RepletoryLib.Communication.Abstractions.Enums;
using RepletoryLib.Communication.Abstractions.Interfaces;
using RepletoryLib.Communication.Abstractions.Models.Common;
using RepletoryLib.Communication.Abstractions.Models.Email;
using RepletoryLib.Communication.Abstractions.Services;

[Fact]
public async Task CommunicationService_routes_email_to_email_service()
{
    var mockEmail = new Mock<IEmailService>();
    mockEmail
        .Setup(e => e.SendAsync(It.IsAny<EmailMessage>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync(SendResult.Succeeded(CommunicationChannel.Email, "msg-001"));

    var service = new CommunicationService(emailService: mockEmail.Object);

    var result = await service.SendAsync(new CommunicationMessage
    {
        Channel = CommunicationChannel.Email,
        Recipient = "user@example.com",
        Subject = "Test",
        Body = "<p>Hello</p>"
    });

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

    mockEmail.Verify(e => e.SendAsync(
        It.Is<EmailMessage>(m => m.To.Contains("user@example.com")),
        It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
public async Task CommunicationService_returns_failure_when_channel_not_registered()
{
    var service = new CommunicationService(); // No services registered

    var result = await service.SendAsync(new CommunicationMessage
    {
        Channel = CommunicationChannel.Sms,
        Recipient = "+27821234567",
        Body = "Hello"
    });

    result.Success.Should().BeFalse();
    result.Error.Should().Contain("not registered");
}

Troubleshooting

Issue Solution
SendResult.Error says "service is not registered" The channel-specific service (e.g., IEmailService) was not added to DI. Register the implementation package (e.g., AddRepletoryEmail)
BulkSendResult shows partial failures Inspect individual Results entries -- bulk operations continue on per-message failure
CommunicationMessage with wrong Channel Ensure the Channel enum matches the recipient type (email address, phone number, device token)
ArgumentNullException on send Ensure the message object is not null before passing it to send methods

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 (4)

Showing the top 4 NuGet packages that depend on RepletoryLib.Communication.Abstractions:

Package Downloads
RepletoryLib.Communication.Email

AWS SES email service implementation for RepletoryLib

RepletoryLib.Communication.Sms

AWS SNS SMS service implementation for RepletoryLib

RepletoryLib.Communication.WhatsApp

360Dialog WhatsApp messaging implementation for RepletoryLib

RepletoryLib.Communication.Push

Push notification service (Firebase, Expo, WebPush) for RepletoryLib

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 90 3/2/2026