MailForge

Core

The MailForge package contains the framework pipeline: models, builders, typed emails, rendering, validation, retries, auditing, middleware, and failover.

Models

Building a Message

using MailForge.Models;

var message = EmailMessage.Create()
    .From("noreply@example.com", "Acme")
    .To("jane@example.com")
    .Cc("billing@example.com")
    .Subject("Order #1042 confirmed")
    .Html("<h1>Order confirmed</h1><p>On its way.</p>")
    .Text("Order #1042 confirmed. On its way.")
    .Priority(EmailPriority.High)
    .Header("X-Sev", "2")
    .Tag("kind", "order")
    .Attachment(new EmailAttachment("invoice.pdf", bytes, "application/pdf"))
    .Build();

Typed Emails

Subclass Email<TModel> and build the message in the constructor from the model:

public sealed class WelcomeEmail : Email<WelcomeModel>
{
    public WelcomeEmail(WelcomeModel model) : base(model)
    {
        AddTo("user@example.com");
        SetSubject("Welcome !");
        SetHtml("<h1>Welcome !</h1>");
        AddTag("kind", "welcome");
    }
}

The protected builder surface is SetFrom, AddTo, AddCc, AddBcc, SetSubject, UseTemplate, SetHtml, SetText, SetPriority, Attach, AddHeader, AddTag.

Send typed emails with sender.SendAsync(new WelcomeEmail(model)).

The Sender

IEmailSender is the entry point. EmailSender composes rendering, validation, retries, logging, audit, and your middleware, then hands the message to the configured provider. Register it via AddMailForge; you can also construct EmailSender directly if you are not using dependency injection.

For channel-agnostic sending on top of the email pipeline, see Communication.

Validation

The default DefaultEmailValidator requires a sender, at least one recipient, a subject, and a body, and checks every address is well formed. Add more validators:

services.AddMailForge(builder => builder
    .AddValidator(new MyDomainValidator())
    .AddValidator(new PrivacyGuard()));

Validators are IEmailValidator implementations returning IReadOnlyList<ValidationProblem>.

Auto Plain Text

Plain-text generation from HtmlBody is enabled by default — a TextBody is derived from HTML when only HTML was supplied, stripping <script>/<style>/<title> blocks and collapsing whitespace at block boundaries. Disable it with EnableAutoPlainText(false).

Retries, Logging, and Auditing

Custom Middleware

Implement IEmailMiddleware (see NextEmailHandler) and register it with AddMiddleware, which runs after the built-in retry/logging/audit middleware:

public sealed class KillSwitchMiddleware : IEmailMiddleware
{
    public async Task<EmailDeliveryResult> InvokeAsync(EmailDeliveryContext context, NextEmailHandler next)
    {
        if (context.Items.ContainsKey("maintenance"))
            return EmailDeliveryResult.Failed(context.Message, "killed by maintenance mode");
        return await next();
    }
}