【问题标题】:Generating HTML email body in C#在 C# 中生成 HTML 电子邮件正文
【发布时间】:2010-10-27 13:38:41
【问题描述】:

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

等等,等等?

【问题讨论】:

  • 嗯,这真的取决于我所看到的解决方案。我已经完成了从获取用户输入和从不同模式自动格式化它的所有工作。我使用 html 邮件完成的最佳解决方案实际上是 xml+xslt 格式,因为我们预先知道邮件的输入。
  • 这取决于您的要求有多复杂。我曾经有一个应用程序在 HTML 电子邮件中呈现表格,而我使用 ASP.NET Gridview 来呈现 HTML 连接字符串以生成表格会很混乱。

标签: c# html email


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    归因于...

    how to send email wth email template 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>
    

    Heading Here

    尊敬的 Fred,

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

    【讨论】:

    • 当需要循环和 ifs 时,这将提供最多的选择
    【解决方案3】:

    更新答案

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

    【讨论】:

    • FWIW 此代码已经过测试,正在生产应用程序中使用。
    • 这看起来不对,附加带有 mediatype PDF 的 HTML? var file = new Attachment(fileStream, MediaTypeNames.Application.Pdf);
    • 您所指的示例部分演示了如何将 PDF 附加到电子邮件中。
    • 这有点令人困惑,因为在其他一些库中,HTML 是作为附件发送的。我建议从此示例中删除 PDF 附件部分以使其更清晰。此外,此示例代码中从未设置 msg.Body,我认为应该为其分配 body 变量?
    • 缺少关键步骤,设置 msg.IsBodyHtml=true。在此处查看此答案:stackoverflow.com/questions/7873155/…
    【解决方案4】:

    您可以使用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。不错,虽然有限,但可能涵盖了许多用途。如果您想以编程方式包含 HTML 部分和/或循环通过一组需要呈现的项目,则不是那么有用。
    • 我最近才意识到这一点。很酷。我想它告诉您在自己为任何问题编写课程之前查看 MSDN 文档是多么重要。我编写了自己的类,它的作用与 MailDefinition 几乎相同。对我来说太糟糕了。浪费时间。
    • 我对使用 MailDefinition 类感到不舒服,因为用于指定 from、to、cc 和 bcc 字段的选项有限。它还依赖于 Web UI 控件的命名空间——这对我来说没有意义。请参阅下面的答案...
    • +1 因为我不知道这个类存在,尽管底层实现只是简单地迭代替换列表并为每个键/值对运行Regex.Replace(body, pattern, replacement, RegexOptions.IgnoreCase); ...鉴于该细节,除非使用对 System.Web.UI.Controls 的现有引用,否则此类不会提供上述使用的太多价值。
    • 这比使用@$"&lt;div&gt;{someValue}&lt;/div&gt;" 有什么好处?我实际上认为您的代码比直接处理字符串的可读性差
    【解决方案5】:

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

    【讨论】:

    • templateSource 可以是.html 文件吗?还是更好的 .cshtml 剃须刀文件?
    • @Ozzy 实际上可以是任何(文本)文件。 DotLiquid 甚至允许更改模板语法,以防它干扰您的模板文件。
    【解决方案6】:

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

    【讨论】:

      【解决方案7】:

      您可能想看看目前可用的一些模板框架。其中一些是 MVC 的衍生产品,但这不是必需的。 Spark 不错。

      【讨论】:

      • 仅供参考 - 您回答中的网址参考不再相关;指向一个新闻网站。
      【解决方案8】:

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

      【讨论】:

      • 嗨,如何将内联样式添加到例如h1 标签?
      • 当电子邮件弹出窗口打开时,正文,iam 在我的上下文中使用 div 标记,它呈现为 。请您帮助最后一步如何进行正确的呈现
      【解决方案9】:

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

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

      【讨论】:

        【解决方案10】:

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

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

        【讨论】:

        • 同意,所有答案几乎都使用不同的方法做同样的事情。 String.Format 就是你所需要的,你可以使用其中任何一个来创建你自己的模板。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-15
        • 2013-04-08
        • 2018-10-22
        • 1970-01-01
        相关资源
        最近更新 更多