C#でのHTMLメール本文の生成


113

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

などなど?


まあ、それは私が見る限り、本当にソリューションに依存します。ユーザー入力を取得して、さまざまなパターンから自動的にフォーマットすることから、すべてを実行しました。メールの入力を前もって知っているので、私がHTMLメールで行った最良の解決策は、実際にはxml + xsltフォーマットでした。
サイバー化された2009年

それは、要件がどれだけ複雑かによって異なります。HTMLメールでテーブルをレンダリングするアプリケーションがあり、ASP.NETグリッドビューを使用してHTML連結文字列をレンダリングし、テーブルを生成するのは面倒でした。
RichardOD

回答:


180

MailDefinitionクラスを使用できます。

これはあなたがそれを使う方法です:

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

また、MailDefinitionクラスを使用したテンプレートを使用して、C#でHTML電子メールの本文生成する方法に関するブログ投稿を作成しました


11
私はこれが存在することさえ知りませんでした、それはまさに天才です... +1そして受け入れられました
Rob

5
+1。限定的ではありますが、おそらく多くの用途に対応できます。プログラムでHTMLのセクションを含めたり、レンダリングが必要な一連のアイテムをループしたりする場合は、あまり役に立ちません。
AnthonyWJones 2009年

つい最近気づきました。カッコイイです。自分で問題のクラスを作成する前に、MSDNドキュメントを確認することがいかに重要であるかがわかると思います。私はMailDefinitionとほとんど同じように自分のクラスを書きました。私にはあまりにも悪い。時間の無駄。
MartinHN、2009年

4
from、to、cc、およびbccフィールドを指定するためのオプションが限られているため、MailDefinitionクラスを使用することに不快でした。また、Web UIコントロールの名前空間に依存しています-それは私には意味がありません。以下の私の答えを参照してください...
セス

+1は、このクラスが存在することを知らなかったため、基になる実装は単に置換リストを反復し、Regex.Replace(body, pattern, replacement, RegexOptions.IgnoreCase);各キー/値のペアに対して実行しています...その詳細に照らして、このクラスは上記で使用されたほど多くの値を提供しませんへの既存の参照を使用しない限りSystem.Web.UI.Controls
Chris Baxter

27

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

2
これは時代遅れのようです
ダニエル

1
これは私にとって最良の答えでした。シンプルで要点があります(確かにかなり不格好ですが)。MailDefinitionは気の利いたものでしたが、私が探していたものではありませんでした。
thehelix

こんにちはh1。たとえば、タグにインラインスタイルを追加するにはどうすればよいですか。
イジー

メールのポップアップが開かれたとき、body、iamは私のコンテキストでdivタグを使用して<25>としてレンダリングしていました。適切なレンダリングを行う方法の最後のステップを手伝ってください
明確化

16

更新された回答

SmtpClientこの回答で使用されているクラスであるのドキュメントには、「Obsolete( "SmtpClient and its network of types are不完全に設計されています。https://github.com/jstedfast/MailKitおよびhttps:// githubを使用することを強くお勧めします.com / jstedfast / MimeKit代わりに ") '。

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

元の回答

MailDefinitionクラスを使用するのは間違ったアプローチです。はい、それは便利ですが、プリミティブであり、Web UIコントロールに依存します。これは通常、サーバー側のタスクであるものには意味がありません。

以下に示すアプローチは、MSDNのドキュメントとCodeProject.comでのQureshiの投稿に基づいています。

注:この例では、埋め込みリソースから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();
}

9
基本的にブログ投稿へのリンクにすぎない回答を投稿しないでください。もしあなたのブログが消えてしまったら、ここでの答えはほとんど役に立たなくなります。ここでの回答に投稿の「重要な」部分を組み込むことを検討してください。
Rob

1
ブログ記事のコンテンツをここに移動しました。ありがとう、@ Rob。
セス

1
FWIWこのコードはテストされており、本番アプリケーションで使用されています。
セス

1
他の一部のライブラリでは、HTMLが添付ファイルとして送信されるため、これは少し混乱します。わかりやすくするために、このサンプルからPDF添付ファイル部分を削除することをお勧めします。さらに、このサンプルコードではmsg.Bodyは設定されていません。body変数を割り当てる必要があると思いますか?
Gudlaugur Egilsson 2014

1
msg.IsBodyHtml = trueを設定する重要なステップがありません。こちらの回答をご覧ください:stackoverflow.com/questions/7873155/…–
Gudlaugur Egilsson 2014

6

私はまさにこのタスクに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));

コレクションでも機能しますいくつかのオンライン例をご覧ください。


templateSourceは.htmlファイルにすることができますか?またはより良い.cshtmlカミソリファイル?
ozzy432836

1
@Ozzy実際には任意の(テキスト)ファイルを使用できます。DotLiquidでは、テンプレートファイルに干渉する場合に備えて、テンプレートの構文を変更することもできます。
マルセル

5

ある種のテンプレートを使用することをお勧めします。これにはさまざまな方法がありますが、基本的にはメールのテンプレートをどこかに(ディスク上、データベースなど)保持し、キーデータ(IE:受信者名など)をテンプレートに挿入するだけです。

これは、コードを変更せずに必要に応じてテンプレートを変更できることを意味するため、はるかに柔軟です。私の経験では、エンドユーザーからテンプレートの変更要求を受け取る可能性があります。独り占めしたい場合は、テンプレートエディタを含めることができます。


同意します。すべての答えは、さまざまな方法を使用してほぼ同じことを行います。String.Formatが必要なすべてであり、これらのいずれかを使用して独自のテンプレートを作成できます。
user1040975

4

MailDefinitionの代わりに、RazorEngine https://github.com/Antaris/RazorEngineをご覧ください。

これはより良いソリューションのように見えます。

に起因する...

メールテンプレート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>

ここに向かって

親愛なるフレッド、

メール本文の最初の部分がここに入ります


これは、ループとifsが必要な場合に最も多くのオプションを提供します
CMS

3

マークアップがあまり複雑でない限り、このように手作りのhtmlを出力するのがおそらく最善の方法です。文字列ビルダーは、約3つの連結の後、効率の点であなたに返済し始めるだけなので、本当に単純なものでは文字列+文字列で十分です。

それ以外は、htmlコントロール(System.Web.UI.HtmlControls)の使用を開始してレンダリングできるため、それらを継承して、複雑な条件付きレイアウトの独自のクラスを作成することができます。


1

現時点で利用可能なテンプレートフレームワークのいくつかを確認したい場合があります。それらのいくつかはMVCの結果としてスピンオフされていますが、それは必須ではありません。Sparkは良いものです。


参考までに-あなたの答えのURL参照はもはや関係ありません。ニュースウェブサイトにアクセスします。
Geovani Martinez

1

完全な.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メールを送信します。


1

私が本番環境で使用し、メンテナンスが容易な商用バージョンはLimiLabsテンプレートエンジンで、3年以上使用しており、コード(免責事項、リンクなど)を更新することなくテキストテンプレートに変更を加えることができます。と同じくらい簡単かもしれません

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

私がしたように、見てみる価値があります。ここで述べた様々な答えを試みた後。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.