Dev Life

Envoyer un email avec C# et l’API de Mailgun

Maîtrisez l'envoi d'emails transactionnels avec l'API HTTP de Mailgun en C#. Ce guide vous explique comment configurer un compte Mailgun, l'intégrer à .NET et gérer les erreurs pour une livraison d'emails prête pour la production.
Image pour Envoyer un email avec C# et l’API de Mailgun

.NET est l’un des frameworks web les plus populaires, stables et appréciés que vous pouvez utiliser pour créer des applications web modernes. Les outils fournis par .NET vous aident à démarrer rapidement et à maintenir vos applications sur le long terme. Ils vous permettent de tout créer, des petits microservices ultra-ciblés aux applications web complètes.

Toutefois, chaque application réelle finit par avoir besoin d’envoyer les emails transactionnels (comme la vérification de compte, la réinitialisation de mot de passe, les rapports récapitulatifs quotidiens/mensuels automatisés, etc.). Bien que .NET propose des outils pour vous aider à envoyer des emails, il ne dispose pas de l’infrastructure de production nécessaire pour les envoyer de manière fiable et efficace.

Dans cet article, vous découvrirez comment utiliser l’API HTTP de Mailgun pour envoyer des emails transactionnels depuis vos applications .NET et garantir que votre intégration est fiable, évolutive et sécurisée.

Mailgun est un service d’email transactionnel qui permet à vos applications .NET d’envoyer des emails prêts pour la production. Vous pouvez choisir d’utiliser le service SMTP de Mailgun ou son API HTTP pour une livraison d’emails transactionnels plus performante.

Comment envoyer un email avec l’API de Mailgun

Avant de commencer ce tutoriel, vous aurez besoin des prérequis suivants :

  • Des connaissances de base en C# et .NET
  • Un IDE moderne comme Visual Studio, JetBrains Rider ou Visual Studio Code

Si vous choisissez de ne pas utiliser Visual Studio et que l’exécution de dotnet –info depuis un terminal échoue, vous devrez alors télécharger et installer le dernier SDK .NET.

.NET est un framework multiplateforme, vous pouvez donc l’installer sur Windows, Mac et Linux. Si vous rencontrez des difficultés pour créer une clé API, vous pouvez suivre ces instructions.

Configurer votre compte Mailgun

Commencez par créer un compte Mailgun gratuit. Une fois la connexion établie, créez une nouvelle clé API et conservez-la pour l’utiliser plus tard.

Pour l’envoi d’emails en production, vous devez enregistrer un domaine qui vous appartient auprès de Mailgun. Dans ce tutoriel, vous utiliserez le domaine sandbox fourni par Mailgun.

Créer un nouveau projet C#

Une fois votre compte Mailgun configuré, vous devez créer une nouvelle solution web .NET MVC et configurer des outils supplémentaires pour vous aider à envoyer des emails transactionnels avec .NET.

Ouvrez un terminal et exécutez dotnet new mvc -n MailDemo. Cette commande crée un nouveau projet web .NET utilisant une architecture MVC dans un nouveau dossier /MailDemo. Ensuite, exécutez cd MailDemo pour accéder au nouveau dossier créé.

Une fois dans ce dossier, vous devez ajouter vos valeurs de configuration dans appsettings.json. Ajoutez une nouvelle entrée JSON nommée « Mailgun ». La valeur pour Mailgun:ApiKey est la clé API que vous avez créée dans la section précédente (vous découvrirez comment sécuriser vos clés API plus tard). Mailgun:Domain est le domaine sandbox qui a déjà été créé pour vous.

L’intégralité de votre fichier appsettings.json devrait ressembler à ceci :

                                

                                    {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}
                                
                            

Ensuite, vous devez configurer un HttpClient nommé pour réutiliser facilement les paramètres par défaut. Pour ce faire, ouvrez Program.cs. Le haut du fichier devrait ressembler à ceci :

                                

                                    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
                                
                            

Puisque vous n’enverrez que des emails, votre HttpClient est configuré avec l’URL complète de l’API HTTP de Mailgun utilisée pour l’envoi d’emails.

À ce stade, tout est prêt pour envoyer votre premier email.

En savoir plus sur les points de terminaison de l’API de Mailgun

Le HttpClient est configuré pour envoyer des requêtes HTTP au point de terminaison https://api.mailgun.net/v3/{domain}/messages. Mailgun propose également d’autres points de terminaison pour vous offrir un outil robuste et complet permettant de gérer et d’envoyer des emails transactionnels :

  • Envoyer un email : POST /v3/{domain_name}/messages
  • Envoyer un email au format MIME : POST /v3/{domain_name}/messages.mime
  • Récupérer un email stocké : GET /v3/domains/{domain_name}/messages/{storage_key}
  • Afficher vos domaines : GET /v4/domains
  • Créer un nouveau domaine : POST /v4/domains
  • Afficher une liste paginée de tous les événements entrants et sortants : GET /v3/{domain_name}/events
  • Afficher une liste paginée de tous les rebonds : GET /v3/{domainID}/bounces
Vous pouvez consulter les autres points de terminaison disponibles en visitant la documentation de référence de l’API de Mailgun.

Envoyer votre premier email avec l’API de Mailgun

Avant d’envoyer votre premier email transactionnel, assurez-vous que l’adresse email du destinataire que vous utilisez fait partie des destinataires autorisés pour votre domaine sandbox. Dans votre compte Mailgun, affichez vos domaines, ouvrez votre domaine sandbox, puis sur la droite, ajoutez votre adresse email personnelle comme destinataire autorisé :

Overview Screen

Ensuite, créez un nouveau fichier dans /Controllers/OrderController.cs et remplacez son contenu par ce qui suit :

                                

                                    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
                                
                            

Exécutez dotnet run depuis votre terminal pour démarrer votre application web. Puis, ouvrez un navigateur web et accédez à /order/confirm. Vous devriez recevoir un email dans votre boîte de réception en quelques secondes :

Hello World Screen Shot
L’email peut se retrouver dans votre dossier spam car vous n’avez pas encore enregistré le domaine. Ce n’est pas grave pour le moment.

Gérer les réponses et les erreurs

Malheureusement, il arrive que les choses tournent mal. Par exemple, votre clé API peut contenir une faute de frappe, vous n’avez peut-être pas ajouté tous les champs requis à la requête HTTP, ou vous pourriez avoir atteint la limite de taux de Mailgun.

L’échec d’une requête HTTP vers l’API de Mailgun renverra l’un des quatre codes d’erreur HTTP suivants :

  • 400 : un problème de formatage est survenu dans la requête.
  • 401 : l’authentification a échoué.
  • 429 : vous avez atteint la limite de taux de Mailgun.
  • 500 : un problème est survenu sur le réseau ou du côté de Mailgun.

Voyons comment vous pouvez gérer certains de ces scénarios d’échec.

Gérer les codes d’erreur 400

Chaque fois que vous recevez un code d’état HTTP 400, cela signifie que votre charge utile ou votre formatage était incorrect. Par exemple, Mailgun répondra avec un code d’état HTTP 400 si un champ obligatoire est manquant.

Dans ces cas-là, vous pouvez adopter une approche générale :

  • Lever une exception, car il s’agit d’un scénario d’échec irrécupérable.
  • Enregistrer l’exception et les raisons de celle-ci dans les journaux.

Voici à quoi pourrait ressembler le code pour cela :

                                

                                    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
                                
                            

Vous souhaiterez peut-être également adopter une approche similaire avec le code d’état HTTP 401.

Gérer les codes d’erreur 500

Lorsque vous recevez un code d’état HTTP 500, cela peut signifier qu’un problème est survenu du côté de Mailgun ou qu’un problème de réseau général a été détecté. Dans ces cas-là, vous pouvez envisager plusieurs approches différentes :

  • Mettre l’email en file d’attente pour réessayer plus tard.
  • Dans le même chemin de code, réessayer après une courte période.
  • Employer une technique avancée comme un disjoncteur

Voici à quoi pourrait ressembler une approche de nouvelle tentative de base :

                                

                                    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
                                
                            

Dans ce scénario, si vous recevez un code d’état 500, vous attendrez une seconde avant de réessayer la requête HTTP. Si la nouvelle requête échoue également, vous enregistrerez et lèverez une exception de la même manière que pour le scénario du code d’état 400.

Pour vous donner une idée de ce à quoi pourrait ressembler le code global, voici un squelette montrant comment votre code pourrait commencer à gérer divers scénarios d’erreur :

                                

                                    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
                                
                            

Intégration d’emails prête pour la production

À ce stade, vous avez envoyé un email avec .NET et C#, mais pour être prêt pour la production, il y a quelques éléments importants à prendre en compte.

Sécuriser votre clé API

Vous ne pouvez pas stocker votre véritable clé API de production dans le code source. De plus, elle ne doit pas être accessible par quiconque dans des fichiers en texte clair.

Il existe de nombreux outils que vous pouvez utiliser pour sécuriser votre clé API. Chaque fournisseur cloud possède son propre système de gestion de clés qui permet à votre application de récupérer vos secrets de manière sécurisée. Par exemple, Azure Key Vault ou AWS Secrets Manager fonctionnent très bien.

Autres fonctionnalités de niveau production

Mailgun prend également en charge de nombreuses fonctionnalités de niveau production dont vous pourriez avoir besoin, telles que :

S’intégrer à l’écosystème .NET

Pour démontrer à quel point il est facile de s’intégrer aux outils prêts pour la production de l’écosystème .NET, n’hésitez pas à utiliser une bibliothèque open source comme Coravel pour améliorer la réutilisabilité et l’expérience développeur de votre solution.

Exécutez dotnet add package coravel.mailer depuis votre terminal en étant dans le dossier MailDemo.

Ensuite, ajoutez l’entrée JSON suivante à votre fichier appsettings.json :

                                

                                    "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
                                
                            

Ensuite, vous devez indiquer à Coravel d’utiliser ce mailer. Dans votre fichier Program.cs, avant que var app = builder.Build() ne soit appelé, ajoutez ce qui suit :

                                

                                    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
                                
                            

Après une petite configuration initiale, vous remarquerez que la logique d’envoi d’emails depuis le code de votre application est beaucoup plus facile à comprendre et moins verbeuse.

Vous avez également ajouté la prise en charge, via Mailgun et Coravel, de la définition des corps d’emails au format HTML et en texte brut. Mailgun recommande d’envoyer à la fois du HTML et du texte brut ensemble. Il est préférable d’envoyer des emails en plusieurs parties (multipart) contenant à la fois du texte et du HTML, ou uniquement du texte. L’envoi d’emails contenant uniquement du HTML n’est pas bien perçu par les services d’emailing (ESP).

Mailgun et Coravel prennent également en charge d’autres fonctionnalités telles que CC, CCI et les pièces jointes pour des emails transactionnels de niveau production plus avancés.

Conclusion

Mailgun offre un moyen simple API HTTP d’envoyer des emails depuis vos solutions .NET de manière efficace et sécurisée. Dans cet article, vous avez appris à intégrer l’API HTTP de Mailgun dans une application web C# et à commencer à ajouter des outils de niveau production ainsi que les fonctionnalités prêtes pour la production de Mailgun.

En utilisant Mailgun et .NET conjointement, vos emails transactionnels peuvent évoluer efficacement grâce à la fonctionnalité async/await de .NET, à l’ensemble de son infrastructure web haute performance, , aux outils supplémentaires de l’écosystème .NET, et à l’API HTTP performante et simple de Mailgun.

Cet article vous a-t-il été utile ? Inscrivez-vous à notre newsletter pour recevoir des mises à jour sur les tutoriels, l’actualité des emails et les conseils de nos experts en emailing.