Back to "Envoi de courriels HTML depuis ASP.NET Core avec FluentEmail"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

ASP.NET FluentEmail

Envoi de courriels HTML depuis ASP.NET Core avec FluentEmail

Wednesday, 07 August 2024

Il s'agit d'un article assez simple, mais qui couvrira une partie de l'utilisation Courriel fluide dans ASP.NET Core pour envoyer des courriels HTML Je n'ai pas vu ailleurs.

Le problème

Envoyer des mails HTML est lui-même assez simple avec SmtpClient, mais il n'est pas très flexible et ne supporte pas des choses comme des modèles ou des pièces jointes. FluentEmail est une excellente bibliothèque pour cela, mais il n'est pas toujours clair comment l'utiliser dans ASP.NET Core.

FluentEmail avec Razorlight (il est intégré) vous permet de modéliser vos e-mails en utilisant la syntaxe Razor. C'est génial car il vous permet d'utiliser toute la puissance de Razor pour créer vos e-mails.

La solution

Tout d'abord, vous devez installer le FluentEmail.Core, FluentEmail.Smtp & FluentEmail.

dotnet add package FluentEmail.Core
dotnet add package FluentEmail.Smtp
dotnet add package FluentEmail.Razor

Configuration FluentEmail

Pour garder les choses séparées, j'ai ensuite créé une extension IServiceCollection qui met en place les services FluentEmail :

namespace Mostlylucid.Email;

public static class Setup
{
    public static void SetupEmail(this IServiceCollection services, IConfiguration config)
    {
          var smtpSettings = services.ConfigurePOCO<SmtpSettings>(config.GetSection(SmtpSettings.Section));

        services.AddFluentEmail(smtpSettings.SenderEmail, smtpSettings.SenderName)
            .AddRazorRenderer();

        services.AddSingleton<ISender>(new SmtpSender( () => new SmtpClient()
        {
            DeliveryMethod = SmtpDeliveryMethod.Network,
            Host = smtpSettings.Server,
            Port = smtpSettings.Port,
            Credentials = new NetworkCredential(smtpSettings.Username, smtpSettings.Password),
            EnableSsl = smtpSettings.EnableSSL,
            UseDefaultCredentials = false
        }));
        services.AddSingleton<EmailService>();
        
    }

}

Paramètres ##SMTP

Comme vous le verrez, j'ai également utilisé la méthode IConfigSection mentionnée dans mon article précédent pour obtenir les paramètres SMTP.

  var smtpSettings = services.ConfigurePOCO<SmtpSettings>(config.GetSection(SmtpSettings.Section));

Cela vient du fichier appsettings.json:

"SmtpSettings":
  {
    "Server": "smtp.gmail.com",
    "Port": 587,
    "SenderName": "Mostlylucid",
    "Username": "",
    "SenderEmail": "[email protected]",
    "Password": "",
    "EnableSSL": "true",
    "EmailSendTry": 3,
    "EmailSendFailed": "true",
    "ToMail": "[email protected]",
    "EmailSubject": "Mostlylucid"
    
  }

GMAIL / Google SMTP

Note: Pour Google SMTP si vous utilisez MFA (que vous *Vraiment au cas où vous auriez besoin de faire un mot de passe de l'application pour votre compte.

Pour dev local, vous pouvez ajouter ceci à votre fichier secret.json :

secrets.png

Configuration de Docker

Pour l'utilisation de la composition de docker, vous l'incluez normalement dans un fichier.env :

SMTPSETTINGS_USERNAME="[email protected]"
SMTPSETTINGS_PASSWORD="<MFA PASSWORD>" -- this is the app password you created

Ensuite, dans le fichier de composition de docker, vous injectez ces variables sous forme de variables env :

services:
  mostlylucid:
    image: scottgal/mostlylucid:latest
    ports:
      - 8080:8080
    environment:
      - SmtpSettings__UserName=${SMTPSETTINGS_USERNAME}
      - SmtpSettings__Password=${SMTPSETTINGS_PASSWORD}

Prenez note de l'espacement car cela peut vraiment vous gâcher avec Docker composer. Pour vérifier ce qui est injecté vous pouvez utiliser

docker compose config

Pour vous montrer à quoi ressemble le fichier avec ces injectés.

Annoyances d'email fluide

Un problème avec Fluent Email est que vous devez ajouter ceci à votre csproj

  <PropertyGroup>
    <PreserveCompilationContext>true</PreserveCompilationContext>
  </PropertyGroup>

C'est parce que FluentEmail utilise RazorLight qui a besoin de cela pour fonctionner.

Pour les fichiers modèles, vous pouvez soit les inclure dans votre projet en tant que fichiers Contenu ou comme je le fais dans le conteneur Docker, copiez les fichiers à l'image finale

FROM build AS publish
RUN dotnet publish "Mostlylucid.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app

COPY --from=publish /app/publish .
# Copy the Markdown directory
COPY ./Mostlylucid/Markdown /app/Markdown
COPY ./Mostlylucid/Email/Templates /app/Email/Templates
# Switch to a non-root user
USER $APP_UID

Service de courrier électronique

Retournez au code!

Maintenant nous avons tout mis en place, nous pouvons ajouter le service d'email. Il s'agit d'un service simple qui prend un modèle et envoie un courriel:

public class EmailService(SmtpSettings smtpSettings, IFluentEmail fluentEmail)
{
    public async Task SendCommentEmail(string commenterEmail, string commenterName, string comment, string postSlug)
    {
        var commentModel = new CommentEmailModel
        {
            PostSlug = postSlug,
            SenderEmail = commenterEmail,
            SenderName = commenterName,
            Comment = comment
        };
        await SendCommentEmail(commentModel);
    }

    public async Task SendCommentEmail(CommentEmailModel commentModel)
    {
        // Load the template
        var templatePath = "Email/Templates/MailTemplate.template";
        await SendMail(commentModel, templatePath);
    }

    public async Task SendContactEmail(ContactEmailModel contactModel)
    {
        var templatePath = "Email/Templates/ContactEmailModel.template";

        await SendMail(contactModel, templatePath);
    }


    public async Task SendMail(BaseEmailModel model, string templatePath)
    {
        var template = await File.ReadAllTextAsync(templatePath);
        // Use FluentEmail to send the email
        var email = fluentEmail.UsingTemplate(template, model);
        await email.To(smtpSettings.ToMail)
            .SetFrom(smtpSettings.SenderEmail, smtpSettings.SenderName)
            .Subject("New Comment")
            .SendAsync();
    }
}

Comme vous pouvez le voir ici, nous avons deux méthodes, l'une pour les commentaires et l'autre pour le formulaire de contact (Envoyez-moi un courrier! )............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................. Dans cette application, je vous fais vous connecter afin que je puisse obtenir le courrier de (et pour éviter le spam).

La plupart du travail est fait ici :

 var template = await File.ReadAllTextAsync(templatePath);
        // Use FluentEmail to send the email
        var email = fluentEmail.UsingTemplate(template, model);
        await email.To(smtpSettings.ToMail)
            .SetFrom(smtpSettings.SenderEmail, smtpSettings.SenderName)
            .Subject("New Comment")
            .SendAsync();

Ici, nous ouvrons un fichier modèle, ajoutons le modèle contenant le contenu de l'email, chargeons-le dans FluentEmail puis envoyons-le. Le modèle est un simple fichier Razor:

@model Mostlylucid.Email.Models.ContactEmailModel

<!DOCTYPE html>
<html class="dark">
<head>
    <title>Comment Email</title>
</head>
<body>
<h1>Comment Email</h1>
<p>New comment from email @Model.SenderEmail name @Model.SenderName</p>

<p>Thank you for your comment on our blog post. We appreciate your feedback.</p>
<p>Here is your comment:</p>
<div>
    @Raw( @Model.Comment)</div>
<p>Thanks,</p>
<p>The Blog Team</p>

</body>
</html>

Ceux-ci sont stockés sous forme de fichiers.template dans le dossier Email/Templates. Vous pouvez utiliser des fichiers.cshtml mais cela cause un problème avec la balise @Raw dans le modèle (c'est une chose de rasoir).

Le Contrôleur

Enfin nous arrivons au contrôleur; c'est vraiment assez simple

    [HttpPost]
    [Route("submit")]
    [Authorize]
    public async Task<IActionResult> Submit(string comment)
    {
        var user = GetUserInfo();
            var commentHtml = commentService.ProcessComment(comment);
            var contactModel = new ContactEmailModel()
            {
                SenderEmail = user.email,
                SenderName =user.name,
                Comment = commentHtml,
            };
            await emailService.SendContactEmail(contactModel);
            return PartialView("_Response", new ContactViewModel(){Email = user.email, Name = user.name, Comment = commentHtml, Authenticated = user.loggedIn});

        return RedirectToAction("Index", "Home");
    }

Ici, nous obtenons l'information utilisateur, traitons le commentaire (j'utilise un simple processeur de balisage avec Markdig pour convertir balisage en HTML) puis envoyons l'e-mail.

logo

©2024 Scott Galloway