2009-05-20 190 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

相關問題