Regira-Packages

Regira Office.Mail

Regira Office.Mail provides a unified abstraction for sending email through multiple providers. All implementations share the same IMailService interface, making mail backends interchangeable in consuming code.

Projects

Project Package Backend
Common.Office (transitive) Shared abstractions, models, and DummyMailer
Mail.SendGrid Regira.Office.Mail.SendGrid SendGrid API
Mail.MailGun Regira.Office.Mail.MailGun Mailgun REST API
Mail.Web Regira.Office.Mail.Web HTTP request DTOs for mail endpoints
Mail.MSGReader Regira.Office.Mail.MSGReader Read existing .msg and .eml files
Security.Authentication.Web Regira.Security.Authentication.Web IdentityMailer bridge to ASP.NET Identity’s IEmailSender

Installation

<!-- SendGrid -->
<PackageReference Include="Regira.Office.Mail.SendGrid" Version="6.*" />

<!-- Mailgun -->
<PackageReference Include="Regira.Office.Mail.MailGun" Version="6.*" />

<!-- Mail.Web -->
<PackageReference Include="Regira.Office.Mail.Web" Version="6.*" />

<!-- Mail.MSGReader -->
<PackageReference Include="Regira.Office.Mail.MSGReader" Version="6.*" />

<!-- IdentityMailer (ASP.NET Identity integration) -->
<PackageReference Include="Regira.Security.Authentication.Web" Version="6.*" />

Quick Start

IServiceCollection services  = new ServiceCollection();
IConfiguration configuration = new ConfigurationBuilder().Build();

// Register (pick one)
services.AddSendGrid(cfg => cfg.Key = configuration["Mail:SendGrid:Key"]!);
// or
services.AddMailGun(cfg =>
{
    cfg.Api    = configuration["Mail:MailGun:Api"]!;
    cfg.Key    = configuration["Mail:MailGun:Key"]!;
    cfg.Domain = configuration["Mail:MailGun:Domain"]!;
});

// Use — the parameters are interface-typed, so construct the concrete models
// (the implicit string conversions don't apply to IMailAddress/IMailRecipient)
IMailService mailer = services.BuildServiceProvider().GetRequiredService<IMailService>();
await mailer.Send(
    sender:     new MailAddress { Email = "no-reply@example.com" },
    recipients: [new MailRecipient { Email = "alice@example.com" }],
    subject:    "Hello",
    message:    "<p>Hi!</p>"
);

IMailService

Both backends implement this interface.

// Parameter-based overload
Task<IMailResponse> Send(
    IMailAddress             sender,
    IEnumerable<IMailRecipient> recipients,
    string?                  subject,
    string?                  message,
    bool                     isHtml      = true,
    IEnumerable<INamedFile>? attachments = null,
    CancellationToken        cancellationToken = default);

// Full message overload
Task<IMailResponse> Send(IMessageObject message, CancellationToken cancellationToken = default);

IMailResponse

Property Type Description
Success bool true when the provider accepted the message
Status string? HTTP status code or provider status text
Content string? Raw response body
Exception Exception? Set when sending fails

Core Models

IMessageObject / MessageObject

Represents a complete outgoing email.

Property Type Default Description
From MailAddress? null Sender address
To ICollection<MailRecipient> [] Recipients (To / Cc / Bcc)
ReplyTo IMailAddress? null Reply-To address
Subject string? null Email subject
Body string? null Message body
IsHtml bool true HTML vs plain text
Attachments ICollection<BinaryFileItem>? null File attachments

MessageObject exposes the concrete model types shown above; the interface-typed members of IMessageObject (IMailAddress? From, ICollection<IMailRecipient> To, ICollection<INamedFile>? Attachments) are implemented explicitly and convert to/from the concrete types.

IMailAddress / MailAddress

Property Type Description
Email string Email address — validated on assignment
DisplayName string? Optional display name

MailAddress supports implicit conversion from string:

MailAddress addr  = "alice@example.com";
MailAddress named = new() { Email = "alice@example.com", DisplayName = "Alice" };

ToString() returns "Alice <alice@example.com>" when DisplayName is set, or just the email.

IMailRecipient / MailRecipient

Extends IMailAddress with a recipient type.

public enum RecipientTypes { To, Cc, Bcc }
MailRecipient to  = "alice@example.com";   // implicit — defaults to RecipientTypes.To
var cc = new MailRecipient { Email = "bob@example.com",   RecipientType = RecipientTypes.Cc };
var bcc = new MailRecipient { Email = "carol@example.com", RecipientType = RecipientTypes.Bcc };

Configuration

SendGridConfig

Property Type Description
Key string SendGrid API key

MailgunConfig

Property Type Description
Api string Mailgun API endpoint (e.g. https://api.mailgun.net/v3)
Key string Mailgun API key
Domain string Sending domain
TestMode bool Sends with Mailgun’s o:testmode flag. Default false.

With TestMode enabled, Mailgun validates, accepts and logs each call exactly as it would a real one, but never delivers it to the recipient. The response is a normal success, so code and tests that check response.Success are unaffected. Note that it suppresses delivery, not billing — message counts and charges may still apply.

DI Registration

IServiceCollection services = new ServiceCollection();

// SendGrid
services.AddSendGrid(cfg => cfg.Key = "SG.xxx");

// Mailgun
services.AddMailGun(cfg =>
{
    cfg.Api    = "https://api.mailgun.net/v3";
    cfg.Key    = "key-xxx";
    cfg.Domain = "mail.example.com";
});

// Mailgun, accepted and logged but never delivered — for staging hosts and test suites
// that send to real addresses
services.AddMailGun(cfg =>
{
    cfg.Api      = "https://api.mailgun.net/v3";
    cfg.Key      = "key-xxx";
    cfg.Domain   = "mail.example.com";
    cfg.TestMode = true;
});

Both extension methods register IMailService as a transient service.

Exceptions

MailException

Thrown by the shared MailerBase for invalid attachments (missing file name or empty content), and by the SendGrid and Mailgun backends when the provider returns a non-success response. The provider’s own error body is on ResponseContent — the status code alone rarely says why a send was refused. An unauthorized response is the exception: both backends throw a plain Exception("Not authorized") for it.

Property Type Description
MessageObject IMessageObject? The message that failed to send
ResponseContent string? Raw provider response body

EmailFormatException

Thrown when an invalid email address is assigned to MailAddress.Email.

Property Type Description
EmailInput string? The invalid value that was provided

Testing — DummyMailer

DummyMailer implements IMailService (via MailerBase) and sends nothing — it returns an empty MailResponse, so Success is false. Register it in tests to suppress actual sending:

IServiceCollection services = new ServiceCollection();
services.AddSingleton<IMailService, DummyMailer>();

Web DTOs — MailInput

Mail.Web ships MailInput for accepting email requests over HTTP. MailInputExtensions.ToMessageObject() converts it to a domain IMessageObject.

[HttpPost]
public async Task<IActionResult> Send([FromBody] MailInput input, IMailService mailer)
{
    var message = input.ToMessageObject();
    var result  = await mailer.Send(message);
    return result.Success ? Ok() : StatusCode(502);
}

MailInput structure

Property Type Validation Description
From Address? — Optional sender override
To ICollection<Recipient>? [Required] Recipients
ReplyTo Address? — Reply-To address
Subject string? [Required] Email subject
Body string? — HTML or plain text body
IsHtml bool — Defaults to true
Attachments ICollection<Attachment>? — File attachments

Address and Recipient both support implicit conversion from a plain email string.

ASP.NET Identity Integration

IdentityMailer (from the Regira.Security.Authentication.Web package, namespace Regira.Security.Authentication.Web.Mail) bridges IMailService to the ASP.NET Identity IEmailSender interface.

IServiceCollection services = new ServiceCollection();
services.AddSingleton<IEmailSender>(provider =>
    new IdentityMailer(
        provider.GetRequiredService<IMailService>(),
        new IdentityMailerOptions { Sender = "no-reply@example.com" }
    ));

Overview

  1. Index — Overview, interface, models, and configuration reference
  2. Examples — Simple send, attachments & multiple recipients, backend swap, Identity integration