You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ASP.NET Core中结合MailKit使用Razor视图(cshtml)发送邮件

使用Razor视图生成ASP.NET Core动态邮件内容

我刚好有过用Razor视图生成动态邮件内容的实践经验,完全能解决你需要插入动态集合内容的问题,给你一步步拆解具体实现:

步骤1:定义邮件数据模型

首先创建对应邮件内容的模型类,把你需要的动态数据(比如商品项集合)都包含进去:

public class OrderEmailModel
{
    public string RecipientName { get; set; }
    public List<OrderItem> OrderItems { get; set; }
    // 可以添加其他字段,比如订单号、下单时间等
}

public class OrderItem
{
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
}

步骤2:创建Razor邮件模板

在你的项目里新建一个存放邮件模板的文件夹(比如Views/EmailTemplates),然后创建对应的cshtml视图文件,比如OrderConfirmation.cshtml,用Razor语法编写动态内容:

@model OrderEmailModel

<h2>Hi @Model.RecipientName,</h2>
<p>感谢你的订单!以下是你的商品明细:</p>

<table style="border-collapse: collapse; width: 100%;">
    <thead>
        <tr style="background-color: #f2f2f2;">
            <th style="border: 1px solid #ddd; padding: 8px;">商品名称</th>
            <th style="border: 1px solid #ddd; padding: 8px;">数量</th>
            <th style="border: 1px solid #ddd; padding: 8px;">单价</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.OrderItems)
        {
            <tr>
                <td style="border: 1px solid #ddd; padding: 8px;">@item.ProductName</td>
                <td style="border: 1px solid #ddd; padding: 8px; text-align: center;">@item.Quantity</td>
                <td style="border: 1px solid #ddd; padding: 8px; text-align: right;">@item.UnitPrice.ToString("C")</td>
            </tr>
        }
    </tbody>
</table>

<p>如有任何问题,请随时联系我们!</p>

注意:邮件HTML最好用内联样式,因为很多邮件客户端不支持外部样式表。

步骤3:实现Razor视图渲染服务

接下来需要一个服务来把Razor视图和模型转换成纯HTML字符串,我们可以利用ASP.NET Core内置的IRazorViewEngine来实现:

public interface IEmailTemplateRenderer
{
    Task<string> RenderTemplateAsync<TModel>(string viewPath, TModel model);
}

public class EmailTemplateRenderer : IEmailTemplateRenderer
{
    private readonly IRazorViewEngine _razorViewEngine;
    private readonly ITempDataProvider _tempDataProvider;
    private readonly IServiceProvider _serviceProvider;

    public EmailTemplateRenderer(IRazorViewEngine razorViewEngine,
                                 ITempDataProvider tempDataProvider,
                                 IServiceProvider serviceProvider)
    {
        _razorViewEngine = razorViewEngine;
        _tempDataProvider = tempDataProvider;
        _serviceProvider = serviceProvider;
    }

    public async Task<string> RenderTemplateAsync<TModel>(string viewPath, TModel model)
    {
        // 创建ActionContext用于视图渲染
        var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
        var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

        // 查找指定视图
        var viewResult = _razorViewEngine.FindView(actionContext, viewPath, isMainPage: false);
        if (!viewResult.Success)
        {
            throw new InvalidOperationException($"无法找到指定视图:{viewPath}");
        }

        // 准备ViewData和TempData
        var viewData = new ViewDataDictionary<TModel>(
            new EmptyModelMetadataProvider(), 
            new ModelStateDictionary())
        {
            Model = model
        };

        using var stringWriter = new StringWriter();
        var viewContext = new ViewContext(
            actionContext,
            viewResult.View,
            viewData,
            new TempDataDictionary(httpContext, _tempDataProvider),
            stringWriter,
            new HtmlHelperOptions());

        // 渲染视图到字符串
        await viewResult.View.RenderAsync(viewContext);
        return stringWriter.ToString();
    }
}

步骤4:注册渲染服务

在你的Program.cs(.NET 6+)或者Startup.cs里注册这个服务:

// .NET 6+ Program.cs
builder.Services.AddScoped<IEmailTemplateRenderer, EmailTemplateRenderer>();

步骤5:修改邮件发送代码

最后,在你的邮件发送逻辑里注入IEmailTemplateRenderer,用它来生成动态HTML内容:

// 假设这是你的邮件服务类
public class EmailService
{
    private readonly IEmailTemplateRenderer _templateRenderer;

    public EmailService(IEmailTemplateRenderer templateRenderer)
    {
        _templateRenderer = templateRenderer;
    }

    public async Task SendOrderEmailAsync()
    {
        // 构造模型数据(这里可以从数据库或业务逻辑获取真实数据)
        var emailModel = new OrderEmailModel
        {
            RecipientName = "Gurdip",
            OrderItems = new List<OrderItem>
            {
                new OrderItem { ProductName = "无线耳机", Quantity = 1, UnitPrice = 299.99m },
                new OrderItem { ProductName = "手机壳", Quantity = 2, UnitPrice = 29.99m }
            }
        };

        // 渲染Razor视图为HTML字符串
        var htmlBody = await _templateRenderer.RenderTemplateAsync("EmailTemplates/OrderConfirmation", emailModel);

        // 构建邮件内容
        var bodyBuilder = new BodyBuilder();
        bodyBuilder.HtmlBody = htmlBody;
        // 可以同时添加纯文本版本,提升兼容性
        bodyBuilder.TextBody = "你的邮件客户端不支持HTML内容,请查看附件或升级客户端。";

        var message = new MimeMessage();
        message.To.Add(new MailboxAddress("Gurdip", "gurdip.sira@gmail.com"));
        message.From.Add(new MailboxAddress("商城团队", "gurdip.sira@gmail.com"));
        message.Subject = "你的订单确认邮件";
        message.Body = bodyBuilder.ToMessageBody();

        // 发送邮件
        using var smtpClient = new MailKit.Net.Smtp.SmtpClient();
        await smtpClient.ConnectAsync("smtp.gmail.com", 587, MailKit.Security.SecureSocketOptions.StartTls);
        smtpClient.AuthenticationMechanisms.Remove("XOAUTH2");
        await smtpClient.AuthenticateAsync("gurdip.sira@gmail.com", "December5!");
        await smtpClient.SendAsync(message);
        await smtpClient.DisconnectAsync(true);
    }
}

一些额外提示

  • 视图路径注意:如果你的模板放在Views/Shared文件夹下,视图路径就用Shared/YourTemplateName;如果是自定义文件夹,确保路径和FindView方法的查找逻辑匹配。
  • Gmail SMTP注意:如果你的账号开启了两步验证,需要使用应用专用密码代替普通密码登录SMTP;如果没开两步验证,需要在Google账号设置里开启“不太安全的应用访问”(不过这个选项现在逐渐被淘汰了,还是推荐用应用密码)。
  • 模板复用:可以把通用的邮件头部、尾部抽成部分视图(Partial View),用@await Html.PartialAsync("_EmailHeader")来引用,提升模板复用性。

内容的提问来源于stack exchange,提问作者Bladerider1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:08:11