Создание тела электронной почты HTML в С#

Есть ли лучший способ генерировать HTML-адрес электронной почты в С# (для отправки через System.Net.Mail), чем использовать Stringbuilder для выполнения следующих действий:

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

и т.д. и т.д.?

Ответ 1

Вы можете использовать класс MailDefinition.

Вот как вы его используете:

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

Кроме того, я написал сообщение в блоге о том, как создать тело электронной почты HTML в С# с использованием шаблонов, используя класс MailDefinition.

Ответ 2

Используйте класс 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();

Ответ 3

Обновленный ответ:

Документация для SmtpClient, класса, используемого в этом ответе, теперь читается: "Устаревший (" SmtpClient и его сеть типов плохо разработаны, мы настоятельно рекомендуем использовать https://github.com/jstedfast/MailKit и https://github.com/jstedfast/MimeKit вместо") '.

Источник: https://www.infoq.com/news/2017/04/MailKit-MimeKit-Official

Оригинальный ответ:

Использование класса MailDefinition - неправильный подход. Да, это удобно, но оно также примитивно и зависит от элементов управления веб-интерфейса - это не имеет смысла для чего-то, что обычно является задачей на стороне сервера.

Представленный ниже подход основан на документации MSDN и пост Qureshi на CodeProject.com.

ПРИМЕЧАНИЕ. В этом примере извлекается 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();
}

Ответ 4

Я бы рекомендовал использовать какие-то шаблоны. Существуют различные способы подхода к этому, но по существу содержат шаблон электронной почты, где (на диске, в базе данных и т.д.) И просто вставляйте ключевые данные (IE: имя получателей и т.д.) В шаблон.

Это намного более гибко, потому что это означает, что вы можете изменять шаблон по мере необходимости, не изменяя свой код. По моему опыту, вы можете получить запросы об изменениях в шаблонах от конечных пользователей. Если вы хотите пройти весь свиньи, вы можете включить редактор шаблонов.

Ответ 5

Я использую 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));

Он также работает с коллекциями, см. несколько онлайн-примеров.

Ответ 6

Испускать ручной html, как это, вероятно, лучший способ, пока разметка не слишком сложна. Строковый строитель только начинает возвращать вас с точки зрения эффективности после примерно трех конкатенаций, поэтому для действительно простых строк строка + строка будет делать.

Кроме того, вы можете начать использовать элементы управления html (System.Web.UI.HtmlControls) и визуализировать их, таким образом, вы можете иногда наследовать их и создавать свою собственную класификацию для сложного условного макета.

Ответ 7

Возможно, вам захочется взглянуть на некоторые рамки шаблонов, доступные на данный момент. Некоторые из них являются побочными эффектами в результате MVC, но это не требуется. Spark является хорошим.

Ответ 8

Если вам не нужна зависимость от полной .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-письмо из приложения.

Ответ 10

Ну, это действительно зависит от решения, как я его вижу. Я сделал все, чтобы автоматически захватывать пользовательский ввод и форматировать его из разных паттернов. Лучшее решение, которое я сделал с html-письмами, было фактически форматированием xml + xslt, так как мы знали ввод почты вверх.

Ответ 11

Это зависит от того, насколько сложны ваши требования. У меня когда-то было приложение, которое отображало таблицу в HTML-письме, и я использовал Gridview ASP.NET для визуализации строк конкатенации HTML для генерации таблицы, было бы грязно.

Ответ 12

cyberzed - я использовал аналогичный подход в прошлом (XML + XSLT) с хорошими результатами. Это обеспечивает большую гибкость и означает, что код не должен касаться точных данных, которые требуются электронной почтой (создайте XML-документ, содержащий всю необходимую информацию, и пусть XSLT выбирает бит, который он хочет.

Единственное, что я бы сказал, это то, что я обнаружил, что XSLT немного болит в головной боли, но я был в порядке, когда я прошел мимо первоначальной нечетности.

Ответ 13

Существует аналогичный вопрос fooobar.com/info/22472/..., в котором содержатся довольно полные ответы. Лично я использую NVelocity в качестве механизма шаблона, ранее пытавшегося использовать механизм ASP.Net для генерации html-содержимого электронной почты. NVelocity намного проще использовать, сохраняя при этом гибкость. Я обнаружил, что использование ASP.Net.aspx файлов для шаблонов работало, но имело некоторые непредвиденные побочные эффекты.