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

时间:2009-05-20 08:07:27

标签: c# html email

是否有更好的方法在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>");

依此类推,等等?

11 个答案:

答案 0 :(得分:174)

您可以使用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的博客文章。

答案 1 :(得分:25)

使用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 :(得分:15)

更新了答案

本答案中使用的SmtpClient类的文档现在显示为'过时(“SmtpClient及其类型网络设计不佳,我们强烈建议您使用https://github.com/jstedfast/MailKit和{{3而不是“)”。

来源:https://github.com/jstedfast/MimeKit

原始答案

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

下面介绍的方法基于MSDN文档和https://www.infoq.com/news/2017/04/MailKit-MimeKit-Official

注意:此示例从嵌入资源中提取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();
}

答案 3 :(得分:4)

我建议使用某种模板。有各种不同的方法可以解决这个问题,但实质上是将电子邮件模板放在一些位置(在磁盘上,在数据库中等)并简单地将关键数据(IE:收件人名称等)插入到模板中。

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

答案 4 :(得分: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

答案 5 :(得分:3)

只要标记不太复杂,发送这样的手工构建的html可能是最好的方法。在大约三个连接之后,stringbuilder只会在效率方面开始回报,所以对于非常简单的东西,string + string会做。

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

答案 6 :(得分:3)

作为MailDefinition的替代方案,请查看RazorEngine https://github.com/Antaris/RazorEngine

这看起来是一个更好的解决方案。

归于......

how to send email wth email template c#

E.g

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>
  

走到这里

亲爱的弗雷德,

电子邮件的第一部分   身体到这里

答案 7 :(得分:2)

您可能希望了解一下目前可用的一些模板框架。其中一些是MVC的结果,但这不是必需的。 Spark是一个很好的。

答案 8 :(得分:1)

如果您不希望依赖完整的.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电子邮件。

答案 9 :(得分:1)

我在生产中使用并易于维护的商业版本是LimiLabs Template Engine,使用了3年以上,使我无需更新代码即可更改文本模板(免责声明,链接等) ..)-可能很简单

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

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

答案 10 :(得分:0)

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