RepletoryLib.Communication.Email 1.0.0

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

RepletoryLib.Communication.Email

AWS SES v2 email service implementation with support for HTML/text emails, attachments, and provider-hosted templates.

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

NuGet .NET 10 License: MIT


Overview

RepletoryLib.Communication.Email provides an AWS Simple Email Service (SES) v2 implementation of the IEmailService interface from RepletoryLib.Communication.Abstractions. It supports simple text/HTML emails, raw MIME messages with file attachments, and templated emails using SES-hosted templates.

The service handles sender address formatting, configuration set integration, reply-to defaults, custom headers, and CC/BCC recipients out of the box. It also automatically registers the unified ICommunicationService facade so messages can be routed across channels.

Key Features

  • Simple emails -- HTML and/or plain text body with subject, CC, BCC, reply-to, and custom headers
  • File attachments -- Raw MIME message construction for emails with binary attachments
  • Templated emails -- SES-hosted template support with template data substitution
  • Bulk send -- Send multiple emails with per-message success/failure tracking
  • Configuration set -- Optional SES configuration set for delivery tracking and event publishing
  • 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.Email

Or add to your .csproj:

<PackageReference Include="RepletoryLib.Communication.Email" 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.SimpleEmailV2 NuGet (3.7.402)
Microsoft.Extensions.Configuration.Abstractions NuGet (10.0.0)
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 SES v2 enabled
  • Verified sender email address or domain in SES
  • AWS credentials (access key/secret key or IAM role)

Quick Start

using RepletoryLib.Communication.Email;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRepletoryEmail(builder.Configuration);
{
  "Communication": {
    "Email": {
      "Region": "af-south-1",
      "FromAddress": "noreply@example.com",
      "FromName": "My Application",
      "AccessKey": "AKIAIOSFODNN7EXAMPLE",
      "SecretKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
    }
  }
}

Configuration

SesOptions

Property Type Default Description
Region string "af-south-1" AWS region for the SES service
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
FromAddress string "" Sender email address used in the From header
FromName string? null Sender display name. When set, From is formatted as "FromName <FromAddress>"
ConfigurationSetName string? null Optional SES configuration set name for delivery tracking
ReplyToAddress string? null Default reply-to address when the message does not specify one

Section name: "Communication:Email"


Usage Examples

Register Services

using RepletoryLib.Communication.Email;

var builder = WebApplication.CreateBuilder(args);

// Register the SES email service
builder.Services.AddRepletoryEmail(builder.Configuration);

var app = builder.Build();

Send a Simple Email

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

public class OrderService
{
    private readonly IEmailService _emailService;

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

    public async Task SendOrderConfirmationAsync(string customerEmail, string orderId, decimal total)
    {
        var result = await _emailService.SendAsync(new EmailMessage
        {
            To = [customerEmail],
            Subject = $"Order Confirmation - #{orderId}",
            HtmlBody = $"""
                <h1>Thank you for your order!</h1>
                <p>Order ID: <strong>{orderId}</strong></p>
                <p>Total: <strong>{total:C}</strong></p>
                """,
            TextBody = $"Thank you for your order!\nOrder ID: {orderId}\nTotal: {total:C}"
        });

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

Send Email with CC, BCC, and Reply-To

var result = await _emailService.SendAsync(new EmailMessage
{
    To = ["customer@example.com"],
    Cc = ["manager@example.com"],
    Bcc = ["audit@example.com"],
    Subject = "Invoice #12345",
    HtmlBody = "<p>Please find your invoice attached.</p>",
    ReplyTo = "billing@example.com",
    Headers = new Dictionary<string, string>
    {
        ["X-Custom-Tracking"] = "invoice-12345"
    }
});

Send Email with Attachments

var pdfBytes = await File.ReadAllBytesAsync("/path/to/invoice.pdf");

var result = await _emailService.SendAsync(new EmailMessage
{
    To = ["customer@example.com"],
    Subject = "Your Invoice",
    HtmlBody = "<p>Please find your invoice attached.</p>",
    Attachments =
    [
        new EmailAttachment
        {
            FileName = "invoice-2024-001.pdf",
            ContentType = "application/pdf",
            Content = pdfBytes
        }
    ]
});

Send Templated Email

using RepletoryLib.Communication.Abstractions.Models.Email;

var result = await _emailService.SendTemplateAsync(new TemplatedEmailMessage
{
    To = ["customer@example.com"],
    TemplateName = "OrderShipped",
    TemplateData = new Dictionary<string, string>
    {
        ["customerName"] = "John Doe",
        ["orderId"] = "ORD-2024-001",
        ["trackingUrl"] = "https://tracking.example.com/abc123",
        ["estimatedDelivery"] = "March 5, 2026"
    },
    Cc = ["notifications@example.com"]
});

Bulk Send

var emails = customers.Select(c => new EmailMessage
{
    To = [c.Email],
    Subject = "Monthly Newsletter - March 2026",
    HtmlBody = newsletterHtml,
    TextBody = newsletterText
});

var bulkResult = await _emailService.SendBulkAsync(emails);

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 NotificationService
{
    private readonly ICommunicationService _communication;

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

    public async Task NotifyAsync(string email, string subject, string body)
    {
        var result = await _communication.SendAsync(new CommunicationMessage
        {
            Channel = CommunicationChannel.Email,
            Recipient = email,
            Subject = subject,
            Body = body
        });
    }
}

API Reference

ServiceCollectionExtensions

Method Returns Description
AddRepletoryEmail(configuration) IServiceCollection Registers IAmazonSimpleEmailServiceV2 (singleton), IEmailService (scoped), and ICommunicationService (scoped)

SesEmailService (implements IEmailService)

Method Returns Description
SendAsync(EmailMessage, ct) Task<SendResult> Sends a single email (simple or raw MIME with attachments)
SendBulkAsync(IEnumerable<EmailMessage>, ct) Task<BulkSendResult> Sends multiple emails with per-message results
SendTemplateAsync(TemplatedEmailMessage, ct) Task<SendResult> Sends an email using an SES-hosted template

SesOptions

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)
FromAddress string "" Sender email address
FromName string? null Sender display name
ConfigurationSetName string? null SES configuration set name
ReplyToAddress string? null Default reply-to address

Integration with Other RepletoryLib Packages

Package Relationship
RepletoryLib.Communication.Abstractions Direct dependency -- provides IEmailService, EmailMessage, SendResult
RepletoryLib.Communication.Sms Combine with SMS 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.SimpleEmailV2;
using Amazon.SimpleEmailV2.Model;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using RepletoryLib.Communication.Abstractions.Enums;
using RepletoryLib.Communication.Abstractions.Models.Email;
using RepletoryLib.Communication.Email.Options;
using RepletoryLib.Communication.Email.Services;

[Fact]
public async Task SendAsync_returns_success_with_message_id()
{
    var mockSes = new Mock<IAmazonSimpleEmailServiceV2>();
    mockSes
        .Setup(s => s.SendEmailAsync(It.IsAny<SendEmailRequest>(), It.IsAny<CancellationToken>()))
        .ReturnsAsync(new SendEmailResponse { MessageId = "ses-msg-001" });

    var options = Options.Create(new SesOptions
    {
        Region = "af-south-1",
        FromAddress = "noreply@example.com",
        FromName = "Test App"
    });

    var service = new SesEmailService(mockSes.Object, options, NullLogger<SesEmailService>.Instance);

    var result = await service.SendAsync(new EmailMessage
    {
        To = ["user@example.com"],
        Subject = "Test",
        HtmlBody = "<p>Hello</p>"
    });

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

Troubleshooting

Issue Solution
AmazonSimpleEmailServiceV2Exception: Email address is not verified Verify the sender email address or domain in the AWS SES console
AmazonSimpleEmailServiceV2Exception: Access Denied Verify your AWS access key/secret key, or ensure the IAM role has ses:SendEmail permissions
Emails not arriving Check the SES sending dashboard for bounces/complaints. Ensure you are out of the SES sandbox for production sends
FromAddress is empty Set Communication:Email:FromAddress in appsettings.json
Attachments not sending Ensure EmailAttachment.Content is a non-empty byte array and ContentType is a valid MIME type
Template data not applied Ensure TemplateData keys match the placeholders in the SES template exactly

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 72 3/2/2026