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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/886728/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 08:26:43  来源:igfitidea点击:

Generating HTML email body in C#

c#htmlemail

提问by Rob

Is there a better way to generate HTML email in C# (for sending via System.Net.Mail), than using a Stringbuilder to do the following:

与使用 Stringbuilder 执行以下操作相比,是否有更好的方法在 C# 中生成 HTML 电子邮件(用于通过 System.Net.Mail 发送):

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

and so on, and so forth?

等等等等?

采纳答案by MartinHN

You can use the MailDefinition class.

您可以使用MailDefinition 类

This is how you use it:

这是你如何使用它:

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

Also, I've written a blog post on how to generate HTML e-mail body in C# using templates using the MailDefinition class.

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

回答by Mark Dickinson

Emitting handbuilt html like this is probably the best way so long as the markup isn't too complicated. The stringbuilder only starts to pay you back in terms of efficiency after about three concatenations, so for really simple stuff string + string will do.

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

Other than that you can start to use the html controls (System.Web.UI.HtmlControls) and render them, that way you can sometimes inherit them and make your own clasess for complex conditional layout.

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

回答by AnthonyWJones

Use the System.Web.UI.HtmlTextWriter 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();

For extensive HTML that includes the creation of style attributes HtmlTextWriter is probably the best way to go. However it can be a bit clunky to use and some developers like the markup itself to be easily read but perversly HtmlTextWriter's choices with regard indentation is a bit wierd.

对于包括创建样式属性的大量 HTML,HtmlTextWriter 可能是最好的方法。然而,它使用起来可能有点笨拙,一些开发人员喜欢标记本身易于阅读,但 HtmlTextWriter 在缩进方面的选择有点奇怪。

In this example you can also use XmlTextWriter quite effectively:-

在此示例中,您还可以非常有效地使用 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();

回答by Leather

I would recomend using templates of some sort. There are various different ways to approach this but essentially hold a template of the Email some where (on disk, in a database etc) and simply insert the key data (IE: Recipients name etc) into the template.

我建议使用某种模板。有各种不同的方法来解决这个问题,但本质上是在某个地方(在磁盘上,在数据库中等)保存电子邮件的模板,然后简单地将关键数据(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.

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

回答by Simon Farrow

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. Sparkis a good one.

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

回答by Vladislav Zorov

If you don't want a dependency on the full .NET Framework, there's also a library that makes your code look like:

如果你不想依赖完整的 .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();

It's open source, you can download it from http://sourceforge.net/projects/htmlplusplus/

它是开源的,你可以从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.

免责声明:我是这个库的作者,它是为了解决同样的问题而编写的 - 从应用程序发送 HTML 电子邮件。

回答by Seth

Updated Answer:

更新答案

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/MailKitand https://github.com/jstedfast/MimeKitinstead")'.

的文档SmtpClient,这个答案中使用的类,现在读到,'Obsolete("SmtpClient 及其类型的网络设计不佳,我们强烈建议您使用https://github.com/jstedfast/MailKithttps://github .com/jstedfast/MimeKit代替")'。

Source: https://www.infoq.com/news/2017/04/MailKit-MimeKit-Official

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

Original Answer:

原答案

Using the MailDefinition class is the wrong approach. Yes, it's handy, but it's also primitive and depends on web UI controls--that doesn't make sense for something that is typically a server-side task.

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

The approach presented below is based on MSDN documentation and Qureshi's post on CodeProject.com.

下面介绍的方法基于 MSDN 文档和Qureshi 在 CodeProject.com 上的帖子

NOTE: This example extracts the HTML file, images, and attachments from embedded resources, but using other alternatives to get streams for these elements are fine, e.g. hard-coded strings, local files, and so on.

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

回答by Mick

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

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

This looks like a better solution.

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

Attributted to...

归因于...

how to send email wth email template c#

如何使用电子邮件模板发送电子邮件 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);
        }
    }
}

Which outputs...

哪个输出...

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

Heading Here

Dear Fred,

First part of the email body goes here

前往这里

亲爱的弗雷德,

电子邮件正文的第一部分在这里

回答by Marcel

I use dotLiquidfor exactly this task.

我使用dotLiquid来完成这个任务。

It takes a template, and fills special identifiers with the content of an anonymous object.

它需要一个模板,并用匿名对象的内容填充特殊标识符。

//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));

It also works with collections, see some online examples.

它也适用于集合,请参阅一些在线示例