Tạo nội dung email HTML trong C #


114

Có cách nào tốt hơn để tạo email HTML trong C # (để gửi qua System.Net.Mail), hơn là sử dụng Stringbuilder để thực hiện như sau:

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

Vân vân và vân vân?


Vâng, nó thực sự phụ thuộc vào giải pháp như tôi thấy. Tôi đã làm mọi thứ từ việc lấy thông tin đầu vào của người dùng và định dạng nó một cách tự động từ những người sáng tạo khác nhau. Giải pháp tốt nhất mà tôi đã thực hiện với thư html thực sự là định dạng xml + xslt vì chúng tôi biết đầu vào của thư từ trước.
trực tuyến hóa

Điều đó phụ thuộc vào mức độ phức tạp của yêu cầu của bạn. Tôi đã từng có một ứng dụng hiển thị một bảng trong email HTML và tôi đã sử dụng ASP.NET Gridview để hiển thị các chuỗi liên kết HTML để tạo một bảng sẽ rất lộn xộn.
RichardOD

Câu trả lời:


181

Bạn có thể sử dụng lớp MailDefinition .

Đây là cách bạn sử dụng nó:

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

Ngoài ra, tôi đã viết một bài đăng trên blog về cách tạo nội dung e-mail HTML trong C # bằng cách sử dụng các mẫu sử dụng lớp MailDefinition .


11
Tôi thậm chí còn không biết điều này tồn tại, nó là thiên tài tuyệt đối ... +1 và được chấp nhận
Rob

5
+1. Đẹp, mặc dù hạn chế, có lẽ bao gồm nhiều mục đích sử dụng. Không quá hữu ích nếu bạn muốn lập trình bao gồm các phần của HTML và / hoặc lặp qua một tập hợp các mục cần hiển thị.
AnthonyWJones

Tôi mới biết đến nó gần đây. Nó là mát mẻ. Tôi đoán nó cho bạn biết tầm quan trọng của việc xem Tài liệu MSDN trước khi tự viết một lớp cho bất kỳ vấn đề nào. Tôi đã viết lớp của riêng mình, nó gần giống như MailDefinition. Quá tệ đối với tôi. Mất thời gian.
MartinHN

4
Tôi không thoải mái khi sử dụng lớp MailDefinition vì các tùy chọn hạn chế để chỉ định các trường from, to, cc và bcc. Nó cũng dựa trên một không gian tên cho các điều khiển giao diện người dùng Web - điều đó không hợp lý với tôi. Xem câu trả lời của tôi bên dưới ...
Seth

+1 vì tôi không biết lớp này tồn tại, mặc dù việc triển khai cơ bản chỉ đơn giản là lặp lại danh sách thay thế và chạy Regex.Replace(body, pattern, replacement, RegexOptions.IgnoreCase);cho từng cặp khóa / giá trị ... về mặt chi tiết đó, lớp này không cung cấp nhiều giá trị như được sử dụng ở trên trừ khi làm việc với một tham chiếu hiện có tới System.Web.UI.Controls.
Chris Baxter

27

Sử dụng lớp 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();

Đối với HTML mở rộng bao gồm việc tạo các thuộc tính kiểu, HtmlTextWriter có lẽ là cách tốt nhất. Tuy nhiên, nó có thể hơi rắc rối khi sử dụng và một số nhà phát triển thích bản thân đánh dấu để dễ đọc nhưng các lựa chọn của HtmlTextWriter liên quan đến thụt lề hơi khó hiểu.

Trong ví dụ này, bạn cũng có thể sử dụng XmlTextWriter khá hiệu quả: -

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
Điều này có vẻ siêu cổ xưa
Daniel

1
Đây là câu trả lời tốt nhất cho tôi. Đơn giản và đến mức (mặc dù phải thừa nhận là khá lắt léo). MailDefinition rất tiện lợi, nhưng không phải là thứ tôi đang tìm kiếm.
thehelix

Xin chào, làm cách nào để thêm kiểu nội tuyến vào ví dụ như h1thẻ?
Izzy

khi cửa sổ bật lên của email được mở ra, phần nội dung, tôi đang sử dụng thẻ div trong ngữ cảnh của tôi, nó đang hiển thị dưới dạng <25>. Bạn có thể vui lòng giúp đỡ bước cuối cùng cách tạo kết xuất thích hợp không
clarifier

17

Cập nhật câu trả lời :

Tài liệu cho SmtpClientlớp được sử dụng trong câu trả lời này hiện có nội dung là 'Đã lỗi thời ("SmtpClient và các loại mạng của nó được thiết kế kém, chúng tôi thực sự khuyên bạn nên sử dụng https://github.com/jstedfast/MailKithttps: // github .com / jstedfast / MimeKit thay vào đó ") '.

Nguồn: https://www.infoq.com/news/2017/04/MailKit-MimeKit-Official

Câu trả lời gốc :

Sử dụng lớp MailDefinition là cách tiếp cận sai. Vâng, nó tiện dụng, nhưng nó cũng nguyên thủy và phụ thuộc vào các điều khiển giao diện người dùng web - điều đó không có ý nghĩa đối với một thứ thường là tác vụ phía máy chủ.

Cách tiếp cận được trình bày dưới đây dựa trên tài liệu MSDN và bài đăng của Qureshi trên CodeProject.com .

LƯU Ý: Ví dụ này trích xuất tệp HTML, hình ảnh và tệp đính kèm từ các tài nguyên được nhúng, nhưng sử dụng các lựa chọn thay thế khác để lấy luồng cho các phần tử này là tốt, ví dụ: chuỗi mã hóa cứng, tệp cục bộ, v.v.

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

9
Vui lòng không đăng câu trả lời về cơ bản chỉ là một liên kết đến bài đăng trên blog của bạn. Nếu / khi blog của bạn biến mất, câu trả lời của bạn ở đây sẽ trở nên vô dụng. Cân nhắc kết hợp các phần "chính" của bài đăng vào câu trả lời của bạn tại đây.
Rob

1
Đã chuyển nội dung bài viết trên blog đến đây. Cảm ơn, @Rob.
Seth

1
FWIW mã này đã được thử nghiệm và đang được sử dụng trong một ứng dụng sản xuất.
Seth

1
Điều này hơi khó hiểu vì trong một số thư viện khác, HTML được gửi dưới dạng tệp đính kèm. Tôi khuyên bạn nên xóa phần đính kèm PDF khỏi mẫu này để làm rõ ràng hơn. Hơn nữa, msg.Body không bao giờ được đặt trong mã mẫu này, tôi cho rằng nó nên được gán cho biến body?
Gudlaugur Egilsson

1
Thiếu một bước quan trọng, cài đặt msg.IsBodyHtml = true. Xem câu trả lời này tại đây: stackoverflow.com/questions/7873155/…
Gudlaugur Egilsson,

6

Tôi sử dụng dotLiquid cho chính xác nhiệm vụ này.

Nó có một khuôn mẫu và điền các số nhận dạng đặc biệt với nội dung của một đối tượng ẩn danh.

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

Nó cũng hoạt động với các bộ sưu tập, hãy xem một số ví dụ trực tuyến .


templateSource có thể là tệp .html không? hoặc tốt hơn là một tệp dao cạo .cshtml?
ozzy432836

1
@Ozzy Nó thực sự có thể là bất kỳ tệp (văn bản) nào. DotLiquid thậm chí còn cho phép thay đổi cú pháp mẫu trong trường hợp nó can thiệp vào tệp mẫu của bạn.
Marcel

5

Tôi khuyên bạn nên sử dụng các mẫu của một số loại. Có nhiều cách khác nhau để tiếp cận điều này nhưng về cơ bản, giữ một mẫu Email ở đâu đó (trên đĩa, trong cơ sở dữ liệu, v.v.) và chỉ cần chèn dữ liệu chính (IE: Tên người nhận, v.v.) vào mẫu.

Điều này linh hoạt hơn nhiều vì nó có nghĩa là bạn có thể thay đổi mẫu theo yêu cầu mà không cần phải thay đổi mã của mình. Theo kinh nghiệm của tôi, bạn có thể nhận được yêu cầu thay đổi các mẫu từ người dùng cuối. Nếu bạn muốn đi toàn bộ con lợn, bạn có thể bao gồm một trình chỉnh sửa mẫu.


Đồng ý, Tất cả các câu trả lời khá giống nhau bằng cách sử dụng các phương pháp khác nhau. String.Format là tất cả những gì bạn cần và bạn có thể sử dụng bất kỳ cái nào trong số này để tạo mẫu của riêng bạn.
user1040975

4

Để thay thế cho MailDefinition, hãy xem RazorEngine https://github.com/Antaris/RazorEngine .

Đây có vẻ là một giải pháp tốt hơn.

Được gán cho ...

cách gửi email với mẫu email c #

Ví dụ

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

Đầu ra nào ...

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

Hướng tới đây

Fred thân mến,

Phần đầu tiên của nội dung email ở đây


điều này sẽ cung cấp nhiều tùy chọn nhất khi có nhu cầu về vòng lặp & ifs
CMS

3

Phát ra html dựng sẵn như thế này có lẽ là cách tốt nhất miễn là việc đánh dấu không quá phức tạp. Trình tạo chuỗi chỉ bắt đầu trả lại cho bạn về mặt hiệu quả sau khoảng ba lần nối, vì vậy đối với những thứ thực sự đơn giản thì chuỗi + chuỗi sẽ làm được.

Ngoài ra, bạn có thể bắt đầu sử dụng các điều khiển html (System.Web.UI.HtmlControls) và hiển thị chúng, theo cách đó, đôi khi bạn có thể kế thừa chúng và tạo ra sự chắc chắn cho bố cục có điều kiện phức tạp.


1

Bạn có thể muốn xem một số khuôn khổ mẫu hiện có sẵn. Một số trong số chúng là spin off do MVC nhưng điều đó không bắt buộc. Tia lửa là một trong những tốt.


Chỉ là tham chiếu FYI - Url trong câu trả lời của bạn không còn phù hợp nữa; dẫn đến một trang web tin tức.
Geovani Martinez

1

Nếu bạn không muốn phụ thuộc vào .NET Framework đầy đủ, thì cũng có một thư viện làm cho mã của bạn trông giống như sau:

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

Nó là mã nguồn mở, bạn có thể tải xuống từ http://sourceforge.net/projects/htmlplusplus/

Tuyên bố từ chối trách nhiệm: Tôi là tác giả của thư viện này, nó được viết để giải quyết chính xác vấn đề tương tự - gửi email HTML từ một ứng dụng.


1

Một phiên bản thương mại mà tôi sử dụng trong sản xuất và cho phép bảo trì dễ dàng là LimiLabs Template Engine , đã sử dụng nó hơn 3 năm và cho phép tôi thực hiện các thay đổi đối với mẫu văn bản mà không cần phải cập nhật mã (tuyên bố từ chối trách nhiệm, liên kết, v.v.) - nó có thể đơn giản như

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

Đáng để xem, giống như tôi đã làm; sau khi thử các câu trả lời khác nhau được đề cập ở đây.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.