CI NuGet NuGet License Codecov
Modern .NET email library. Drop-in replacement for FluentEmail.
| FluentEmail | MailVolt |
|---|---|
| Unmaintained since 2022 | Actively maintained |
| Sync API with async wrappers | Async-only from day one |
Static Email.From(...) entry point |
DI-first with MailVoltBuilder |
| No batch sending | IBatchEmailSender with concurrency control and rate limiting |
| No SendGrid inline images | Supported |
Mailgun ignores ReplyTo |
Fixed |
| No test helpers | InMemorySender plus fluent assertions |
| Razor via RazorLight | Native ASP.NET Core Razor |
See Migrating from FluentEmail.
Targets net8.0, net9.0 and net10.0. Building from source needs the .NET 10 SDK (the DI extensions use C# 14 extension members); consuming the packages does not.
dotnet add package MailVolt.AutoConfigure
{
"MailVolt": {
"From": { "Address": "noreply@example.com", "DisplayName": "My App" },
"Transport": "Smtp",
"Templates": "Razor",
"Smtp": {
"Host": "smtp.example.com",
"Port": 587,
"Username": "USER",
"Password": "PASS"
}
}
}// Program.cs — everything comes from configuration builder.Services.AddMailVolt(builder.Configuration);
Switch providers by changing Transport and adding the matching section — no code change.
Supports Smtp · SendGrid · Mailgun · Resend · Postmark · Azure · Brevo ·
AwsSes · InMemory. See docs/autoconfigure.md for every option.
dotnet add package MailVolt.Core
dotnet add package MailVolt.Transport.Smtp
using MailVolt.Core.DependencyInjection; // One using covers AddMailVolt and every transport and template engine. builder.Services.AddMailVolt() .UseSmtpTransport(options => { options.Host = "smtp.example.com"; options.Username = "user"; options.Password = "pass"; });
using MailVolt.Core.Interfaces; public sealed class WelcomeService(IEmailBuilder email) { public async Task SendAsync(string recipient, CancellationToken cancellationToken) { var result = await email .From("sender@example.com") .To(recipient) .Subject("Hello from MailVolt!") .HtmlBody("<h1>Welcome!</h1>") .SendAsync(cancellationToken); if (result.IsFailure) { throw new InvalidOperationException(result.Error); } } }
IEmailBuilder is registered transient, so inject a fresh one per send. Do not hold one and
reuse it across messages — see docs/troubleshooting.md.
| Package | Purpose |
|---|---|
MailVolt.Core |
Abstractions, fluent builder, batch sender, in-memory transport |
MailVolt.AutoConfigure |
Zero-code setup from appsettings.json |
MailVolt.Testing |
AwesomeAssertions extensions for asserting on sent mail |
Transports: MailVolt.Transport.{Smtp,SendGrid,Mailgun,Resend,Postmark,AzureEmail,Brevo,AwsSes}.
Templates: MailVolt.Templates.{Razor,Liquid,Handlebars}.
| Provider | Package | Registration | Docs |
|---|---|---|---|
| SMTP (MailKit) | MailVolt.Transport.Smtp |
UseSmtpTransport |
docs |
| SendGrid | MailVolt.Transport.SendGrid |
UseSendGridTransport |
docs |
| Mailgun | MailVolt.Transport.Mailgun |
UseMailgunTransport |
docs |
| Resend | MailVolt.Transport.Resend |
UseResendTransport |
docs |
| Postmark | MailVolt.Transport.Postmark |
UsePostmarkTransport |
docs |
| Azure Email | MailVolt.Transport.AzureEmail |
UseAzureEmailTransport |
docs |
| Brevo | MailVolt.Transport.Brevo |
UseBrevoTransport |
docs |
| AWS SES | MailVolt.Transport.AwsSes |
UseAwsSesTransport |
docs |
| In-memory | MailVolt.Core |
UseInMemoryTransport |
docs |
| Engine | Package | Registration | Docs |
|---|---|---|---|
Razor (.cshtml) |
MailVolt.Templates.Razor |
UseRazorTemplates |
docs |
| Liquid | MailVolt.Templates.Liquid |
UseLiquidTemplates |
docs |
| Handlebars | MailVolt.Templates.Handlebars |
UseHandlebarsTemplates |
docs |
using MailVolt.Core.Interfaces; public sealed class DigestService(IBatchEmailSender batchSender) { public async Task<BatchEmailResult> SendAsync( IReadOnlyList<EmailMessage> emails, CancellationToken cancellationToken) { return await batchSender.SendBatchAsync(emails, new BatchSendOptions( MaxConcurrency: 10, DelayMs: 200, FailureStrategy: FailureStrategy.Continue), cancellationToken); } }
SentCount, FailedCount and SkippedCount always sum to TotalCount.
See docs/advanced/batch-sending.md.
dotnet add package MailVolt.Testing
using MailVolt.Core.DependencyInjection; using MailVolt.Core.Transports; using MailVolt.Testing; var services = new ServiceCollection(); services.AddMailVolt().UseInMemoryTransport(); await using var provider = services.BuildServiceProvider(); var sender = provider.GetRequiredService<InMemorySender>(); await provider.GetRequiredService<WelcomeService>().SendAsync("user@example.com", default); sender.Should() .HaveCount(1) .ContainEmailTo("user@example.com") .ContainSubject("Welcome!");
- Getting started
- Configuration reference
- Migrating from FluentEmail
- Troubleshooting
- Attachments and inline images
- Batch sending
- Resilience
- Testing
- Full index
MailVolt follows Semantic Versioning. While the version is below
1.0.0 the public API may still change between minor releases; breaking changes are called
out in CHANGELOG.md. All packages are versioned and released together.
Issues and pull requests are welcome — see CONTRIBUTING.md, CODE_OF_CONDUCT.md and SECURITY.md.