在C#中生成HTML电子邮件正文

有没有更好的方式来生成HTML电子邮件在C#(通过System.Net.Mail发送),比使用Stringbuilder来执行以下操作:

string userName = "John Doe"; StringBuilder mailBody = new StringBuilder(); mailBody.AppendFormat("<h1>Heading Here</h1>"); mailBody.AppendFormat("Dear {0}," userName); mailBody.AppendFormat("<br />"); mailBody.AppendFormat("<p>First part of the email body goes here</p>"); 

等等等等?

您可以使用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 = "<div>Hello {name} You're from {country}.</div>"; MailMessage msg = md.CreateMailMessage("you@anywhere.com", replacements, body, new System.Web.UI.Control()); 

另外,我写了一篇关于如何使用MailDefinition类使用模板在C#中生成HTML电子邮件正文的博文 。

使用System.Web.UI.HtmlTextWriter类。

 StringWriter writer = new StringWriter(); HtmlTextWriter html = new HtmlTextWriter(writer); html.RenderBeginTag(HtmlTextWriterTag.H1); html.WriteEncodedText("Heading Here"); html.RenderEndTag(); html.WriteEncodedText(String.Format("Dear {0}", userName)); html.WriteBreak(); html.RenderBeginTag(HtmlTextWriterTag.P); html.WriteEncodedText("First part of the email body goes here"); html.RenderEndTag(); html.Flush(); string htmlString = writer.ToString(); 

对于包含创build样式属性的大量HTML,HtmlTextWriter可能是最好的方法。 然而,使用起来可能有些笨重,有些开发人员喜欢这个标记本身,但是对于缩进来说,HtmlTextWriter的select有点奇怪。

在这个例子中,你也可以非常有效地使用XmlTextWriter: –

 writer = new StringWriter(); XmlTextWriter xml = new XmlTextWriter(writer); xml.Formatting = Formatting.Indented; xml.WriteElementString("h1", "Heading Here"); xml.WriteString(String.Format("Dear {0}", userName)); xml.WriteStartElement("br"); xml.WriteEndElement(); xml.WriteElementString("p", "First part of the email body goes here"); xml.Flush(); 

已更新答案

SmtpClient (这个答案中使用的类)的文档现在读取为“Obsolete(”SmtpClient及其networkingtypesdevise不佳,我们强烈build议您使用https://github.com/jstedfast/MailKit和https::// github.com/jstedfast/MimeKit改为“)”。

来源: https : //www.infoq.com/news/2017/04/MailKit-MimeKit-Official

原始答案

使用MailDefinition类是错误的方法。 是的,这很方便,但它也是原始的,取决于Web UI控件 – 对于通常是服务器端任务的东西来说,这是没有意义的。

下面介绍的方法基于MSDN文档和Qureshi在CodeProject.com上的文章 。

注意:本示例从embedded式资源中提取HTML文件,图像和附件,但是使用其他替代方法来获取这些元素的stream是很好的,例如硬编码的string,本地文件等等。

 Stream htmlStream = null; Stream imageStream = null; Stream fileStream = null; try {    // Create the message.    var from = new MailAddress(FROM_EMAIL, FROM_NAME);    var to = new MailAddress(TO_EMAIL, TO_NAME);    var msg = new MailMessage(from, to);    msg.Subject = SUBJECT;    msg.SubjectEncoding = Encoding.UTF8;    // Get the HTML from an embedded resource.    var assembly = Assembly.GetExecutingAssembly();    htmlStream = assembly.GetManifestResourceStream(HTML_RESOURCE_PATH);    // Perform replacements on the HTML file (if you're using it as a template).    var reader = new StreamReader(htmlStream);    var body = reader        .ReadToEnd()        .Replace("%TEMPLATE_TOKEN1%", TOKEN1_VALUE)        .Replace("%TEMPLATE_TOKEN2%", TOKEN2_VALUE); // and so on...    // Create an alternate view and add it to the email.    var altView = AlternateView.CreateAlternateViewFromString(body, null, MediaTypeNames.Text.Html);    msg.AlternateViews.Add(altView);    // Get the image from an embedded resource. The <img> tag in the HTML is:    //    <img src="pid:IMAGE.PNG">    imageStream = assembly.GetManifestResourceStream(IMAGE_RESOURCE_PATH);    var linkedImage = new LinkedResource(imageStream, "image/png");    linkedImage.ContentId = "IMAGE.PNG";    altView.LinkedResources.Add(linkedImage);    // Get the attachment from an embedded resource.    fileStream = assembly.GetManifestResourceStream(FILE_RESOURCE_PATH);    var file = new Attachment(fileStream, MediaTypeNames.Application.Pdf);    file.Name = "FILE.PDF";    msg.Attachments.Add(file);    // Send the email    var client = new SmtpClient(...);    client.Credentials = new NetworkCredential(...);    client.Send(msg); } finally {    if (fileStream != null) fileStream.Dispose();    if (imageStream != null) imageStream.Dispose();    if (htmlStream != null) htmlStream.Dispose(); } 

我会推荐使用某种模板。 有很多不同的方式来处理这个,但本质上持有电子邮件的一些模板(在磁盘上,在数据库等),只需将关键数据(IE:收件人名称等)插入模板。

这更加灵活,因为这意味着您可以根据需要更改模板,而无需更改代码。 根据我的经验,您可能会收到最终用户对模板进行更改的请求。 如果你想整个猪,你可以包括一个模板编辑器。

我使用dotLiquid来完成这个任务。

它采用一个模板,并用匿名对象的内容填充特殊的标识符。

 //define template String templateSource = "<h1>{{Heading}}</h1>Dear {{UserName}},<br/><p>First part of the email body goes here"); Template bodyTemplate = Template.Parse(templateSource); // Parses and compiles the template source //Create DTO for the renderer var bodyDto = new { Heading = "Heading Here", UserName = userName }; String bodyText = bodyTemplate.Render(Hash.FromAnonymousObject(bodyDto)); 

它也适用于collections,看一些在线的例子 。

像这样发布手工制作的HTML可能是最好的方法,只要标记不是太复杂。 stringbuilder只会在三次连接之后开始回报效率,所以对于真正简单的东西string + string会做。

除此之外,您可以开始使用html控件(System.Web.UI.HtmlControls)并呈现它们,这样,您有时可以inheritance它们并对复杂的条件布局进行自己的设置。

您可能想看看目前可用的一些模板框架。 其中一些是MVC的结果,但这不是必需的。 星火是一个很好的。

如果您不希望依赖于完整的.NET Framework,那么还有一个库使您的代码如下所示:

 string userName = "John Doe"; var mailBody = new HTML { new H(1) { "Heading Here" }, new P { string.Format("Dear {0},", userName), new Br() }, new P { "First part of the email body goes here" } }; string htmlString = mailBody.Render(); 

它是开源的,你可以从http://sourceforge.net/projects/htmlplusplus/下载;

免责声明:我是这个库的作者,它的写作是为了解决同样的问题 – 从应用程序发送HTML电子邮件。

作为MailDefinition的替代方法,请看RazorEngine https://razorengine.codeplex.com/

这看起来更好的解决scheme。

归属于…

如何发送邮件电子邮件模板c#

那么,这真的取决于我所看到的解决scheme。 我已经做了一切,从抓住用户input,并从不同的模式自动格式化。 我用HTML邮件做的最好的解决scheme实际上是xml + xslt格式化,因为我们知道邮件的input。

networking化 – 过去我使用过类似的方法(XML + XSLT),效果也不错。 这提供了很大的灵活性,并且意味着你的代码不必关心这个Email需要的确切数据(生成一个包含所有相关信息的XML文档,并让XSLT挑出它想要的位。

我唯一要说的是我发现XSLT有点让人头痛,但是一旦我经历了最初的奇怪之后,我就没事了。

这取决于你的要求有多复杂。 我曾经有一个应用程序在HTML电子邮件中呈现了一个表格,并且我使用ASP.NET Gridview来呈现HTML连接的string来生成一个表格会是一团糟。

有类似的StackOverflow问题 ,包含一些相当全面的回应。 就我个人而言,我使用NVelocity作为以前尝试使用ASP.Net引擎生成html电子邮件内容的模板引擎。 NVelocity使用起来简单多了,同时还提供了大量的灵活性。 我发现使用ASP.Net .aspx文件模板工作,但有一些意想不到的副作用。