用 C # 生成 HTML 电子邮件主体

有没有更好的方法来生成 HTML 电子邮件在 C # (发送通过系统。网。邮件) ,而不是使用 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>");

等等,等等?

251074 次浏览

只要标记不太复杂,发出这样的手工构建的 html 可能是最好的方法。字符串构建器只在大约三次连接之后才开始回报效率,所以对于非常简单的事情 string + string 就可以了。

除此之外,您可以开始使用 html 控件(System。HtmlControls)并呈现它们,这样您有时可以继承它们并为复杂的条件布局创建自己的类。

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

你可以使用 MailDefinition 类

这就是你如何使用它:

MailDefinition md = new MailDefinition();
md.From = "test@domain.example";
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.example", replacements, body, new System.Web.UI.Control());

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

我建议使用某种类型的模板。有各种不同的方法来实现这一点,但本质上保持一个模板的电子邮件的某个地方(在磁盘上,在数据库等) ,并简单地插入关键数据(IE: 收件人的名称等)到模板。

This is far more flexible because it means you can alter the template as required without having to alter your code. In my experience your likely to get requests for changes to the templates from end users. If you want to go the whole hog you could include a template editor.

You might want to have a look at some of the template frameworks that are available at the moment. Some of them are spin offs as a result of MVC but that isn't required. Spark is a good one.

如果你不想要一个完整的依赖。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/下载

Disclaimer: I'm the author of this library, it was written to solve the same issue exactly - send an HTML email from an application.

更新答案 :

The documentation for SmtpClient, the class used in this answer, now reads, 'Obsolete("SmtpClient and its network of types are poorly designed, we strongly recommend you use https://github.com/jstedfast/MailKit and https://github.com/jstedfast/MimeKit instead")'.

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

原答案 :

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

下面介绍的方法基于 MSDN 文档和 库雷希在 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();
}

As an alternative to MailDefinition, have a look at RazorEngine https://github.com/Antaris/RazorEngine.

This looks like a better solution.

归功于..。

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

例如

using RazorEngine;
using RazorEngine.Templating;
using System;


namespace RazorEngineTest
{
class Program
{
static void Main(string[] args)
{
string template =
@"<h1>Heading Here</h1>
Dear @Model.UserName,
<br />
<p>First part of the email body goes here</p>";


const string templateKey = "tpl";


// Better to compile once
Engine.Razor.AddTemplate(templateKey, template);
Engine.Razor.Compile(templateKey);


// Run is quicker than compile and run
string output = Engine.Razor.Run(
templateKey,
model: new
{
UserName = "Fred"
});


Console.WriteLine(output);
}
}
}

输出..。

<h1>Heading Here</h1>
Dear Fred,
<br />
<p>First part of the email body goes here</p>

这里标题

亲爱的弗雷德,< br/> < p > 电子邮件的第一部分 尸体在这里

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

它还可以处理集合,请参阅 一些网上的例子

我在生产中使用的一个商业版本是 LimiLabs 模板引擎,它支持简单的维护,已经使用了3年多,允许我在不更新代码(免责声明,链接等)的情况下对文本模板进行修改可能就是这么简单

Contact templateData = ...;
string html = Template
.FromFile("template.txt")
.DataFrom(templateData )
.Render();

值得一看,就像我一样; 在尝试了这里提到的各种答案之后。