C # ile HTML e-posta gövdesi oluşturma


114

Aşağıdakileri yapmak için bir Stringbuilder kullanmaktan daha C # ile HTML e-posta oluşturmanın (System.Net.Mail yoluyla göndermek için) daha iyi bir yolu var mı?

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

vesaire vesaire?


Benim gördüğüm şekliyle gerçekten çözüme bağlı. Kullanıcı girişini almaktan ve farklı desenlerden otomatik olarak biçimlendirmekten her şeyi yaptım. HTML postalarıyla yaptığım en iyi çözüm, postanın girişini önceden bildiğimiz için aslında xml + xslt biçimlendirmesiydi.
14'te siber saldırıya uğradı

Bu, gereksinimlerinizin ne kadar karmaşık olduğuna bağlıdır. Bir zamanlar bir HTML e-postasında bir tablo oluşturan bir uygulamaya sahiptim ve bir tablo oluşturmak için HTML birleştirme dizelerini işlemek için bir ASP.NET Gridview kullandım.
RichardOD

Yanıtlar:


181

MailDefinition sınıfını kullanabilirsiniz .

Bunu nasıl kullanıyorsun:

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

Ayrıca, MailDefinition sınıfını kullanarak şablonları kullanarak C # içinde HTML e-posta gövdesinin nasıl oluşturulacağına dair bir blog yazısı yazdım .


11
Bunun var olduğunu bile bilmiyordum, katıksız dahice ... +1 ve Kabul Edildi
Rob

5
+1. Nice, sınırlı olmasına rağmen, muhtemelen birçok kullanımı kapsamaktadır. HTML bölümlerini programlı bir şekilde dahil etmek ve / veya oluşturulması gereken bir dizi öğe arasında döngü oluşturmak istiyorsanız o kadar kullanışlı değildir.
AnthonyWJones

Yakın zamanda bunun farkına vardım. Bu harika. Sanırım, herhangi bir problem için kendiniz bir sınıf yazmadan önce MSDN Dokümantasyonuna bakmanın ne kadar önemli olduğunu anlatıyor. MailDefinition ile neredeyse aynı şeyi yapan kendi sınıfımı yazmıştım. Benim için çok kötü. Zaman kaybı.
MartinHN

4
Kimden, kime, cc ve bcc alanlarını belirtmek için sınırlı seçeneklerden dolayı MailDefinition sınıfını kullanmaktan rahatsız oldum. Ayrıca, Web Kullanıcı Arayüzü kontrolleri için bir ad alanına dayanıyor - bu bana mantıklı gelmiyor. Aşağıdaki cevabımı görün ...
Seth

Bu sınıfın var olduğunu bilmediğim için +1, ancak temeldeki uygulama yalnızca değiştirmeler listesi üzerinde yineleme yapıyor ve Regex.Replace(body, pattern, replacement, RegexOptions.IgnoreCase);her anahtar / değer çifti için çalışıyor ... bu ayrıntı ışığında, bu sınıf yukarıda kullanıldığı gibi çok fazla değer sağlamıyor mevcut bir referansla çalışmadıkça System.Web.UI.Controls.
Chris Baxter

27

System.Web.UI.HtmlTextWriter sınıfını kullanın.

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

Stil niteliklerinin oluşturulmasını içeren kapsamlı HTML için HtmlTextWriter muhtemelen gitmenin en iyi yoludur. Bununla birlikte, kullanımı biraz hantal olabilir ve bazı geliştiriciler işaretlemenin kendisinin kolayca okunmasını sever, ancak htmlTextWriter'ın girinti ile ilgili seçimleri biraz gariptir.

Bu örnekte, XmlTextWriter'ı oldukça etkili bir şekilde de kullanabilirsiniz: -

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
Bu çok modası geçmiş görünüyor
Daniel

1
Bu benim için en iyi cevaptı. Basit ve isabetli (kuşkusuz oldukça hantal olmasına rağmen). MailDefinition şıktı, ama aradığım şey değildi.
thehelix

Merhaba, örneğin h1etikete satır içi stil nasıl eklenir ?
Izzy

E-posta açıldı kadar pop ne zaman u düzgün render nasıl son adımda yardım lütfen .can, bedeni, <25> olarak render benim bağlamda div etiketini kullanarak IAM
arıtıcılara

17

Güncellenmiş Cevap :

SmtpClientBu yanıtta kullanılan sınıfın dokümantasyonu artık 'Eski ("SmtpClient ve türleri ağı kötü tasarlanmış, https://github.com/jstedfast/MailKit ve https: // github kullanmanızı şiddetle tavsiye ediyoruz. .com / jstedfast / MimeKit yerine ") '.

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

Orijinal Cevap :

MailDefinition sınıfını kullanmak yanlış bir yaklaşımdır. Evet, kullanışlıdır, ancak aynı zamanda ilkeldir ve web kullanıcı arayüzü kontrollerine bağlıdır - bu, tipik olarak sunucu tarafı görevi olan bir şey için mantıklı değildir.

Aşağıda sunulan yaklaşım, MSDN belgelerine ve Qureshi'nin CodeProject.com'daki gönderisine dayanmaktadır .

NOT: Bu örnek, gömülü kaynaklardan HTML dosyasını, resimleri ve ekleri çıkarır, ancak bu öğeler için akışları almak için diğer alternatifleri kullanmak iyidir, örneğin, sabit kodlu dizeler, yerel dosyalar vb.

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
Lütfen sadece blog yazınızın bağlantısı olan bir yanıt göndermeyin. Blogunuz kaybolursa / kaybolursa, buradaki cevabınız oldukça işe yaramaz hale gelir. Buradaki yanıtınıza gönderinin "temel" bölümlerini eklemeyi düşünün.
Rob

1
Blog makalesi içeriği buraya taşındı. Teşekkürler @Rob.
Seth

1
FWIW bu kod test edilmiştir ve bir üretim uygulamasında kullanılmaktadır.
Seth

1
Bu biraz kafa karıştırıcı, çünkü diğer bazı kitaplıklarda HTML bir ek olarak gönderiliyor. Daha net hale getirmek için bu örnekten PDF eki bölümünü kaldırmanızı öneririm. Ayrıca, msg.Body bu örnek kodda asla ayarlanmamıştır, vücut değişkeninin atanması gerektiğini varsayıyorum?
Gudlaugur Egilsson

1
Msg.IsBodyHtml = true ayarını yapan önemli bir adım eksik. Bu yanıtı burada görün: stackoverflow.com/questions/7873155/…
Gudlaugur Egilsson

6

Tam olarak bu görev için dotLiquid kullanıyorum .

Bir şablon alır ve özel tanımlayıcıları anonim bir nesnenin içeriğiyle doldurur.

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

Ayrıca koleksiyonlarla da çalışır, bazı çevrimiçi örneklere bakın .


templateSource bir .html dosyası olabilir mi? veya daha iyisi bir .cshtml jilet dosyası mı?
ozzy432836

1
@Ozzy Aslında herhangi bir (metin) dosyası olabilir. DotLiquid şablon dosyanıza müdahale etmesi durumunda şablon sözdizimini değiştirmenize bile izin verir.
Marcel

5

Bir çeşit şablon kullanmanızı tavsiye ederim. Buna yaklaşmanın çeşitli farklı yolları vardır, ancak esasen bir E-posta şablonunu bir yerde tutun (diskte, bir veritabanında vb.) Ve basitçe anahtar verileri (IE: Alıcı adı vb.) Şablona ekleyin.

Bu çok daha esnektir, çünkü kodunuzu değiştirmek zorunda kalmadan şablonu gerektiği gibi değiştirebileceğiniz anlamına gelir. Tecrübelerime göre, son kullanıcılardan şablonlarda değişiklik talepleri alma olasılığınız yüksektir. Bütün işi bitirmek istiyorsanız, bir şablon düzenleyici ekleyebilirsiniz.


Kabul edildi, Tüm cevaplar hemen hemen aynı şeyi farklı yöntemler kullanarak yapıyor. String.Format ihtiyacınız olan tek şeydir ve bunlardan herhangi birini kullanarak kendi şablonunuzu oluşturabilirsiniz.
user1040975

4

MailDefinition'a alternatif olarak, RazorEngine https://github.com/Antaris/RazorEngine'e bir göz atın .

Bu daha iyi bir çözüm gibi görünüyor.

Attributted ...

e-posta şablonu c # ile nasıl e-posta gönderilir

Örneğin

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

Hangi çıktılar ...

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

Buraya Başlık

Sevgili Fred,

E-posta gövdesinin ilk bölümü buraya gelir


bu, döngüler ve ifs'e ihtiyaç duyulduğunda en fazla seçeneği verecektir
CMS

3

Biçimlendirme çok karmaşık olmadığı sürece, el yapımı html'yi bu şekilde yaymak muhtemelen en iyi yoldur. Stringbuilder, yalnızca yaklaşık üç birleştirme işleminden sonra verimlilik açısından size geri ödeme yapmaya başlar, bu nedenle gerçekten basit şeyler için string + string işe yarar.

Bunun dışında html kontrollerini (System.Web.UI.HtmlControls) kullanmaya başlayabilir ve bunları oluşturabilir, bu şekilde bazen onları miras alabilir ve karmaşık koşullu düzen için kendi sınıfınızı oluşturabilirsiniz.


1

Şu anda mevcut olan bazı şablon çerçevelerine bir göz atmak isteyebilirsiniz. Bazıları MVC'nin bir sonucu olarak spin off'lardır, ancak bu gerekli değildir. Kıvılcım iyidir.


Yalnızca bir Bilginize - yanıtınızdaki URL referansı artık alakalı değil; bir haber sitesine yönlendiriyor.
Geovani Martinez

1

Tam .NET Framework'e bağımlı olmak istemiyorsanız, kodunuzun şöyle görünmesini sağlayan bir kitaplık da vardır:

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

Açık kaynaktır, http://sourceforge.net/projects/htmlplusplus/ adresinden indirebilirsiniz.

Feragatname: Bu kitaplığın yazarıyım, aynı sorunu tam olarak çözmek için yazılmıştır - bir uygulamadan bir HTML e-postası gönderin.


1

Üretimde kullandığım ve kolay bakıma izin veren ticari bir sürüm LimiLabs Template Engine , 3+ yıldır kullanıyor ve metin şablonunda kodu güncellememe gerek kalmadan (sorumluluk reddi beyanları, bağlantılar vb.) Değişiklik yapmama izin veriyor - kadar basit olabilir

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

Benim yaptığım gibi bir göz atmaya değer; burada bahsedilen çeşitli cevapları denedikten sonra.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.