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

97

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

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

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

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

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

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

Джон Бубриски
источник
Другое решение - использовать AlphaMail для создания и отправки ваших писем с использованием C # и языка шаблонов Comlang .
Тимоти Э. Йоханссон,
1
@JohnBubriski: Я работаю вокруг проблемы управления вы упомянули в «ОБНОВЛЕНИЕ С РИСКОВАННОГО» с использованием , new System.Web.UI.Control()как в: mailDefinition.CreateMailMessage("somebody@fake.com", iDictionaryReplacements, new System.Web.UI.Control()).
Теофил
Да, я тоже это сделал, но с появлением Razor это становится все менее хорошей идеей.
Джон Бубриски

Ответы:

73

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

Как указано в статье, «Лучшее в Razor состоит в том, что в отличие от своего предшественника (веб-форм) он не привязан к веб-среде, мы можем легко разместить его вне Интернета и использовать его в качестве механизма шаблонов для различных целей».

Создание электронных писем HTML с помощью RazorEngine - Часть 01 - Введение

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

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

Подобный Stackoverflow QA

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

Использование Razor без MVC

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

Майк Барлоу - BarDev
источник
1
+1, но будьте осторожны, если пользователи предоставляют шаблоны, поскольку они могут запускать код C # из шаблона, что дает им гораздо больше возможностей в вашей системе, чем вы, вероятно, хотели бы.
AaronLS
Что вы думаете о безопасности. Использование этого механизма шаблонов позволяет отформатировать всю файловую систему. Мне нравится двигатель, но это заставляет меня взглянуть на другие двигатели.
der_chirurg
55

Вы также можете попробовать загрузить элемент управления, а затем отобразить его в строке и установить его как тело 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);

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

Mun
источник
Я почему-то пропустил этот ответ в первый раз ... хороший. Подобно моему решению, но с ascx вместо aspx. Я по-прежнему думаю, что aspx было бы лучше, поскольку он предлагал бы полную страницу вместо элемента управления, но я так думаю.
Джон Бубриски
Да, вы можете использовать любое решение ... Они работают одинаково. Одно из преимуществ этого подхода - последовательность. Например, вы можете показать пользователю сводку заказа и включить то же самое в электронное письмо с подтверждением, повторно используя тот же элемент управления.
Мун,
Незначительный момент, но вам не хватает строки для объявления StringBuilder в первом блоке кода.
Киршштейн
9
В примере не объясняется, где находится код, это страница? Потому что LoadControl - это метод страницы / элемента управления.
Шраге Смиловиц
@Mun, вы загружаете usercontrol в переменную ctrl и больше никогда не ссылаетесь на нее в своем коде. Как это должно работать?
The Muffin Man
35

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

Джон Шиэн
источник
4
Я просто хочу отметить, что это хорошо для обычных писем, но не для чего-то сложного. Класс MailDefinition не поддерживает привязку данных. Единственное, что он действительно делает, - это замена строк. Хотя он также встроен в Мастер создания учетной записи членства.
Джон Бубриски
4
Класс MailDefinition должен получить Control для отображения шаблонного содержимого. Не очень хорошо.
Юки
17

Если вы хотите передать такие параметры, как имена пользователей, названия продуктов и т. Д., Вы можете использовать механизм шаблонов с открытым исходным кодом 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 и сохранять шаблоны в файлы.

Канавар
источник
7

Компонент электронной почты Mail.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();

Вы можете получить больше информации в блоге о движке шаблонов электронной почты.

Или просто скачайте почтовый компонент Mail.dll и попробуйте.

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

Павел Лесниковский
источник
6

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

Эвертон
источник
Я никогда не думал об этом раньше, но, попробовав множество других методов, я обнаружил, что это отлично работает в сочетании с добавлением IXmlSerializableинтерфейса в мои классы. Всего через несколько строк я могу отправить класс по электронной почте.
cjbarth
Уф, мне снились кошмары про XSLT. Вероятно, самый неинтуитивный язык программирования / разметки, с которым я работал. И невозможно поддерживать для других и даже для себя через месяц после того, как вы впервые написали свой XSLT.
PussInBoots
5

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

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

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

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

Джон Бубриски
источник
Хотя класс MailDefinition - хорошее начало, он немного рудиментарный. Этот метод должен поддерживать гораздо больше функций, таких как привязка данных и, возможно, даже трассировка. Есть какие-нибудь мысли по этому поводу или возможные проблемы?
Джон Бубриски
Большой! Были ли у вас с этим проблемы?
Джон Бубриски
Так вы позволите своим пользователям редактировать файлы .aspx, когда им нужно внести изменения в почтовый шаблон? Я бы назвал это потенциальной проблемой.
Брайан,
Я бы так не подумал, по крайней мере, не больше, чем другие шаблоны, которые они могут редактировать. Конечно, если бы они знали, что делают, они могли бы причинить вред, но, по крайней мере, в этом случае это маловероятно. Это не будет сложная страница .aspx, скорее шаблон с заполнителями.
Джон Бубриски
Я знаю, это было давно, но вы помните свое окончательное решение? Мне не удалось заставить этот конкретный подход работать с a Page, по крайней мере, при использовании универсального метода расширения для рендеринга. Таким образом я переключился на UserControl; мой ответ ниже. Пока что, похоже, все работает хорошо ... Мне было бы интересно узнать, как у вас это получалось в то время.
InteXX 01
4

Конечно, вы можете создать шаблон 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("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);
Джош Майн
источник
Вы можете вырезать материал StreamReader и заменить его на File.ReadAllText (путь)
Джон Шихан,
Это хорошее начало, но оно обеспечивает функциональность только для верхнего и нижнего колонтитула. Это не совсем помогает с самим телом.
Джон Бубриски
Все, что вам нужно сделать, это ввести желаемое содержимое тела в поля HTMLBody и TextBody или, конечно, вы также можете сохранить их в файлах
Джош Майн,
4

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

Алек Дэвис
источник
2
Нравится ссылка. Спасибо! Мой мозг начал вращаться и понял, что я могу сделать еще один шаг и иметь шаблон XSLT, который принимает объект XML Serializable или контракт данных WCF прямо в формат html-электронной почты. Неожиданно у меня были бы «строго типизированные» шаблоны писем через реальные сериализуемые классы!
CodingWithSpike
2

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

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

Danswain
источник
1

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

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

Марк Брэкетт
источник
1

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

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

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

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

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

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

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

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

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

Радж
источник
Но как вы поступали с коллекциями?
Riri
1
Я тоже делал это, и это хорошо сработало. Кроме того, вы можете исторически вернуться и увидеть записи отправленных писем, если отчеты вам нравятся.
Марк Глори,
1

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

Роско
источник
1

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

Надеюсь, поможет!

Сохан
источник
Хм, странно, что этот ответ не привлек столько внимания ?!
PussInBoots
1

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

AaronLS
источник
0

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

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

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

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

Джон Руди
источник
0

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

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

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

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

Боб Дворник
источник
0

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

Jvenema
источник
0

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

MikeJ
источник
0

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

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

Ник
источник
0

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

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

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

Брайан Бэйлиаш
источник
0

Вот простой способ использования класса 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 )

ROFLwTIME
источник
Аккуратно, хотя я думаю, что большинство других ответов делают это без отправки веб-запроса обратно на сайт, то есть необходимости размещать тело электронной почты на вашем сайте.
Rup
@Rup Понятно, но имейте в виду, что в большинстве случаев люди все равно хотят видеть "веб-версию" электронного письма. Это решение идеально подходит для этого сценария.
ROFLwTIME
0

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

Я использую WebForms на веб-сайте (клянусь, я больше никогда не буду использовать веб-сайт - что за PITA) в VS 2013.

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

Никс снова на Razor.

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

FWIW: В моем тестировании, по крайней мере, вызов RenderControl () не любит элемент управления Page, поэтому я выбрал 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
InteXX
источник
0

Просто добавляю библиотеку, которую я использую, в микс: https://github.com/lukencode/FluentEmail

Он отображает электронные письма с помощью RazorLight , использует свободный стиль для создания электронных писем и поддерживает несколько отправителей из коробки. Он также поставляется с методами расширения для ASP.NET DI. Простая в использовании, небольшая настройка, с поддержкой обычного текста и HTML.

ахонг
источник