本文主要介绍ASP.NET Core中,使用FluentEmail来通过Razor语法及cshtml模板生成HTML格式邮件内容,以及发送邮件的方法及示例代码。

1、安装引用FluentEmail方法

参照文档.NET Core(ASP.NET Core)使用FluentEmail发送邮件方法及示例代码

2、Startup.cs中ConfigureServices(IServiceCollection services)中配置

// 配置 IFluentEmail
services.AddFluentEmail(Configuration["email_address"])
.AddRazorRenderer()
.AddSmtpSender(new SmtpClient("smtp.gmail.com", 587)
{
    Credentials = new NetworkCredential(Configuration["email_address"], Configuration["email_password"]),
    EnableSsl = true
});
// 添加 service
services.TryAddScoped<IEmailSender, EmailSender>();

配置示例中使用GMAIL帐户发送电子邮件,可以使用所需的任何电子邮件服务器。

3、使用FluentEmail发送邮件示例代码

//通过模板发送邮件的接口
public interface IEmailSender
{
    Task<bool> SendUsingTemplate(string to, string subject, EmailTemplate template, object model);
}
//邮件模板
public enum EmailTemplate
{
    EmailConfirmation,
    ChangeEmail
}
public class EmailSender : IEmailSender
{
   //需要更改的是TemplatePath常量,该常量需要包含模板文件(.cshtml文件)所在的完整命名空间名称。
    private const string TemplatePath = "Web.Api.Infrastructure.Services.Emails.Templates.{0}.cshtml";
    private readonly IFluentEmail _email;
    private readonly ILogger<EmailSender> _logger;
    public EmailSender(IFluentEmail email, ILogger<EmailSender> logger)
    {
        _email = email;
        _logger = logger;
    }
    public async Task<bool> SendUsingTemplate(string to, string subject, EmailTemplate template, object model)
    {
        var result = await _email.To(to)
            .Subject(subject)
            .UsingTemplateFromEmbedded(string.Format(TemplatePath, template), ToExpando(model), GetType().Assembly)
            .SendAsync();
        if (!result.Successful)
        {
            _logger.LogError("Failed to send an email.\n{Errors}", string.Join(Environment.NewLine, result.ErrorMessages));
        }
        return result.Successful;
    }
}

注意:在模板中使用匿名对象,我们需要将其转换为Expando objects。这是RazorLight(FluentEmail用于处理Razor模板的库)所具有的“限制” 。

private static ExpandoObject ToExpando(object model)
{
    if (model is ExpandoObject exp)
    {
        return exp;
    }
    IDictionary<string, object> expando = new ExpandoObject();
    foreach (var propertyDescriptor in model.GetType().GetTypeInfo().GetProperties())
    {
        var obj = propertyDescriptor.GetValue(model);
        if (obj != null && IsAnonymousType(obj.GetType()))
        {
            obj = ToExpando(obj);
        }
        expando.Add(propertyDescriptor.Name, obj);
    }
    return (ExpandoObject)expando;
}
private static bool IsAnonymousType(Type type)
{
    bool hasCompilerGeneratedAttribute = type.GetTypeInfo()
        .GetCustomAttributes(typeof(CompilerGeneratedAttribute), false)
        .Any();
    bool nameContainsAnonymousType = type.FullName.Contains("AnonymousType");
    bool isAnonymousType = hasCompilerGeneratedAttribute && nameContainsAnonymousType;
    return isAnonymousType;
}

3、嵌入cshtml模板

上面代码引用cshtml模板需要嵌入资源,要cshtml模板打包在程序集中,在cshtml模板文件中属性窗口:"生成操作" =》选择 "嵌入的资源"

相关文档:

ASP.NET Core中使用SmtpClient发送邮件的方法代码

.NET Core 2.0中使用gmail发送电子邮件