如何在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
相关产品推荐
相关产品推荐

