ASP.NET Core如何生成带动态内容的专业HTML订单邮件?
解决方案:还原邮件模板样式并动态生成订单内容
一、解决邮件样式丢失问题
邮件客户端(如Outlook、Gmail)对外部CSS、类选择器的支持非常有限,这是你使用BodyBuilder后样式与模板不符的核心原因。要还原模板效果,需做以下处理:
将模板CSS转为内联样式
原模板的CSS多为外部或嵌入式,必须把所有样式直接写入HTML元素的style属性中。比如原模板里的表格样式,要改成:<table style="width:100%;border-collapse:collapse;margin-bottom:20px;">可以手动转换,也可以通过代码批量处理(遍历HTML元素,将对应类的样式写入
style)。正确使用BodyBuilder嵌入样式
若坚持用BodyBuilder,不要引入外部CSS链接,直接将带内联样式的HTML写入HtmlContent,也可通过AddCssInline()添加全局嵌入式样式(内联样式优先级更高):var bodyBuilder = new BodyBuilder(); bodyBuilder.HtmlContent = @" <div style='max-width:600px;margin:0 auto;font-family:Arial,sans-serif;'> <!-- 带内联样式的模板内容 --> </div>";
二、动态生成多笔订单内容
推荐两种灵活的实现方式:
方法1:使用Razor模板(首选)
- 创建Razor视图文件(如
OrderEmailTemplate.cshtml),用Razor语法处理动态部分:@model OrderEmailModel <div style='max-width:600px;margin:0 auto;font-family:Arial,sans-serif;'> <h2 style='color:#2c3e50;'>你的订单已完成</h2> <table style='width:100%;border-collapse:collapse;margin-bottom:20px;'> <thead> <tr style='background:#f8f9fa;'> <th style='padding:10px;text-align:left;border-bottom:1px solid #ddd;'>商品</th> <th style='padding:10px;text-align:left;border-bottom:1px solid #ddd;'>数量</th> <th style='padding:10px;text-align:left;border-bottom:1px solid #ddd;'>单价</th> <th style='padding:10px;text-align:left;border-bottom:1px solid #ddd;'>小计</th> </tr> </thead> <tbody> @foreach(var item in Model.OrderItems) { <tr> <td style='padding:10px;border-bottom:1px solid #ddd;'>@item.ProductName</td> <td style='padding:10px;border-bottom:1px solid #ddd;'>@item.Quantity</td> <td style='padding:10px;border-bottom:1px solid #ddd;'>@item.Price.ToString("C")</td> <td style='padding:10px;border-bottom:1px solid #ddd;'>@(item.Quantity * item.Price).ToString("C")</td> </tr> } </tbody> </table> <div style='text-align:right;margin-top:20px;'> <p style='font-size:18px;font-weight:bold;'>总计:@Model.TotalAmount.ToString("C")</p> </div> </div> - 在代码中渲染模板为HTML字符串(可使用
RazorViewEngine或第三方库如RazorLight):// 构造订单数据模型 var model = new OrderEmailModel { OrderItems = new List<OrderItem> { new OrderItem { ProductName = "商品A", Quantity = 2, Price = 99.99m }, new OrderItem { ProductName = "商品B", Quantity = 1, Price = 199.99m } }, TotalAmount = 399.97m }; // 渲染模板得到HTML内容 var htmlContent = RenderRazorTemplate("OrderEmailTemplate.cshtml", model); // 发送邮件 await _emailSender.SendEmailAsync(customerEmail, "订单完成通知", htmlContent);
方法2:使用StringBuilder手动拼接
若不想依赖Razor,可通过StringBuilder循环生成订单行:
var sb = new StringBuilder(); // 写入模板头部(带内联样式) sb.Append(@" <div style='max-width:600px;margin:0 auto;font-family:Arial,sans-serif;'> <h2 style='color:#2c3e50;'>你的订单已完成</h2> <table style='width:100%;border-collapse:collapse;margin-bottom:20px;'> <thead> <tr style='background:#f8f9fa;'> <th style='padding:10px;text-align:left;border-bottom:1px solid #ddd;'>商品</th> <th style='padding:10px;text-align:left;border-bottom:1px solid #ddd;'>数量</th> <th style='padding:10px;text-align:left;border-bottom:1px solid #ddd;'>单价</th> <th style='padding:10px;text-align:left;border-bottom:1px solid #ddd;'>小计</th> </tr> </thead> <tbody>"); // 循环添加订单条目 foreach(var item in orderItems) { sb.AppendFormat(@" <tr> <td style='padding:10px;border-bottom:1px solid #ddd;'>{0}</td> <td style='padding:10px;border-bottom:1px solid #ddd;'>{1}</td> <td style='padding:10px;border-bottom:1px solid #ddd;'>{2:C}</td> <td style='padding:10px;border-bottom:1px solid #ddd;'>{3:C}</td> </tr>", item.ProductName, item.Quantity, item.Price, item.Quantity * item.Price); } // 写入模板尾部 sb.Append(@" </tbody> </table> <div style='text-align:right;margin-top:20px;'> <p style='font-size:18px;font-weight:bold;'>总计:{0:C}</p> </div> </div>", totalAmount); var htmlContent = sb.ToString(); await _emailSender.SendEmailAsync(customerEmail, "订单完成通知", htmlContent);
三、额外注意事项
- 测试邮件在主流客户端的显示效果,不同客户端对HTML/CSS支持存在差异。
- 避免使用复杂CSS选择器(如
:nth-child)、浮动布局,优先用表格布局(邮件客户端对表格支持最稳定)。 - 模板中的图片需使用绝对路径,不要用相对路径。
内容的提问来源于stack exchange,提问作者raysefo
相关产品推荐
相关产品推荐

