如何使用C#发送带有邮件模板的电子邮件

31

假设我需要向客户发送包含客户详细信息和订单详细信息的邮件。 我有一个包含客户数据和订单详细信息的模板html文件。我的html看起来像:

{{客户信息}} {{订单详情}}

<html>
<body>
Hi {FirstName} {LastName},

Here are your orders: 
{foreach Orders}
    Order ID {OrderID} Quantity : {Qty} <strong>{Price}</strong>. 
{end}

</body>
</html>

现在我想用实际值填充所有用{}括起来的关键字样本,并迭代并填充订单。

我在谷歌上搜索发现微软提供了一个称为 MailDefinition 的类,可以动态生成邮件正文。 我也找到了一个示例代码

MailDefinition md = new MailDefinition();
md.From = "test@domain.com";
md.IsBodyHtml = true;
md.Subject = "Test of MailDefinition";

ListDictionary replacements = new ListDictionary();
replacements.Add("<%Name%>", "Martin");
replacements.Add("<%Country%>", "Denmark");

string body = "
Hello <%Name%> You're from <%Country%>.";


MailMessage msg = md.CreateMailMessage("you@anywhere.com", replacements, body, new    System.Web.UI.Control());

通过上述代码,我们可以使用实际值替换伪值,但我不知道如何在订单详细信息中进行迭代并填充订单数据。

因此,如果可以使用MailDefinition类,则请指导我如何在循环中进行迭代并为订单详细信息生成正文的代码。


如果第三方库是一个选项,可以看看dotLiquid。您也可能想查看我对类似问题的答案:https://dev59.com/CXNA5IYBdhLWcg3wn_fD#28558160 - Marcel
我该如何下载MailDefinition - Kiquenet
MailDefinition是.NET的一部分,位于System.Web命名空间中。您无需下载它。 - Alan B
2个回答

50
作为 MailDefinition 的替代方案,可以看看 RazorEngine https://github.com/Antaris/RazorEngine
RazorEngine 是一个简化的模板框架,围绕 Microsoft 新的 Razor 解析引擎构建,用于 ASP.NET MVC3 和 Web Pages。RazorEngine 提供了一个包装器和额外的服务,围绕解析引擎构建,以允许在其他项目类型中使用解析技术。
它允许您在 ASP.NET MVC 之外使用 razor 模板,然后编写像这样的代码(未经测试):
string template =
@"<html>
<body>
Hi @Model.FirstName @Model.LastName,

Here are your orders: 
@foreach(var order in Model.Orders) {
    Order ID @order.Id Quantity : @order.Qty <strong>@order.Price</strong>. 
}

</body>
</html>";

var model = new OrderModel {
    FirstName = "Martin",
    LastName = "Whatever",
    Orders = new [] {
        new Order { Id = 1, Qty = 5, Price = 29.99 },
        new Order { Id = 2, Qty = 1, Price = 9.99 }
    }
};

string mailBody = Razor.Parse(template, model);

谢谢您的帮助,但我正在使用ASP.NET WebForm而不是MVC。我希望代码以一种可以通过C#在Windows应用程序中运行的方式编写。 - Thomas
1
真的很好,简单的解决方案!这是我审查过的10个方案中最好的一个。我稍微扩展了一下,创建了实际的csthml模板文件。最棒的是,即使它们在一个简单的类库中,Visual Studio仍然将它们识别为cshtml,并且我可以获得完整的Razor语法支持! - Tim
1
我喜欢这个。但是我的模板作者已经习惯了 KnockOut 模板。是否有任何 Knockout 服务器端 API 可用于模板? - Ravi
1
我发现在foreach循环中由于糟糕的razor语法而引发了异常。为了解决这个问题,您需要在文本块中添加文本(显然)以便在循环内部使用。因此,此示例应如下所示: @foreach(var order in Model.Orders) { <text>订单ID </text>@order.Id <text>数量: </text>@order.Qty <strong>@order.Price</strong><text>。</text> } - Pnctovski

1

使用默认的替换功能无法处理这样“复杂”的逻辑(占位符处理仅用于简单变量,例如名称或值)。

您必须自己进行解析。根据复杂程度(例如循环内部的循环),这可能会有点棘手。

如果您不想要或不需要这些东西,那么它就更加琐碎。例如,使用正则表达式\{foreach (.*?)\}(.*?)\{end\}查找此类循环,然后以所需的方式解析内容/匹配组。完成此部分后,您可以替换其他值或使用默认的替换功能。

这种方法的唯一缺点是您必须为每个收件人重新创建邮件(即不能使用MailDefinition进行群发邮件)。


我只是不明白如何处理循环。你说:“如果你不想要或不需要这些东西,那就更简单了。例如,使用正则表达式{foreach (.?)}(.?){end}来查找这样的循环,然后以所需的方式解析内容/匹配组。完成这部分后,您可以替换其他值或使用默认替换功能。”能否请您给我展示一下如何在小样本代码中操作?谢谢。 - Thomas
可以在这里找到有关正则表达式及其如何使用查找模式的简短介绍:http://support.microsoft.com/kb/308252/en-us 如果正则表达式匹配成功,您就会知道存在一个循环。捕获组将包含要迭代的对象/组作为字符串(在您的示例中为“Orders”),以及用于每个订单的格式字符串(“Order ID {OrderId}...”)。如果您不熟悉正则表达式,则使用完整/预制解决方案(如David建议的)可能是更好的选择。如果需要,稍后可以尝试编写一个简短的示例。 - Mario

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接