2009-05-20 138 views
91

是否有更好的方法来生成在C#中的HTML电子邮件(用于通过System.Net.Mail发送),比使用一个StringBuilder做到以下几点:生成HTML电子邮件正文

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>"); 

等等等?

回答

152

可以使用MailDefinition class

这是你如何使用它:

MailDefinition md = new MailDefinition(); 
md.From = "[email protected]"; 
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("[email protected]", replacements, body, new System.Web.UI.Control()); 

另外,我写了关于如何generate HTML e-mail body in C# using templates using the MailDefinition class博客文章。

3

像这样发布手工制作的html可能是最好的方法,只要标记不是太复杂。在大约三次连接之后,stringbuilder只会在效率方面给你回报,所以对于非常简单的东西string + string将会这样做。

除此之外,您可以开始使用html控件(System.Web.UI.HtmlControls)并呈现它们,这种方式有时可以继承它们并为复杂的条件布局制作自己的分支。

21

使用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(); 

对于包含创建样式属性的大量HTML,HtmlTextWriter可能是最好的方法。然而,使用它可能有点笨重,一些像标记本身一样易于阅读的开发人员,但是对于缩进来说,HtmlTextWriter的选择有些奇怪。

在这个例子中,你也可以非常高效地使用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(); 
+2

这看起来超级陈旧 – Daniel 2013-04-22 15:24:52

+0

这对我来说是最好的答案。简单和重点(虽然承认非常笨重)。 MailDefinition非常漂亮,但不是我想要的。 – thehelix 2015-09-16 19:28:59

+0

走出你的洞穴男人的欢呼声! – tobias 2016-03-23 08:51:22

4

我会推荐使用某种模板。有很多不同的方法可以解决这个问题,但本质上将电子邮件的模板保存在某个位置(在磁盘上,在数据库等中),并将关键数据(IE:收件人名称等)插入到模板中。

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

0

嗯,它真的取决于我所看到的解决方案。我已经做了一切,从抓住用户输入和格式化从不同的模式自动。我用HTML邮件完成的最好的解决方案实际上是xml + xslt格式化,因为我们知道邮件的预先输入。

0

这取决于您的要求有多复杂。我曾经有一个应用程序在HTML电子邮件中呈现了一个表格,并且我使用了ASP.NET Gridview来呈现HTML连接的字符串来生成一个表格会很麻烦。

0

cyberzed - 我在过去使用过类似的方法(XML + XSLT),也有很好的效果。这提供了很大的灵活性,并且意味着您的代码不必关心本电子邮件所需的确切数据(生成包含所有相关信息的XML文档,并让XSLT挑选出它想要的位)。我想说的是,我发现XSLT有点让人头疼,但是一旦我经历了最初的奇怪事情,我就没事了。

1

您可能想看看目前可用的一些模板框架。其中一些是MVC的结果,但这不是必需的。 Spark是一个不错的选择。

0

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

1

如果你不想在完整的.NET框架的依赖性做,有也使您的代码看起来像一个图书馆:

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电子邮件。

14

更新答

SmtpClient的文件,在这个答案中使用的类,现在读,“过时的(“SmtpClient和其类型的网络设计不当,我们强烈建议您使用https://github.com/jstedfast/MailKithttps://github.com/jstedfast/MimeKit代替”)'。

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

原来的答案

使用MailDefinition类是错误的做法。是的,它很方便,但它也很原始,并且依赖于Web UI控件 - 这对于通常是服务器端任务的东西没有意义。

下面介绍的方法基于MSDN文档和Qureshi's post on CodeProject.com

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

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(); 
} 
4

我用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)); 

它也适用于收藏品,请参阅some online examples

相关问题