Могу ли я настроить HTML/Email Templates с помощью ASP.NET?
Я работаю над сайтом, который отправит значительное количество писем. Я хочу настроить как текст заголовка, так и нижний колонтитул, или, возможно, даже шаблоны, чтобы пользователи могли легко редактировать эти письма, если им нужно.
Если я внедряю HTML внутри строковых литералов С#, это уродливо, и им придется беспокоиться об экранировании. Включение плоских файлов для заголовка и нижнего колонтитула может работать, но что-то об этом просто не кажется правильным.
Что было бы идеальным в том, чтобы каким-то образом использовать страницу .ASPX
в качестве шаблона, а затем просто скажите моему коду, чтобы он обслуживал эту страницу, и используйте HTML, возвращенный для письма.
Есть ли хороший и простой способ сделать это? Есть ли лучший способ решить эту проблему?
Обновлено:
Я добавил ответ, который позволяет использовать стандартную страницу .aspx в качестве шаблона электронной почты. Просто замените все переменные, как обычно, используйте привязку данных и т.д. Затем просто запишите вывод страницы и вуаля! У вас есть HTML-адрес электронной почты!
ОБНОВЛЕНО С ПЕЩЕЙ!!!:
Я очень хорошо использовал класс MailDefinition на некоторых страницах aspx, но при попытке использовать этот класс во время выполняемого серверного процесса он не удался. Я считаю, что это связано с тем, что для метода MailDefinition.CreateMailMessage() требуется действительный элемент управления для ссылки, хотя он не всегда что-то делает. Из-за этого я бы рекомендовал мой подход, используя страницу aspx, или подход Mun, используя страницу ascx, которая кажется немного лучше.
Ответы
Ответ 1
Там уже много ответов, но я наткнулся на отличную статью о том, как использовать Razor с шаблонами электронной почты. Razor был перенесен с ASP.NET MVC 3, но MVC не требуется использовать Razor. Это довольно гладкая обработка шаблонов электронной почты
Как отмечается в статье, "Лучшая вещь Razor заключается в том, что в отличие от своего предшественника (веб-формы) она не связана с веб-средой, мы можем легко разместить ее за пределами Интернета и использовать ее в качестве механизма шаблонов для различных целей".
Создание электронных писем HTML с помощью RazorEngine - Часть 01 - Введение
Использование шаблонов Razor за пределами ASP.NET: Theyre не только для HTML больше!
Умные шаблоны электронной почты в ASP.NET с RazorEngine
Аналогичный QA
Шаблоны с использованием нового API RazorEngine
Использование Razor без MVC
Можно ли использовать Razor View Engine вне asp.net
Ответ 2
Вы также можете попробовать загрузить элемент управления, а затем передать его в строку и установить это как тело 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("[email protected]", "from name");
message.Subject = "Email Subject";
message.Body = body;
message.BodyEncoding = Encoding.ASCII;
message.IsBodyHtml = true;
SmtpClient smtp = new SmtpClient("server");
smtp.Send(message);
Пользовательский элемент управления может содержать другие элементы управления, такие как верхний и нижний колонтитулы, а также использовать такие функции, как привязка данных.
Ответ 3
Вы можете попробовать класс MailDefinition
Ответ 4
Если вы хотите передавать такие параметры, как имена пользователей, названия продуктов и т.д., вы можете использовать механизм шаблонов с открытым исходным кодом 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.vm в приложении:
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 и сохранять свои шаблоны в файлах.
Ответ 5
Компонент электронной почты Mail.dll включает механизм шаблонов электронной почты:
Вот обзор синтаксиса:
<html>
<body>
Hi {FirstName} {LastName},
Here are your orders:
{foreach Orders}
Order '{Name}' sent to <strong>{Street}</strong>.
{end}
</body>
</html>
И код, загружающий шаблон, заполняет данные из объекта С# и отправляет электронное письмо:
Mail.Html(Template
.FromFile("template.txt")
.DataFrom(_contact)
.Render())
.Text("This is text version of the message.")
.From(new MailBox("[email protected]", "Alice"))
.To(new MailBox("[email protected]", "Bob"))
.Subject("Your order")
.UsingNewSmtp()
.WithCredentials("[email protected]", "password")
.Server("mail.com")
.WithSSL()
.Send();
Вы можете получить дополнительную информацию о блоге электронной почты в блоге.
Или просто скачайте компонент электронной почты Mail.dll и попробуйте.
Обратите внимание, что это коммерческий продукт, который я создал.
Ответ 6
Если гибкость является одним из ваших предварительных условий, XSLT может быть хорошим выбором, который полностью поддерживается платформой .NET, и вы сможете даже позволить пользователю редактировать эти файлы. Эта статья (http://www.aspfree.com/c/a/XML/XSL-Transformations-using-ASP-NET/) может быть полезна для запуска (у msdn есть больше информации об этом).
Как сказал ScarletGarden, NVelocity - еще один хороший выбор, но я предпочитаю XSLT для его "встроенной" поддержки платформы .NET и агностики платформы.
Ответ 7
Думаю, вы могли бы сделать что-то вроде этого:
Создайте и .aspx-страницу и поместите это в конец метода OnLoad или вызовите его вручную.
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
HtmlTextWriter htmlTW = new HtmlTextWriter(sw);
this.Render(htmlTW);
Я не уверен, есть ли какие-то потенциальные проблемы с этим, но похоже, что это сработает. Таким образом, вы можете использовать полнофункциональную страницу .aspx вместо класса MailDefinition, которая поддерживает только замену текста.
Ответ 8
Конечно, вы можете создать html-шаблон, и я бы порекомендовал также текстовый шаблон. В шаблоне вы можете просто положить [BODY] в место, где будет размещено тело, а затем вы можете просто прочитать в шаблоне и заменить тело новым контентом. Ты можешь отправить
электронной почты с использованием .Nets Mail Class. Вам просто нужно пройти через отправку электронной почты всем получателям после того, как вы сначала создадите адрес электронной почты. Работала как прелесть для меня.
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("[email protected]", "display name");
m.To.Add("[email protected]");
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);
Ответ 9
Вот еще одна альтернатива, которая использует преобразования XSL для более сложных шаблонов электронной почты: Отправка электронной почты на основе HTML из приложений .NET.
Ответ 10
Будьте осторожны, при этом фильтры SPAM, похоже, блокируют генерируемый html ASP.net, по-видимому, из-за ViewState, поэтому, если вы сделаете это, убедитесь, что полученный Html чистый.
Я лично рассмотрел бы использование Asp.net MVC для достижения желаемых результатов. или NVelocity неплохо в этом
Ответ 11
Что было бы идеальным, чтобы каким-то образом использовать страницу .ASPX как шаблон, а затем просто сообщите моему коду, чтобы он обслуживал эту страницу, и используйте HTML-код, возвращенный для письма.
Вы можете просто построить WebRequest, чтобы попасть на страницу ASPX и получить полученный HTML-код. С немного больше работы, вы можете, возможно, сделать это без WebRequest. PageParser и Response.Filter позволяют вам запускать страницу и захватывать результат... хотя могут быть и более элегантные способы.
Ответ 12
У меня было аналогичное требование в 1 из проектов, где каждый день приходилось отправлять огромное количество писем, и клиент хотел получить полный контроль над шаблонами html для разных типов электронных писем.
из-за большого количества отправляемых писем, производительность была главной проблемой.
то, что мы придумали, - это статический контент на сервере sql, где вы сохраняете весь шаблон шаблона html (вместе с владельцами мест, такими как [UserFirstName], [UserLastName], которые заменяются реальными данными во время выполнения) для разных типов электронная почта
тогда мы загрузили эти данные в кеш-память asp.net - поэтому мы не читаем html-шаблоны снова и снова, но только тогда, когда они действительно изменены
мы предоставили клиенту редактор WYSIWYG для изменения этих шаблонов через веб-форму администратора. всякий раз, когда делались обновления, мы reset кеш asp.net.
а затем у нас была отдельная таблица для журналов электронной почты - где было отправлено каждое отправленное письмо. в этой таблице были поля, называемые emailType, emailSent и numberOfTries.
мы просто запускали работу каждые 5 минут для важных типов электронной почты (например, зарегистрировать нового участника, забыли пароль), которые нужно отправить asap
мы запускали еще одну работу каждые 15 минут для менее важных типов электронной почты (например, для рассылки, электронной почты и т.д.)
Таким образом, вы не блокируете отправку сервера без остановок электронной почты и обрабатываете письма в пакетном режиме. после отправки электронной почты вы установите для поля emailSent значение 1.
Ответ 13
Обратите внимание, что решения aspx и ascx требуют текущего HttpContext, поэтому не могут использоваться асинхронно (например, в потоках) без большой работы.
Ответ 14
Я думаю, что легкий ответ - MvcMailer. Это пакет NuGet, который позволяет использовать ваш любимый механизм просмотра для создания электронных писем. См. Пакет NuGet здесь и документация по проекту
Надеюсь, что это поможет!
Ответ 15
DotLiquid - еще один вариант. Вы указываете значения из модели класса как {{ user.name }}
, а затем во время выполнения вы предоставляете данные в этом классе и шаблон с разметкой, и он будет объединять значения для вас. Он похож на использование шаблона шаблонов Razor разными способами. Он поддерживает более сложные вещи, такие как циклы и различные функции, такие как ToUpper. Самое приятное, что они "безопасны", так что пользователь, создающий шаблоны, не может разрушить вашу систему или написать небезопасный код, как в бритве: http://dotliquidmarkup.org/try-online
Ответ 16
Если вы можете разрешить ASPNET и связанным пользователям разрешать чтение и запись файла, вы можете легко использовать HTML файл со стандартными String.Format()
заполнителями ({0}
, {1:C}
и т.д.), чтобы выполнить это,
Просто прочтите в файле как строку, используя классы из пространства имен System.IO
. После того, как у вас есть эта строка, передайте ее как первый аргумент String.Format()
и укажите параметры.
Сохраните эту строку и используйте ее как тело электронной почты, и вы по существу делаете это. Мы делаем это на десятках (по общему признанию, небольших) сайтов сегодня и не испытывали никаких проблем.
Я должен отметить, что это лучше всего работает, если (а) вы не отправляете по-разному числа писем по электронной почте, (б) вы не персонализируете каждое электронное письмо (иначе вы едите тонну строк) и (c) сам файл HTML относительно невелик.
Ответ 17
Задайте набор сообщений электронной почты IsBodyHtml = true
Возьмите свой объект, содержащий содержимое электронной почты. Сериализуйте объект
и используйте xml/xslt для генерации содержимого html.
Если вы хотите сделать AlternateView, сделайте то же самое, что jmein использует только другой шаблон xslt для создания текстового содержимого.
Одним из основных преимуществ этого является то, что если вы хотите изменить свой макет, все, что вам нужно, обновить шаблон xslt.
Ответ 18
Посмотрите на SubSonic (www.subsonicproject.com). Они делают именно это для генерации кода - шаблон является стандартным ASPX, и он выводит С#. Тот же метод будет использоваться повторно для вашего сценария.
Ответ 19
Я бы использовал библиотеку шаблонов, например TemplateMachine. это позволяет в основном разместить ваш шаблон электронной почты вместе с обычным текстом, а затем использовать правила для ввода/замены значений по мере необходимости. Очень похож на ERB в Ruby. Это позволяет вам отделить создание почтового содержимого, не связывая вас слишком сильно с чем-то вроде ASPX и т.д., После того как контент будет создан с этим, вы можете отправить его по электронной почте.
Ответ 20
Мне нравится ответ Радж. Такие программы, как ListManager и фреймворки, такие как DNN, делают подобные вещи, и если требуется простое редактирование нетехническими пользователями, редакторы WYSIWYG для изменения HTML, хранящихся в SQL, - это, в основном, простой и понятный способ и могут легко размещать заголовки редактирования независимо от нижних колонтитулов, и т.д., а также использование токенов для динамической вставки значений.
Одна вещь, которую следует иметь в виду, если использовать вышеприведенный метод (или любой, действительно), быть строгим и осторожным в отношении того, какие типы стилей и тегов вы позволяете редакторам вставлять. Если вы считаете, что браузеры являются точными, просто подождите, пока не увидите, как по-разному клиенты электронной почты выполняют одно и то же...
Ответ 21
Как и ответ Canavar, но вместо NVelocity я всегда использую " StringTemplate"
который загружает шаблон из файла конфигурации или загружает внешний файл с помощью File.ReadAllText() и устанавливает значения.
Это проект Java, но порт С# является солидным, и я использовал его в нескольких проектах (просто использовал его для шаблонов электронной почты, используя шаблон во внешнем файле).
Альтернативы всегда хороши.
Ответ 22
Вот простой способ использования класса 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);
Конечно, для того, чтобы показать стили веб-страницы в большинстве почтовых клиентов (например, Outlook), ваш CSS должен быть выровнен. Если ваше электронное письмо отображает динамический контент (например, имя клиента), я бы рекомендовал использовать QueryStrings на вашем веб-сайте для заполнения данных. (например, http://www.yourwebsite.com?CustomerName=Bob)
Ответ 23
@bardev обеспечивает хорошее решение, но, к сожалению, он не идеален во всех случаях. Мой был одним из них.
Я использую WebForms на веб-сайте (клянусь, я больше никогда не буду использовать веб-сайт - что такое PITA) на VS 2013.
Я попробовал предложение Razor, но мой сайт стал не самым важным IntelliSense, который IDE предоставляет в проекте MVC. Мне также нравится использовать конструктор для моих шаблонов - идеальное место для UserControl.
Nix на Razor снова.
Итак, я придумал эту небольшую основу (подсказка для @mun для UserControl и @imatoria для сильной печати). Почти единственное потенциальное препятствие, которое я вижу, заключается в том, что вы должны быть осторожны, чтобы сохранить имя файла .ASCX в синхронизации с его именем класса. Если вы отклонились, вы получите ошибку времени выполнения.
FWIW: В моем тестировании, по крайней мере, вызов RenderControl() не нравится управление страницей, поэтому я пошел с UserControl.
Я уверен, что здесь все включено; дайте мне знать, если я что-то оставил.
НТН
Использование:
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} <[email protected]>".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
"Factory" Класс:
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 CodeFile:
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
Ответ 24
Просто добавляю библиотеку, которую я использую, в микс: https://github.com/lukencode/FluentEmail
Он обрабатывает электронные письма, используя RazorLight, использует свободный стиль для создания электронных писем и поддерживает сразу несколько отправителей. Он также поставляется с методами расширения для ASP.NET DI. Простая в использовании, небольшая настройка, с простым текстом и поддержкой HTML.