Menghasilkan badan email HTML di C #

114

Apakah ada cara yang lebih baik untuk menghasilkan email HTML di C # (untuk dikirim melalui System.Net.Mail), daripada menggunakan Stringbuilder untuk melakukan hal berikut:

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

dan sebagainya, dan lain sebagainya?

rampok
sumber
Yah, itu sangat tergantung pada solusinya seperti yang saya lihat. Saya telah melakukan segalanya mulai dari mengambil input pengguna dan memformatnya secara otomatis dari patters yang berbeda. Solusi terbaik yang telah saya lakukan dengan email html sebenarnya adalah pemformatan xml + xslt karena kami mengetahui masukan email di muka.
cyberzed
Itu tergantung seberapa kompleks kebutuhan Anda. Saya pernah memiliki aplikasi yang membuat tabel dalam email HTML dan saya menggunakan ASP.NET Gridview untuk membuat string gabungan HTML untuk menghasilkan tabel akan menjadi berantakan.
RichardOD

Jawaban:

181

Anda dapat menggunakan kelas MailDefinition .

Inilah cara Anda menggunakannya:

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

Selain itu, saya telah menulis posting blog tentang cara menghasilkan badan email HTML di C # menggunakan template menggunakan kelas MailDefinition .

MartinHN
sumber
11
Aku bahkan tidak tahu ini ada, benar-benar jenius ... +1 dan Diterima
Rob
5
+1. Bagus, meski terbatas, mungkin mencakup banyak kegunaan. Tidak begitu berguna jika Anda ingin secara terprogram menyertakan bagian HTML dan / atau memutar melalui sekumpulan item yang perlu dirender.
AnthonyWJones
Saya baru saja menyadarinya. Ini keren. Saya rasa ini memberi tahu Anda betapa pentingnya melihat Dokumentasi MSDN sebelum menulis kelas untuk masalah apa pun sendiri. Saya telah menulis kelas saya sendiri, yang hampir sama dengan MailDefinition. Sayang sekali bagiku. Buang-buang waktu.
MartinHN
4
Saya merasa tidak nyaman menggunakan kelas MailDefinition karena opsi terbatas untuk menentukan bidang dari, ke, cc, dan bcc. Itu juga bergantung pada namespace untuk kontrol UI Web - itu tidak masuk akal bagi saya. Lihat jawaban saya di bawah ...
Set
+1 karena saya tidak tahu kelas ini ada, meskipun implementasi yang mendasarinya hanya mengulangi daftar penggantian dan berjalan Regex.Replace(body, pattern, replacement, RegexOptions.IgnoreCase);untuk setiap pasangan kunci / nilai ... mengingat detail itu, kelas ini tidak memberikan banyak nilai seperti yang digunakan di atas kecuali bekerja dengan referensi yang ada ke System.Web.UI.Controls.
Chris Baxter
27

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

Untuk HTML ekstensif yang menyertakan pembuatan atribut gaya, HtmlTextWriter mungkin adalah cara terbaik untuk melakukannya. Namun ini bisa sedikit kikuk untuk digunakan dan beberapa pengembang menyukai markup itu sendiri agar mudah dibaca tetapi pilihan HtmlTextWriters yang menyimpang terkait indentasi agak aneh.

Dalam contoh ini Anda juga dapat menggunakan XmlTextWriter dengan cukup efektif: -

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();
AnthonyWJones
sumber
2
Ini sepertinya sangat kuno
Daniel
1
Ini adalah jawaban terbaik untukku. Sederhana dan langsung ke sasaran (meskipun memang cukup kikuk). MailDefinition memang bagus, tapi bukan yang saya cari.
thehelix
Hai, bagaimana cara menambahkan gaya sebaris, misalnya ke h1tag?
Izzy
ketika pop up email dibuka, body, saya menggunakan tag div dalam konteks saya itu dirender sebagai <25>. dapatkah Anda membantu dengan langkah terakhir cara membuat rendering yang tepat
clarifier
17

Jawaban yang Diperbarui :

Dokumentasi untuk SmtpClient, kelas yang digunakan dalam jawaban ini, sekarang berbunyi, 'Usang ("SmtpClient dan jenis jaringannya dirancang dengan buruk, kami sangat menyarankan Anda menggunakan https://github.com/jstedfast/MailKit dan https: // github .com / jstedfast / MimeKit sebagai gantinya ") '.

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

Jawaban Asli :

Menggunakan kelas MailDefinition adalah pendekatan yang salah. Ya, ini berguna, tetapi juga primitif dan bergantung pada kontrol UI web - itu tidak masuk akal untuk sesuatu yang biasanya merupakan tugas sisi server.

Pendekatan yang disajikan di bawah ini didasarkan pada dokumentasi MSDN dan posting Qureshi di CodeProject.com .

CATATAN: Contoh ini mengekstrak file HTML, gambar, dan lampiran dari sumber daya yang disematkan, tetapi menggunakan alternatif lain untuk mendapatkan aliran untuk elemen-elemen ini baik-baik saja, misalnya string berkode keras, file lokal, dan sebagainya.

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();
}
Seth
sumber
9
Harap jangan memposting jawaban yang pada dasarnya hanya link ke posting blog Anda. Jika / ketika blog Anda menghilang, jawaban Anda di sini menjadi sangat tidak berguna. Pertimbangkan untuk memasukkan bagian "kunci" dari pos ke dalam jawaban Anda di sini.
Rob
1
Konten artikel blog dipindahkan ke sini. Terima kasih, @Rob.
Seth
1
FWIW kode ini telah diuji dan digunakan dalam aplikasi produksi.
Seth
1
Ini agak membingungkan, karena di beberapa pustaka lain, HTML dikirim sebagai lampiran. Saya sarankan untuk menghapus bagian lampiran PDF dari contoh ini untuk membuatnya lebih jelas. Selain itu, msg.Body tidak pernah diatur dalam kode sampel ini, saya berasumsi itu harus diberi variabel body?
Gudlaugur Egilsson
1
Tidak ada langkah kunci, yang menyetel msg.IsBodyHtml = true. Lihat jawaban ini di sini: stackoverflow.com/questions/7873155/…
Gudlaugur Egilsson
6

Saya menggunakan dotLiquid untuk tugas ini.

Dibutuhkan templat, dan mengisi pengenal khusus dengan konten objek anonim.

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

Ini juga berfungsi dengan koleksi, lihat beberapa contoh online .

Marcel
sumber
dapatkah templateSource menjadi file .html? atau lebih baik lagi file silet .cshtml?
ozzy432836
1
@Ozzy Sebenarnya dapat berupa file (teks) apa saja. DotLiquid bahkan memungkinkan untuk mengubah sintaks template jika itu mengganggu file template Anda.
Marcel
5

Saya akan merekomendasikan menggunakan template atau semacamnya. Ada berbagai cara berbeda untuk melakukan pendekatan ini, tetapi pada dasarnya pegang template Email di suatu tempat (di disk, di database, dll.) Dan cukup masukkan data kunci (Yaitu: Nama penerima, dll.) Ke dalam template.

Ini jauh lebih fleksibel karena artinya Anda dapat mengubah template sesuai kebutuhan tanpa harus mengubah kode Anda. Dalam pengalaman saya, Anda cenderung mendapatkan permintaan untuk perubahan template dari pengguna akhir. Jika Anda ingin bekerja keras, Anda bisa menyertakan editor template.

Kulit
sumber
Setuju, Semua jawaban cukup banyak melakukan hal yang sama menggunakan metode yang berbeda. String.Format adalah semua yang Anda butuhkan dan Anda dapat menggunakan salah satu dari ini untuk membuat template Anda sendiri.
pengguna1040975
4

Sebagai alternatif dari MailDefinition, lihat RazorEngine https://github.com/Antaris/RazorEngine .

Sepertinya ini solusi yang lebih baik.

Diatribusikan ke ...

cara mengirim email dengan template email c #

Misalnya

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

Output mana ...

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

Menuju Sini

Fred terkasih,

Bagian pertama dari badan email ada di sini

Mick
sumber
ini akan memberikan opsi paling banyak ketika ada kebutuhan untuk loop & ifs
CMS
3

Memancarkan html buatan tangan seperti ini mungkin merupakan cara terbaik selama markup tidak terlalu rumit. Pembuat string hanya mulai membayar Anda kembali dalam hal efisiensi setelah sekitar tiga penggabungan, jadi untuk hal-hal yang sangat sederhana string + string akan dilakukan.

Selain itu, Anda dapat mulai menggunakan kontrol html (System.Web.UI.HtmlControls) dan merendernya, dengan begitu Anda terkadang dapat mewarisinya dan membuat clasess Anda sendiri untuk tata letak bersyarat yang kompleks.

Mark Dickinson
sumber
1

Anda mungkin ingin melihat beberapa kerangka kerangka yang tersedia saat ini. Beberapa dari mereka adalah spin off sebagai hasil dari MVC tetapi itu tidak diperlukan. Spark itu bagus.

Simon Farrow
sumber
Hanya referensi FYI - Url di jawaban Anda tidak lagi relevan; mengarah ke situs berita.
Geovani Martinez
1

Jika Anda tidak ingin ketergantungan pada .NET Framework penuh, ada juga pustaka yang membuat kode Anda terlihat seperti:

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

Ini open source, Anda dapat mendownloadnya dari http://sourceforge.net/projects/htmlplusplus/

Penafian: Saya adalah pembuat pustaka ini, ini ditulis untuk menyelesaikan masalah yang sama persis - mengirim email HTML dari aplikasi.

Vladislav Zorov
sumber
1

Versi komersial yang saya gunakan dalam produksi dan memungkinkan perawatan yang mudah adalah LimiLabs Template Engine , telah menggunakannya selama 3+ tahun dan memungkinkan saya untuk membuat perubahan pada template teks tanpa harus memperbarui kode (penafian, tautan, dll ..) - itu bisa sesederhana

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

Layak untuk dilihat, seperti yang saya lakukan; setelah mencoba berbagai jawaban yang disebutkan di sini.

Geovani Martinez
sumber