Dev Life
E-Mail-Versand mit C# und der Mailgun-API
.NET gehört zu den beliebtesten, stabilsten und am meisten geschätzten Web-Frameworks , die für die Entwicklung moderner Webanwendungen zur Verfügung stehen. Die von .NET bereitgestellten Tools helfen Ihnen beim schnellen Einstieg und bei der langfristigen Wartung Ihrer Anwendungen. Damit entwickeln Sie alles von kleinen, hochspezialisierten Microservices bis hin zu vollwertigen Webanwendungen.
Letztendlich muss jedoch jede reale Anwendung in der Lage sein, Transaktions-E-Mails (wie etwa die Verifizierung von Konten, das Zurücksetzen von Passwörtern, automatisierte tägliche oder monatliche Berichte und vieles mehr) zu versenden. Zwar bietet .NET Tools für den Versand von E-Mails, es verfügt jedoch nicht über die produktionsfähige Infrastruktur, die für einen zuverlässigen und effizienten Versand erforderlich ist.
In diesem Artikel erfahren Sie, wie Sie die HTTP-API von Mailgun nutzen, um Transaktions-E-Mails aus Ihren .NET-Anwendungen zu versenden und sicherzustellen, dass Ihre Integration zuverlässig, skalierbar und sicher ist.
E-Mails über die Mailgun-API versenden
Bevor Sie mit diesem Tutorial beginnen, benötigen Sie die folgenden Voraussetzungen:
- Grundkenntnisse in C# und .NET
- Eine moderne IDE wie Visual Studio, JetBrains Rider oder Visual Studio Code
Wenn Sie Visual Studio nicht nutzen und die Ausführung von dotnet –info in einem Terminal nicht erfolgreich ist, müssen Sie das neueste .NET-SDK herunterladen und installieren.
Mailgun-Konto einrichten
Beginnen Sie, indem Sie ein kostenloses Mailgun-Konto erstellen. Sobald Sie eingeloggt sind, erstellen Sie einen neuen API-Schlüssel und speichern diesen für die spätere Verwendung.
Für den produktiven E-Mail-Versand müssen Sie eine eigene Domain bei Mailgun registrieren. In diesem Tutorial nutzen Sie die Sandbox-Domain , die von Mailgun bereitgestellt wird.
Neues C#-Projekt erstellen
Sobald Ihr Mailgun-Konto eingerichtet ist, erstellen Sie eine neue .NET-MVC-Weblösung und konfigurieren einige zusätzliche Tools, die Sie beim Versand von Transaktions-E-Mails mit .NET unterstützen.
Öffnen Sie ein Terminal und führen Sie dotnet new mvc -n MailDemo aus. Dieser Befehl erstellt ein neues .NET-Webprojekt mit einer MVC-Architektur in einem neuen Ordner namens /MailDemo. Führen Sie als Nächstes cd MailDemo aus, um in den neu erstellten Ordner zu navigieren.
Nachdem Sie in den Ordner navigiert sind, fügen Sie Ihre Konfigurationswerte zur Datei appsettings.json hinzu. Fügen Sie einen neuen JSON-Eintrag namens „Mailgun“ hinzu. Der Wert für Mailgun:ApiKey ist der API-Schlüssel, den Sie im vorherigen Abschnitt erstellt haben (mehr zur Absicherung Ihrer API-Schlüssel erfahren Sie später). Mailgun:Domain ist die Sandbox-Domain, die bereits für Sie erstellt wurde.
Ihre gesamte Datei appsettings.json sollte wie folgt aussehen:
{rn "Logging": {rn "LogLevel": {rn "Default": "Information",rn "Microsoft.AspNetCore": "Warning"rn }rn },rn "AllowedHosts": "*",rn "Mailgun": {rn "ApiKey": "<Your API Key>",rn "Domain": "<Your sandbox domain>"rn }rn}
Als Nächstes konfigurieren Sie einen benannten HttpClient , um Standardparameter einfach wiederzuverwenden. Öffnen Sie dazu Program.cs. Der obere Teil der Datei sollte so aussehen:
using System.Net.Http.Headers;rnusing System.Text;rnrnvar builder = WebApplication.CreateBuilder(args);rnrn// Add services to the containerrnbuilder.Services.AddControllersWithViews();rnrn// Set up your named HttpClient for easy reusernbuilder.Services.AddHttpClient("Mailgun", client =>rn{rn // Grab values from the configurationrn var apiKey = builder.Configuration.GetValue<string>("Mailgun:ApiKey");rn var base64Auth = Convert.ToBase64String(Encoding.ASCII.GetBytes($"api:{apiKey}"));rn var domain = builder.Configuration.GetValue<string>("Mailgun:Domain");rnrn // Set default values on the HttpClientrn client.BaseAddress = new Uri($"https://api.mailgun.net/v3/{domain}/messages");rn client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64Auth);rn});rnrnvar app = builder.Build();rn
Da Sie ausschließlich E-Mails versenden, wird Ihr HttpClient mit der vollständigen URL der HTTP-API von Mailgun konfiguriert, die für den E-Mail-Versand genutzt wird.
Zu diesem Zeitpunkt ist alles bereit, was Sie für den Versand Ihrer ersten E-Mail benötigen.
Mehr über die Endpunkte der Mailgun-API
Der HttpClient ist so konfiguriert, dass er HTTP-Anfragen an den Endpunkt https://api.mailgun.net/v3/{domain}/messages sendet. Mailgun bietet zudem weitere Endpunkte, um Ihnen ein robustes und ganzheitliches Tool für die Verwaltung und den Versand von Transaktions-E-Mails zur Verfügung zu stellen:
- E-Mail versenden: POST /v3/{domain_name}/messages
- E-Mail im MIME-Format versenden: POST /v3/{domain_name}/messages.mime
- Eine gespeicherte E-Mail abrufen: GET /v3/domains/{domain_name}/messages/{storage_key}
- Ihre Domains anzeigen: GET /v4/domains
- Eine neue Domain erstellen: POST /v4/domains
- Eine paginierte Liste aller eingehenden und ausgehenden Ereignisse anzeigen: GET /v3/{domain_name}/events
- Eine paginierte Liste aller Bounces anzeigen: GET /v3/{domainID}/bounces
Die erste E-Mail mit der Mailgun-API versenden
Bevor Sie Ihre erste Transaktions-E-Mail versenden, stellen Sie sicher, dass die verwendete E-Mail-Adresse des Empfängers zu den autorisierten Empfängern für Ihre Sandbox-Domain gehört. Öffnen Sie in Ihrem Mailgun-Konto Ihre Domains, wählen Sie Ihre Sandbox-Domain aus und fügen Sie auf der rechten Seite Ihre persönliche E-Mail-Adresse als autorisierten Empfänger hinzu:

Erstellen Sie als Nächstes eine neue Datei unter /Controllers/OrderController.cs und ersetzen Sie deren Inhalt durch den folgenden:
using System.Diagnostics;rnusing Microsoft.AspNetCore.Mvc;rnusing MailDemo.Models;rnusing System.Text;rnusing System.Net.Mime;rnrnnamespace MailDemo.Controllers;rnrnpublic class OrderController : Controllerrn{rn private readonly HttpClient _httpClient;rn private readonly IConfiguration _config;rnrn public OrderController(IHttpClientFactory httpClientFactory, IConfiguration config)rn {rn // Get your named HttpClient that is preconfiguredrn this._httpClient = httpClientFactory.CreateClient("Mailgun");rn this._config = config;rn }rnrn public async Task<IActionResult> Confirm()rn {rn using MultipartFormDataContent form = new();rnrn // Local function keeps this code a bit clearerrn void SetFormParam(string key, string value) =>rn form.Add(new StringContent(value, Encoding.UTF8, MediaTypeNames.Text.Plain), key);rnrn SetFormParam("from", $"Test User <postmaster@{this._config.GetValue<string>("Mailgun:Domain")}>");rn SetFormParam("to", "your_authorized_recipient.com");rn SetFormParam("subject", "Hello World!");rn SetFormParam("text", "My first transactional email!");rn SetFormParam("html", @"<html><body><p style=""color:blue;"">My first transactional email!</p></body></html>");rnrn var result = await this._httpClient.PostAsync(string.Empty, form);rnrn if (!result.IsSuccessStatusCode)rn {rn return new JsonResult(await result.Content.ReadAsStringAsync());rn }rnrn return new JsonResult(@"Your order was confirmed. You should get an email soon!");rn }rn}rn
Führen Sie dotnet run in Ihrem Terminal aus, um Ihre Webanwendung zu starten. Öffnen Sie anschließend einen Webbrowser und navigieren Sie zu /order/confirm. Innerhalb weniger Sekunden sollten Sie eine E-Mail in Ihrem Posteingang erhalten:

Antworten und Fehler behandeln
Leider laufen die Dinge manchmal nicht wie geplant. Beispielsweise könnte Ihr API-Schlüssel einen Tippfehler enthalten, Sie haben möglicherweise nicht alle erforderlichen Felder in die HTTP-Anfrage aufgenommen oder Sie stoßen an die Ratenbegrenzungen von Mailgun.
Eine fehlgeschlagene HTTP-Anfrage an die API von Mailgun gibt einen von vier verschiedenen HTTP-Fehlercodes zurück:
- 400: Etwas mit der Formatierung der Anfrage ist falsch.
- 401: Die Authentifizierung ist fehlgeschlagen.
- 429: Sie haben die Ratenbegrenzung von Mailgun erreicht.
- 500: Etwas im Netzwerk oder aufseiten von Mailgun ist schiefgelaufen.
Sehen wir uns an, wie Sie einige dieser Fehlerszenarien handhaben.
Fehlercodes 400 behandeln
Wenn der HTTP-Statuscode 400 zurückgegeben wird, bedeutet das, dass Ihre Nutzdaten oder die Formatierung inkorrekt waren. Beispielsweise antwortet Mailgun mit einem HTTP-Statuscode 400, wenn ein erforderliches Feld fehlt.
In diesen Fällen können Sie einen allgemeinen Ansatz verfolgen:
- Werfen Sie eine Ausnahme, da es sich hierbei um ein nicht behebbares Fehlerszenario handelt.
- Protokollieren Sie die Ausnahme und deren Ursachen.
Der Code hierfür könnte wie folgt aussehen:
if (!result.IsSuccessStatusCode)rn{rn var status = (int) result.StatusCode;rnrn if (status == 400)rn {rn var responseContent = await result.Content.ReadAsStringAsync();rn var exception = new BadHttpRequestException("Mailgun 400 HTTP status code");rnrn this._logger.LogError(exception, exception.Message, responseContent);rn throw exception;rn }rn}rn
Bei dem HTTP-Statuscode 401 empfiehlt sich ein ähnlicher Ansatz.
Fehlercodes 500 behandeln
Wenn Sie einen HTTP-Statuscode 500 erhalten, kann dies bedeuten, dass aufseiten von Mailgun etwas schiefgelaufen ist oder ein allgemeines Netzwerkproblem aufgetreten ist. Für diese Fälle gibt es verschiedene Ansätze, die Sie verfolgen können:
- Stellen Sie die E-Mail in eine Warteschlange, um den Versand später erneut zu versuchen.
- Versuchen Sie es im selben Code-Pfad nach kurzer Zeit erneut.
- Nutzen Sie eine fortgeschrittene Technik wie ein Circuit-Breaker-Muster
Ein grundlegender Wiederholungsansatz könnte wie folgt aussehen:
if (!result.IsSuccessStatusCode)rn{rn var status = (int) result.StatusCode;rnrn if (status == 500)rn {rn // Retry the email after 1 second in hopes that the error was transientrnrn await Task.Delay(1000);rn result = await _httpClient.PostAsync(string.Empty, form);rnrn if (!result.IsSuccessStatusCode)rn {rn // Log and throw an exception like you did in the previous examplern }rn }rn}rn
Wenn Sie in diesem Szenario den Statuscode 500 erhalten, warten Sie eine Sekunde und versuchen die HTTP-Anfrage erneut. Wenn die wiederholte Anfrage ebenfalls fehlschlägt, protokollieren Sie dies und werfen eine Ausnahme, genau wie beim Szenario für den Statuscode 400.
Um Ihnen eine Vorstellung davon zu geben, wie der gesamte Code aussehen könnte, finden Sie hier ein Grundgerüst dafür, wie Ihr Code mit der Behandlung verschiedener Fehlerszenarien beginnen kann:
if (!result.IsSuccessStatusCode)rn{rn var status = (int)result.StatusCode;rnrn if (status == 400)rn {rn // Log the error and notify the development team that thern // request was not formatted properly.rn }rn else if (status == 401)rn {rn // Log the error and notify the development team that thern // request's authentication failed.rn }rn else if (status == 429)rn {rn // Use a .NET library like Polly to throttle or try this requestrn // again with an exponential back-off, etc.rn }rn elsern {rn // Something went wrong: log the error and apply a distributed rn // error handling technique like a circuit breaker.rn // See https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker for more.rn }rn}rn
Produktionsbereite E-Mail-Integration
An diesem Punkt haben Sie eine E-Mail mit .NET und C# versendet. Für die Produktionsbereitschaft gibt es jedoch noch einige wichtige Dinge zu beachten.
API-Schlüssel absichern
Sie dürfen Ihren echten produktiven API-Schlüssel nicht im Quellcode speichern. Darüber hinaus sollte er für niemanden in reinen Textdateien zugänglich sein.
Es gibt viele Tools, mit denen Sie Ihren API-Schlüssel absichern können. Jeder Cloud-Anbieter verfügt über ein eigenes Schlüsselverwaltungssystem, mit dem Ihre Anwendung Geheimnisse sicher abrufen kann. Zum Beispiel, Azure Key Vault oder AWS Secrets Manager eignen sich hervorragend.
Weitere Funktionen auf Produktionsniveau
Mailgun unterstützt zudem viele Funktionen auf Produktionsniveau, die Sie möglicherweise benötigen, wie etwa:
- Das Hinzufügen von Anhängen zu Ihren E-Mails
- Die Möglichkeit, wiederverwendbare E-Mail-Vorlagen zu erstellen
- Personalisierungsfunktionen wie Variablen und Tags
- CC-, BCC- und Reply-To-Kopfzeilen
Integration in das .NET-Ökosystem
Um zu zeigen, wie einfach die Integration mit produktionsbereiten Tools aus dem .NET-Ökosystem ist, nutzen Sie eine Open-Source-Bibliothek wie Coravel , um die Wiederverwendbarkeit und die Developer Experience Ihrer Lösung zu verbessern.
Führen Sie im Ordner MailDemo den Befehl dotnet add package coravel.mailer in Ihrem Terminal aus.
Fügen Sie dann den folgenden JSON-Eintrag in Ihre Datei appsettings.json ein:
"Coravel": {rn "Mail": {rn "From": {rn "Name": "Test User",rn "Email": "postmaster@<Your sandbox domain>"rn }rn }rn}rnNext, create a class file called MailgunMailer.cs that implements the ICanSendMail interface. You might notice that this is essentially the same logic you originally had in OrderController:rnusing System.Net.Mime;rnusing System.Text;rnusing Coravel.Mailer.Mail;rnrnnamespace MailDemo;rnrnpublic class MailgunMailer : ICanSendMailrn{rn private readonly HttpClient _httpClient;rn private readonly IConfiguration _config;rnrn public MailgunMailer(IHttpClientFactory httpClientFactory, IConfiguration config)rn {rn this._httpClient = httpClientFactory.CreateClient("Mailgun");rn this._config = config;rn }rnrn public async Task SendAsync(MessageBody message, string subject, IEnumerable<MailRecipient> to, MailRecipient from, MailRecipient replyTo, IEnumerable<MailRecipient> cc, IEnumerable<MailRecipient> bcc, IEnumerable<Attachment>? attachments = null, MailRecipient? sender = null)rn {rn using MultipartFormDataContent form = new();rnrn void SetFormParam(string key, string value) =>rn form.Add(new StringContent(value, Encoding.UTF8, MediaTypeNames.Text.Plain), key);rnrn if (from is not null)rn {rn SetFormParam("from", $"{from.Name} <{from.Email}>");rn }rn elsern {rn // This gives you a default "from" field if not defined by the callerrn SetFormParam("from", $"{this._config.GetValue<string>("Coravel:Mail:From:Name")} <{this._config.GetValue<string>("Coravel:Mail:From:Email")}>");rn }rnrn foreach (var recipient in to)rn {rn SetFormParam("to", recipient.Email);rn }rn SetFormParam("subject", subject);rnrn if (message.HasHtmlMessage())rn {rn SetFormParam("html", message.Html);rn }rnrn if (message.HasPlainTextMessage())rn {rn SetFormParam("text", message.Text);rn }rnrn var result = await _httpClient.PostAsync(string.Empty, form);rnrn // Error handling logic...rn }rn}rn
Als Nächstes müssen Sie Coravel anweisen, diesen Mailer zu verwenden. Fügen Sie in Ihrer Datei Program.cs vor dem Aufruf von var app = builder.Build() Folgendes hinzu:
builder.Services.AddScoped<MailDemo.MailgunMailer>();rnbuilder.AddCustomMailer<MailDemo.MailgunMailer>();rnFinally, replace the code for OrderController with the following:rnusing Microsoft.AspNetCore.Mvc;rnusing Coravel.Mailer.Mail.Interfaces;rnusing Coravel.Mailer.Mail;rnrnnamespace MailDemo.Controllers;rnrnpublic class OrderController : Controllerrn{rn private readonly IMailer _mailer;rnrn public OrderController(IMailer mailer)rn {rn this._mailer = mailer;rn }rnrn public async Task<IActionResult> Confirm()rn {rn var mailable = Mailable.AsInline()rn .To("jamesmichaelhickey@gmail.com")rn .Subject("Hello World!")rn .Html(@"<html><body><p style=""color:blue;"">My first transactional email!</p></body></html>")rn .Text("My first transactional email!");rnrn await _mailer.SendAsync(mailable);rnrn return new JsonResult(@"Your order was confirmed. You should get an email soon!");rn }rn}rn
Nach einer kurzen einmaligen Konfiguration werden Sie feststellen, dass die Logik für den E-Mail-Versand in Ihrem Anwendungscode deutlich verständlicher und kompakter ist.
Durch Mailgun und Coravel haben Sie zudem die Möglichkeit hinzugefügt, sowohl HTML- als auch reine Text-E-Mail-Inhalte zu definieren. Mailgun empfiehlt, sowohl HTML als auch reinen Text gemeinsam zu versenden. Es ist am besten, Multipart-E-Mails mit sowohl Text als auch HTML oder ausschließlich als Text zu versenden. Der Versand reiner HTML-E-Mails wird von ESPs nicht gerne gesehen.
Zusammenfassung
Mailgun bietet eine unkomplizierte HTTP-API , um E-Mails aus Ihren .NET-Lösungen effizient und sicher zu versenden. In diesem Artikel haben Sie gelernt, wie Sie die HTTP-API von Mailgun in eine C#-Webanwendung integrieren und damit beginnen, Tools auf Produktionsniveau zusammen mit den produktionsbereiten Funktionen von Mailgun hinzuzufügen.
Durch die gemeinsame Nutzung von Mailgun und .NET können Ihre Transaktions-E-Mails effizient skalieren, unterstützt durch die async/await-Funktionalität von .NET, die gesamte vom Framework bereitgestellte hochleistungsfähige Web-Infrastruktur, zusätzliche Tools aus dem .NET-Ökosystem sowie die performante und unkomplizierte HTTP-API von Mailgun.
War das hilfreich? Abonnieren Sie unseren Newsletter, um Updates zu Tutorials, E-Mail-News und Einblicke von unseren hauseigenen E-Mail-Profis zu erhalten.