Southport.Messaging.Email.MailGun
10.0.5
dotnet add package Southport.Messaging.Email.MailGun --version 10.0.5
NuGet\Install-Package Southport.Messaging.Email.MailGun -Version 10.0.5
<PackageReference Include="Southport.Messaging.Email.MailGun" Version="10.0.5" />
<PackageVersion Include="Southport.Messaging.Email.MailGun" Version="10.0.5" />
<PackageReference Include="Southport.Messaging.Email.MailGun" />
paket add Southport.Messaging.Email.MailGun --version 10.0.5
#r "nuget: Southport.Messaging.Email.MailGun, 10.0.5"
#:package Southport.Messaging.Email.MailGun@10.0.5
#addin nuget:?package=Southport.Messaging.Email.MailGun&version=10.0.5
#tool nuget:?package=Southport.Messaging.Email.MailGun&version=10.0.5
Southport.Messaging.Email.MailGun
A Mailgun implementation of Southport.Messaging.Email.Core. It sends email through the Mailgun Messages API using a fluent message builder, with per-recipient Handlebars substitutions, Mailgun stored templates, attachments, and a test-address redirect for non-production environments.
Targets .NET 9.0 and .NET 10.0. Licensed under MIT.
Installation
Available on nuget.org.
dotnet add package Southport.Messaging.Email.MailGun
Configuration
The library reads a MailGunOptions instance:
| Property | Required | Description |
|---|---|---|
ApiKey |
Yes | Mailgun private API key. Sent as HTTP basic auth with user name api. |
Domain |
Yes | Mailgun sending domain used when Send() is called without a domain. |
TestEmailAddresses |
No | Comma-separated list. When set, every message is redirected to these addresses instead of the real recipients. See Test email addresses. |
Example appsettings.json section:
{
"MailGun": {
"ApiKey": "key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Domain": "mail.example.com",
"TestEmailAddresses": ""
}
}
Registering with dependency injection
Both overloads register IMailGunMessageFactory as a typed HttpClient service.
// From a configuration section
builder.Services.AddMailGunServices(builder.Configuration.GetSection("MailGun"));
// Or from an options instance
builder.Services.AddMailGunServices(new MailGunOptions
{
ApiKey = "key-xxxxxxxx",
Domain = "mail.example.com"
});
IMailGunMessageFactory extends the core IEmailMessageFactory, so code written against
the core abstractions can take either interface.
Sending a message
public class WelcomeMailer
{
private readonly IMailGunMessageFactory _messageFactory;
public WelcomeMailer(IMailGunMessageFactory messageFactory)
{
_messageFactory = messageFactory;
}
public async Task SendAsync(string toAddress, CancellationToken cancellationToken)
{
await using var message = _messageFactory.Create();
var results = await message
.SetFromAddress("no-reply@example.com", "Example")
.AddToAddress(toAddress)
.SetSubject("Welcome")
.SetText("Thanks for signing up.")
.SetHtml("<p>Thanks for signing up.</p>")
.Send(cancellationToken: cancellationToken);
foreach (var result in results)
{
if (!result.IsSuccessful)
{
throw new InvalidOperationException(result.Message);
}
}
}
}
Send() makes one request to Mailgun per recipient and returns one IEmailResult per
recipient. Each result carries the recipient, a success flag, the raw Mailgun response in
Message, and the body that was sent in MessageBody.
Send() throws SouthportMessagingException when the from address is missing, when there
are no valid recipients, or when the message has no text, HTML, AMP HTML, or template.
Send overloads
Task<IEnumerable<IEmailResult>> Send(CancellationToken cancellationToken = default);
Task<IEnumerable<IEmailResult>> Send(bool substitute = true, CancellationToken cancellationToken = default);
Task<IEnumerable<IEmailResult>> Send(string domain, CancellationToken cancellationToken = default);
Pass substitute: false to skip Handlebars rendering and send the body as written. Pass a
domain to send from a domain other than the one in MailGunOptions.
Substitutions
Subject, text, HTML, and AMP HTML bodies are rendered with Handlebars.Net before sending. Substitutions can be set per recipient or at message level. Recipient values override message-level values with the same key.
var recipients = new List<IEmailRecipient>
{
new EmailRecipient("ann@example.com", substitutions: new Dictionary<string, object> { ["FirstName"] = "Ann" }),
new EmailRecipient("ben@example.com", substitutions: new Dictionary<string, object> { ["FirstName"] = "Ben" })
};
await using var message = _messageFactory.Create();
var results = await message
.SetFromAddress("no-reply@example.com")
.AddToAddresses(recipients)
.SetSubject("Hello {{FirstName}}")
.SetText("Dear {{FirstName}}, this is a test email.")
.AddSubstitution("Company", "Example Co")
.Send();
Mailgun stored templates
Reference a template stored in Mailgun with SetTemplate. Substitutions are passed to
Mailgun as template variables rather than rendered locally. SetTemplateVersion and
SetTemplateText map to the Mailgun t:version and t:text options.
var recipient = new EmailRecipient("ann@example.com", substitutions: new Dictionary<string, object>
{
["name"] = "Ann Example",
["states"] = new List<string> { "CA", "CT", "TN" }
});
await using var message = _messageFactory.Create();
var results = await message
.SetFromAddress("no-reply@example.com")
.AddToAddress(recipient)
.SetSubject("Your account")
.SetTemplate("welcome_template")
.Send();
Attachments
Attachment types come from the core package. Attachments can be added at message level or per recipient.
await using var pdfStream = File.OpenRead("report.pdf");
await using var message = _messageFactory.Create();
var results = await message
.SetFromAddress("no-reply@example.com")
.AddToAddress("ann@example.com")
.SetSubject("Monthly report")
.SetText("The report is attached.")
.AddAttachments(new EmailAttachmentString("Plain text content.", "notes.txt"))
.AddAttachments(new EmailAttachmentStream(pdfStream, "report.pdf", "application/pdf"))
.Send();
Stream and byte-array attachments are sent in full in every per-recipient request.
Mailgun-specific options
| Method | Mailgun field |
|---|---|
SetAmpHtml(string) |
amp-html |
SetTag(string) / SetTags(list) |
o:tag |
SetDkim(bool) |
o:dkim |
SetDeliveryTime(DateTime) |
o:deliverytime |
SetTestMode(bool) |
o:testmode |
SetTracking(bool) |
o:tracking |
SetTrackingClicks(bool) |
o:tracking-clicks |
SetTrackingOpens(bool) |
o:tracking-opens |
SetRequireTls(bool) |
o:require-tls |
SetSkipVerification(bool) |
o:skip-verification |
AddHeader(key, value) |
h:<key> |
AddCustomArgument(key, value) |
v:<key> |
SetReplyTo(string) |
h:Reply-To |
Test email addresses
When TestEmailAddresses is set, every To, CC, and BCC recipient is replaced with the
listed addresses. Each original To recipient produces one message per test address, keeping
that recipient's substitutions, custom arguments, and attachments. The custom argument
IsTest=true is added to each redirected message. Use this in development and staging to
prevent mail reaching real users.
Building and testing
dotnet restore
dotnet build --configuration Release
dotnet test --configuration Release
The tests send real messages through Mailgun. They need an API key and domain, read from
either a MailGun section in an appsettings.json file at the test project root (ignored by
git) or the MAILGUNAPIKEY and MAILGUNDOMAIN environment variables. Several tests expect a
stored template named test_template to exist on the domain.
Releases
The GitHub Actions workflow builds, tests, and packs on every push and pull request to
main. Pushing a tag of the form release@<version> publishes that version to nuget.org.
Contributing
Open an issue or pull request on GitHub.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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. |
-
net10.0
- Handlebars.Net (>= 2.4.3)
- Microsoft.Extensions.Http (>= 10.0.13)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.13)
- Southport.Messaging.Email.Core (>= 10.0.5)
-
net9.0
- Handlebars.Net (>= 2.4.3)
- Microsoft.Extensions.Http (>= 9.0.21)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 9.0.21)
- Southport.Messaging.Email.Core (>= 10.0.5)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Southport.Messaging.Email.MailGun:
| Package | Downloads |
|---|---|
|
Southport.Azure.Functions.Extensions
Package Description |
|
|
Southport.Azure.Functions.Isolated.Extensions
Initial Release |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.0.5 | 132 | 10/13/2026 |
| 10.0.4 | 114 | 10/8/2026 |
| 10.0.2 | 1,307 | 1/12/2026 |
| 10.0.0 | 298 | 1/1/2026 |
| 8.0.2 | 2,257 | 6/14/2024 |
| 8.0.1 | 324 | 6/5/2024 |
| 8.0.0 | 1,029 | 2/17/2024 |
| 1.4.1 | 3,929 | 12/29/2022 |
| 1.4.0 | 874 | 12/29/2022 |
| 1.3.0 | 872 | 12/28/2022 |
| 1.2.0 | 828 | 12/19/2022 |
| 1.1.0 | 1,624 | 11/30/2022 |
| 1.0.11 | 1,087 | 8/6/2022 |
| 1.0.9 | 8,465 | 8/6/2021 |
| 1.0.9-beta2 | 867 | 8/5/2021 |
| 1.0.9-beta1 | 820 | 8/3/2021 |
| 1.0.8 | 1,133 | 7/31/2021 |
| 1.0.8-beta1 | 787 | 7/30/2021 |
| 1.0.7 | 945 | 7/30/2021 |
| 1.0.6 | 964 | 7/29/2021 |
Core library update.