Могу ли я настроить шаблоны HTML/электронной почты с помощью ASP.NET?


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

Если я вставляю HTML внутри строковых литералов C#, это уродливо, и им придется беспокоиться о побеге. В том числе плоские файлы для верхнего и нижнего колонтитулов могут работать, но что-то в этом просто не так.

что было бы идеально, что бы использовать а .ASPX страница как шаблон каким-то образом, а затем просто скажите мой код, чтобы служить этой странице, и использовать HTML, возвращенный для электронной почты.

есть хороший и простой способ сделать это? Есть ли лучший способ решить эту проблему?

обновление:
Я добавил ответ, который позволяет вам использовать стандарт .aspx в качестве шаблона электронной почты. Просто замените все переменные, как обычно, используйте привязку данных и т. д. Затем просто захватите вывод страницы, и вуаля! У вас есть ваш HTML-адрес электронной почты!

ОБНОВЛЕНО С ОГОВОРКОЙ!!!:
Я использовал класс MailDefinition на некоторых страницах aspx просто отлично, но при попытке использовать этот класс во время запущенного серверного процесса это не удалось. Я считаю, что это было потому, что определение Почты.Метод CreateMailMessage () требует, чтобы действительный элемент управления ссылался, даже если он не всегда что-то делает. Из-за этого я бы рекомендовал свой подход с использованием страницы aspx или Mun подход с использованием страницы ascx, которая кажется немного лучше.

23 93

23 ответа:

здесь уже есть тонна ответов, но я наткнулся на отличную статью о том, как использовать Razor с шаблоном электронной почты. Бритву толкнули с помощью ASP.NET MVC 3, но MVC не требуется использовать бритву. Это довольно гладкая обработка делать шаблоны электронной почты

Как указано в статье, " лучшая вещь Razor заключается в том, что в отличие от своего предшественника(webforms) он не связан с веб-средой, мы можем легко разместить его вне сети и использовать его в качестве шаблонного движка для различных цель. "

генерация HTML-писем с помощью RazorEngine-часть 01-введение

использование шаблонов бритвы за пределами ASP.NET: они больше не только для HTML!

умные шаблоны электронной почты в ASP.NET с RazorEngine

подобный Stackoverflow QA

создание шаблонов с использованием нового API RazorEngine

Использование бритвы без MVC

можно ли использовать Razor View Engine снаружи asp.net

вы также можете попробовать загрузить элемент управления, а затем отобразить его в строку и установить это как тело HTML:

// Declare stringbuilder to render control to
StringBuilder sb = new StringBuilder();

// Load the control
UserControl ctrl = (UserControl) LoadControl("~/Controls/UserControl.ascx");

// Do stuff with ctrl here

// Render the control into the stringbuilder
StringWriter sw = new StringWriter(sb);
Html32TextWriter htw = new Html32TextWriter(sw);
ctrl.RenderControl(htw);

// Get full body text
string body = sb.ToString();

затем вы можете построить свою электронную почту как обычно:

MailMessage message = new MailMessage();
message.From = new MailAddress("from@email.com", "from name");
message.Subject = "Email Subject";
message.Body = body;
message.BodyEncoding = Encoding.ASCII;
message.IsBodyHtml = true;

SmtpClient smtp = new SmtpClient("server");
smtp.Send(message);

пользовательский элемент управления может содержать другие элементы управления, такие как верхний и Нижний колонтитулы, а также использовать такие функциональные возможности, как привязка данных.

вы можете попробовать класс MailDefinition

Если вы хотите передать параметры, такие как имена пользователей, названия продуктов, ... так далее. вы можете использовать open source template engine NVelocity чтобы создать свой окончательный адрес электронной почты / HTML.

пример шаблона NVelocity (MailTemplate.vm):

A sample email template by <b>$name</b>.
<br />

Foreach example :
<br />    
#foreach ($item in $itemList)

[Date: $item.Date] Name: $item.Name, Value: $itemValue.Value
<br /><br />

#end

создание тела почты по MailTemplate.ВМ в приложении :

VelocityContext context = new VelocityContext();
context.Put("name", "ScarletGarden");
context.Put("itemList", itemList);

StringWriter writer = new StringWriter();

Velocity.MergeTemplate("MailTemplate.vm", context, writer);

string mailBody = writer.GetStringBuilder().ToString();

результат тело почты:

образец шаблона электронной почты по ScarletGarden.

пример для каждого:

[Дата: 12.02.2009] Наименование: Пункт 1, Ценность: 09

[Дата: 21.02.2009] Наименование: Пункт 4, Стоимость: 52

[Дата: 01.03.2009] Наименование: Пункт 2, Стоимость: 21

[Дата: 23.03.2009] Наименование: Пункт 6, Стоимость: 24

для редактирования шаблонов, возможно, вы можете использовать FCKEditor и сохраните ваши шаблоны в файлы.

Почта.компонент электронной почты dll включает в себя механизм шаблонов электронной почты:

вот обзор синтаксис:

<html>
<body>
Hi {FirstName} {LastName},

Here are your orders: 
{foreach Orders}
    Order '{Name}' sent to <strong>{Street}</strong>. 
{end}

</body>
</html>

и код, который загружает шаблон, заполняет данные из объекта c# и отправляет электронное письмо:

Mail.Html(Template
              .FromFile("template.txt")
              .DataFrom(_contact)
              .Render())
    .Text("This is text version of the message.")
    .From(new MailBox("alice@mail.com", "Alice"))
    .To(new MailBox("bob@mail.com", "Bob"))
    .Subject("Your order")
    .UsingNewSmtp()
    .WithCredentials("alice@mail.com", "password")
    .Server("mail.com")
    .WithSSL()
    .Send();

вы можете получить дополнительную информацию о email template engine сообщение в блоге.

скачать Почта.компонент электронной почты dll и дать ему попробовать.

обратите внимание, что это коммерческий продукт Я создал.

Если гибкость является одним из ваших предварительных условий, XSLT может быть хорошим выбором, который полностью поддерживается .NET framework, и вы сможете даже позволить пользователю редактировать эти файлы. Эта статья (http://www.aspfree.com/c/a/XML/XSL-Transformations-using-ASP-NET/) может быть полезно для начала (msdn имеет больше информации об этом). Как сказал ScarletGarden NVelocity-еще один хороший выбор, но я предпочитаю XSLT для его "встроенной" поддержки и платформы .NET framework агностический.

конечно, вы можете создать шаблон html, и я бы рекомендовал также текстовый шаблон. В шаблоне вы можете просто поместить [BODY] в то место, где будет размещено тело, а затем вы можете просто прочитать в шаблоне и заменить тело новым содержимым. Вы можете отправить использование электронной почты .Сети Класса Почты. Вам просто нужно выполнить цикл отправки электронной почты всем получателям после первоначального создания электронной почты. Сработало как заклинание для меня.

using System.Net.Mail;

// Email content
string HTMLTemplatePath = @"path";
string TextTemplatePath = @"path";
string HTMLBody = "";
string TextBody = "";

HTMLBody = File.ReadAllText(HTMLTemplatePath);
TextBody = File.ReadAllText(TextTemplatePath);

HTMLBody = HTMLBody.Replace(["[BODY]", content);
TextBody = HTMLBody.Replace(["[BODY]", content);

// Create email code
MailMessage m = new MailMessage();

m.From = new MailAddress("address@gmail.com", "display name");
m.To.Add("address@gmail.com");
m.Subject = "subject";

AlternateView plain = AlternateView.CreateAlternateViewFromString(_EmailBody + text, new System.Net.Mime.ContentType("text/plain"));
AlternateView html = AlternateView.CreateAlternateViewFromString(_EmailBody + body, new System.Net.Mime.ContentType("text/html"));
mail.AlternateViews.Add(plain);
mail.AlternateViews.Add(html);

SmtpClient smtp = new SmtpClient("server");
smtp.Send(m);

Я думаю, что вы могли бы сделать что-то вроде этого:

создать и .aspx-страница и поместите ее в конец метода OnLoad или вызовите его вручную.

    StringBuilder sb = new StringBuilder();
    StringWriter sw = new StringWriter(sb);
    HtmlTextWriter htmlTW = new HtmlTextWriter(sw);
    this.Render(htmlTW);

Я не уверен, есть ли какие-либо потенциальные проблемы с этим, но похоже, что это сработает. Таким образом, вы можете использовать полнофункциональный .aspx-страница, а не класс MailDefinition, который поддерживает только текстовые замены.

вот еще одна альтернатива, которая использует преобразования XSL для более сложных шаблонов электронной почты: отправка электронной почты на основе HTML из приложений .NET.

будьте осторожны при этом, спам-фильтры, кажется, блокировать ASP.net сгенерированный html, по-видимому, из-за ViewState, поэтому, если вы собираетесь это сделать, убедитесь, что созданный Html чист.

Я лично бы посмотрел на использование Asp.net MVC для достижения желаемых результатов. или NVelocity довольно хорошо в этом

что было бы идеально, что бы использовать a .ASPX-страница как шаблон каким-то образом, а затем просто скажите мой код, чтобы служить этой странице, и используйте HTML, возвращенный для электронной почты.

вы можете легко построить WebRequest, чтобы попасть на страницу ASPX и получить результирующий HTML. С немного больше работы, вы, вероятно, можете сделать это без WebRequest. PageParser и ответ.Фильтр позволит вам запустить страницу и захватить выходные...хотя там могут быть некоторые более элегантный способ.

У меня было аналогичное требование на 1 из проектов, где вы должны были отправлять огромное количество писем каждый день, и клиент хотел полный контроль над шаблонами html для различных типов писем.

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

то, что мы придумали, было статическим содержимым в sql server, где вы сохраняете всю разметку шаблона html (вместе с держателями мест, такими как [UserFirstName], [UserLastName], которые заменяются с реальными данными во время выполнения) для различных типов электронной почты

затем мы загрузили эти данные asp.net кэш-так что мы не читаем шаблоны html снова и снова - но только тогда, когда они на самом деле изменены

мы дали клиенту редактор WYSIWYG для изменения этих шаблонов через веб-форму администратора. всякий раз, когда обновления были сделаны, мы сбрасываем asp.net кэш.

и тогда у нас была отдельная таблица для журналов электронной почты - где каждое письмо, которое будет отправлено, было зарегистрировано. эта таблица имела поля называется emailType, emailSent и numberOfTries.

мы просто запускали задание каждые 5 минут для важных типов электронной почты (например, новый член зарегистрироваться, забыли пароль), которые должны быть отправлены как можно скорее

мы запускали другую работу каждые 15 минут для менее важных типов электронной почты (например, рекламная электронная почта, электронная почта новостей и т. д.)

таким образом, вы не блокируете ваш сервер, отправляющий нон-стоп электронные письма, и вы обрабатываете почту в пакетном режиме. после отправки сообщения электронной почты установите для поля emailSent значение 1.

посмотрите на дозвуковой (www.subsonicproject.com). они делают именно это для генерации кода - шаблон является стандартным ASPX, и он выводит c#. Тот же метод будет повторно использоваться для вашего сценария.

обратите внимание, что решения aspx и ascx требуют текущего HttpContext, поэтому их нельзя использовать асинхронно (например, в потоках) без большой работы.

Я думаю, что простой ответ-MvcMailer. Это пакет NuGet, который позволяет использовать ваш любимый движок просмотра для создания электронных писем. Смотрите пакет NuGet здесь и проектная документация

надеюсь, что это помогает!

DotLiquid-это еще один вариант. Вы указываете значения из модели класса {{ user.name }} и затем во время выполнения, вы предоставляете данные в этом классе, и шаблон с разметкой, и он будет объединять значения для вас. Это похоже на использование шаблонного двигателя бритвы во многих отношениях. Он поддерживает более сложные вещи, такие как петли и различные функции, такие как ToUpper. Самое приятное, что они "безопасны", так что пользователи, которые создают шаблоны, не могут разбить вашу систему или написать небезопасный код, как вы бы в бритву:http://dotliquidmarkup.org/try-online

если вы можете разрешить ASPNET и связанные с ним пользователи разрешение на чтение и запись файла, вы можете легко использовать HTML-файл со стандартным String.Format() заполнители ({0},{1:C} и т. д.) для достижения этой цели.

просто читать в файле, как строку, используя классы из System.IO пространство имен. Если у вас есть эта строка, передайте ее в качестве первого аргумента в String.Format() и укажите параметры.

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

Я должен отметить, что это работает лучше всего, если (А) вы не отправляете миллионы электронных писем одновременно, (б) вы не персонализируете каждое электронное письмо (в противном случае вы съедаете тонну строк) и (в) сам HTML-файл относительно мал.

установить установить сообщение электронной почты IsBodyHtml = true

возьмите объект, содержащий содержимое вашей электронной почты сериализовать объект и используйте xml / xslt для создания содержимого html.

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

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

Я бы использовал библиотеку шаблонов, как TemplateMachine. это позволяет в основном поместить шаблон электронной почты вместе с обычным текстом, а затем использовать правила для ввода/замены значений по мере необходимости. Очень похоже на ERB в Ruby. Это позволяет разделить генерацию содержимого почты, не привязывая вас слишком сильно к чему-то вроде ASPX и т. д. затем, как только контент будет создан с этим, вы можете отправить по электронной почте.

Мне нравится ответ Раджа. Такие программы, как ListManager и фреймворки, такие как DNN, делают подобные вещи, и если требуется простое редактирование нетехническими пользователями, Редакторы WYSIWYG для изменения HTML, хранящегося в SQL,-это в основном простой и простой способ пойти и легко разместить редактирование заголовков независимо от нижних колонтитулов и т. д., а также использовать токены для динамической вставки значений.

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

похоже на ответ Канавара, но вместо NVelocity я всегда использую "StringTemplate" который я загружаю шаблон из файла конфигурации или загружаю внешний файл с помощью файла.ReadAllText () и установите значения.

Это проект Java, но порт C# является твердым, и я использовал его в нескольких проектах (просто использовал его для шаблонов электронной почты, используя шаблон во внешнем файле).

альтернативы-это всегда хорошо.

вот простой способ с помощью WebClient класс:

public static string GetHTMLBody(string url)
{
    string htmlBody;

    using (WebClient client = new WebClient ())
    {
        htmlBody = client.DownloadString(url);
    }

    return htmlBody;
}

тогда просто назовите это так:

string url = "http://www.yourwebsite.com";
message.Body = GetHTMLBody(url);

конечно, ваш CSS должен быть встроен, чтобы показать стили веб-страницы в большинстве почтовых клиентов (таких как Outlook). Если ваша электронная почта отображает динамическое содержимое (например. Имя клиента), то я бы рекомендовал использовать QueryStrings на вашем сайте для заполнения данных. (бывший. http://www.yourwebsite.com?CustomerName=Bob)

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

Я использую веб-формы на веб-сайте (я клянусь, что никогда не буду использовать веб-сайт снова-что Пита) в VS 2013.

я попробовал предложение Razor, но мой веб-сайт я не получил все важные IntelliSense, что IDE поставляет в проекте MVC. Я также хотел бы использовать конструктор для моих шаблонов-идеальное место для UserControl.

Никс Опять бритва.

поэтому я придумал эту небольшую структуру вместо этого (советы hat для @mun для UserControl и @imatoria для сильного ввода). Единственное потенциальное место для неприятностей, которое я вижу, это то, что вы должны быть осторожны, чтобы сохранить свой .Имя файла ASCX синхронизировано с именем класса. Если вы заблудитесь, вы получите ошибку времени выполнения.

FWIW: в моем тестировании по крайней мере вызов RenderControl() не нравится элемент управления страницей, поэтому я пошел с UserControl.

я почти уверен, что у меня есть включены все здесь; дайте мне знать, если я что-то упустил.

HTH

использование:

Partial Class Purchase
  Inherits UserControl

  Private Sub SendReceipt()
    Dim oTemplate As MailTemplates.PurchaseReceipt

    oTemplate = MailTemplates.Templates.PurchaseReceipt(Me)
    oTemplate.Name = "James Bond"
    oTemplate.OrderTotal = 3500000
    oTemplate.OrderDescription = "Q-Stuff"
    oTemplate.InjectCss("PurchaseReceipt")

    Utils.SendMail("{0} <james.bond@mi6.co.uk>".ToFormat(oTemplate.Name), "Purchase Receipt", oTemplate.ToHtml)
  End Sub
End Class

Базовый Класс:

Namespace MailTemplates
  Public MustInherit Class BaseTemplate
    Inherits UserControl

    Public Shared Function GetTemplate(Caller As TemplateControl, Template As Type) As BaseTemplate
      Return Caller.LoadControl("~/MailTemplates/{0}.ascx".ToFormat(Template.Name))
    End Function



    Public Sub InjectCss(FileName As String)
      If Me.Styler IsNot Nothing Then
        Me.Styler.Controls.Add(New Controls.Styler(FileName))
      End If
    End Sub



    Private ReadOnly Property Styler As PlaceHolder
      Get
        If _Styler Is Nothing Then
          _Styler = Me.FindNestedControl(GetType(PlaceHolder))
        End If

        Return _Styler
      End Get
    End Property
    Private _Styler As PlaceHolder
  End Class
End Namespace

"Фабрика" Класс:

Namespace MailTemplates
  Public Class Templates
    Public Shared ReadOnly Property PurchaseReceipt(Caller As TemplateControl) As PurchaseReceipt
      Get
        Return BaseTemplate.GetTemplate(Caller, GetType(PurchaseReceipt))
      End Get
    End Property
  End Class
End Namespace

Класс Шаблона:

Namespace MailTemplates
  Public MustInherit Class PurchaseReceipt
    Inherits BaseTemplate

    Public MustOverride WriteOnly Property Name As String
    Public MustOverride WriteOnly Property OrderTotal As Decimal
    Public MustOverride WriteOnly Property OrderDescription As String
  End Class
End Namespace

заголовок ASCX:

<%@ Control Language="VB" ClassName="_Header" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<!--
  See https://www.campaignmonitor.com/blog/post/3317/ for discussion of DocType in HTML Email
-->

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title></title>
  <asp:PlaceHolder ID="plcStyler" runat="server"></asp:PlaceHolder>
</head>
<body>

нижний колонтитул ASCX:

<%@ Control Language="VB" ClassName="_Footer" %>

</body>
</html>

шаблон ASCX:

<%@ Control Language="VB" AutoEventWireup="false" CodeFile="PurchaseReceipt.ascx.vb" Inherits="PurchaseReceipt" %>

<%@ Register Src="_Header.ascx" TagName="Header" TagPrefix="uc" %>
<%@ Register Src="_Footer.ascx" TagName="Footer" TagPrefix="uc" %>

<uc:Header ID="ctlHeader" runat="server" />

  <p>Name: <asp:Label ID="lblName" runat="server"></asp:Label></p>
  <p>Order Total: <asp:Label ID="lblOrderTotal" runat="server"></asp:Label></p>
  <p>Order Description: <asp:Label ID="lblOrderDescription" runat="server"></asp:Label></p>

<uc:Footer ID="ctlFooter" runat="server" />

кодовый файл шаблона ASCX:

Partial Class PurchaseReceipt
  Inherits MailTemplates.PurchaseReceipt

  Public Overrides WriteOnly Property Name As String
    Set(Value As String)
      lblName.Text = Value
    End Set
  End Property



  Public Overrides WriteOnly Property OrderTotal As Decimal
    Set(Value As Boolean)
      lblOrderTotal.Text = Value
    End Set
  End Property



  Public Overrides WriteOnly Property OrderDescription As Decimal
    Set(Value As Boolean)
      lblOrderDescription.Text = Value
    End Set
  End Property
End Class

помощники:

'
' FindNestedControl helpers based on tip by @andleer
' at http://stackoverflow.com/questions/619449/
'

Public Module Helpers
  <Extension>
  Public Function AllControls(Control As Control) As List(Of Control)
    Return Control.Controls.Flatten
  End Function



  <Extension>
  Public Function FindNestedControl(Control As Control, Id As String) As Control
    Return Control.Controls.Flatten(Function(C) C.ID = Id).SingleOrDefault
  End Function



  <Extension>
  Public Function FindNestedControl(Control As Control, Type As Type) As Control
    Return Control.Controls.Flatten(Function(C) C.GetType = Type).SingleOrDefault
  End Function



  <Extension>
  Public Function Flatten(Controls As ControlCollection) As List(Of Control)
    Flatten = New List(Of Control)

    Controls.Traverse(Sub(Control) Flatten.Add(Control))
  End Function


  <Extension>
  Public Function Flatten(Controls As ControlCollection, Predicate As Func(Of Control, Boolean)) As List(Of Control)
    Flatten = New List(Of Control)

    Controls.Traverse(Sub(Control)
                        If Predicate(Control) Then
                          Flatten.Add(Control)
                        End If
                      End Sub)
  End Function



  <Extension>
  Public Sub Traverse(Controls As ControlCollection, Action As Action(Of Control))
    Controls.Cast(Of Control).ToList.ForEach(Sub(Control As Control)
                                               Action(Control)

                                               If Control.HasControls Then
                                                 Control.Controls.Traverse(Action)
                                               End If
                                             End Sub)
  End Sub



  <Extension()>
  Public Function ToFormat(Template As String, ParamArray Values As Object()) As String
    Return String.Format(Template, Values)
  End Function



  <Extension()>
  Public Function ToHtml(Control As Control) As String
    Dim oSb As StringBuilder

    oSb = New StringBuilder

    Using oSw As New StringWriter(oSb)
      Using oTw As New HtmlTextWriter(oSw)
        Control.RenderControl(oTw)
        Return oSb.ToString
      End Using
    End Using
  End Function
End Module



Namespace Controls
  Public Class Styler
    Inherits LiteralControl

    Public Sub New(FileName As String)
      Dim _
        sFileName,
        sFilePath As String

      sFileName = Path.GetFileNameWithoutExtension(FileName)
      sFilePath = HttpContext.Current.Server.MapPath("~/Styles/{0}.css".ToFormat(sFileName))

      If File.Exists(sFilePath) Then
        Me.Text = "{0}<style type=""text/css"">{0}{1}</style>{0}".ToFormat(vbCrLf, File.ReadAllText(sFilePath))
      Else
        Me.Text = String.Empty
      End If
    End Sub
  End Class
End Namespace



Public Class Utils
  Public Shared Sub SendMail(Recipient As MailAddress, Subject As String, HtmlBody As String)
    Using oMessage As New MailMessage
      oMessage.To.Add(Recipient)
      oMessage.IsBodyHtml = True
      oMessage.Subject = Subject.Trim
      oMessage.Body = HtmlBody.Trim

      Using oClient As New SmtpClient
        oClient.Send(oMessage)
      End Using
    End Using
  End Sub
End Class