問題描述
有沒有更好的方法來生成 C#中的 HTML 電子郵件 (透過 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 class 。
這是你如何使用它:
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());
另外,我寫了一篇關於如何 generate HTML e-mail body in C# using templates using the MailDefinition class 的博文。
次佳解決方案
使用 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 的選擇與縮排是有點 wierd 。
在這個例子中,您還可以非常有效地使用 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 及其網路型別設計不佳,我們強烈建議您使用 https://github.com/jstedfast/MailKit 和 https://github.com/jstedfast/MimeKit「) 。
資料來源:https://www.infoq.com/news/2017/04/MailKit-MimeKit-Official
原始答案:
使用 MailDefinition 類是錯誤的方法。是的,它很方便,但它也是原始的,並且取決於 Web UI 控制元件 – 這對於通常是 server-side 任務的東西沒有意義。
下面介紹的方法是基於 MSDN 檔案和 Qureshi’s post on CodeProject.com 。
注意:此示例從嵌入式資源中提取 HTML 檔案,影像和附件,但使用其他替代方法獲取這些元素的流即可。 hard-coded 字串,本地檔案等。
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();
}
第四種方案
我會推薦使用某種模板。有各種不同的方法可以解決這個問題,但實質上是持有 Email 的一些模板 (在磁碟上,資料庫中等等),只需將金鑰資料 (IE:收件人名稱等) 插入到模板中即可。
這更靈活,因為這意味著您可以根據需要更改模板,而無需更改程式碼。根據我的經驗,您可能會收到終端使用者更改模板的請求。如果你想去整個豬,你可以包括一個模板編輯器。
第五種方案
只要標記不是太複雜,發出像這樣的手工製作的 HTML 可能是最好的方式。字串製造商只有在大約三個連線之後才開始付出代價,所以對於真正簡單的字串+字串將做的事情。
除此之外,您可以開始使用 html 控制元件 (System.Web.UI.HtmlControls) 並渲染它們,這樣您有時可以繼承它們,併為複雜的條件佈局制定自己的契約。
第六種方案
我使用 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 。
參考文獻
注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。