Czy mogę skonfigurować szablony HTML / e-mail w programie ASP.NET?

97

Pracuję nad witryną, która będzie wysyłać znaczną liczbę e-maili. Chcę ustawić zarówno tekst nagłówka, jak i stopki, a może nawet szablony, aby umożliwić użytkownikom łatwą edycję tych wiadomości e-mail, jeśli zajdzie taka potrzeba.

Jeśli osadzę kod HTML wewnątrz literałów ciągów C #, będzie to brzydkie i będą musieli się martwić o ucieczkę. Dołączanie płaskich plików do nagłówka i stopki może działać, ale coś w tym jest po prostu nie tak.

Co byłoby idealne, gdyby .ASPXw jakiś sposób użyć strony jako szablonu, a następnie po prostu powiedz mojemu kodowi, aby wyświetlał tę stronę, i użyj kodu HTML zwróconego w wiadomości e-mail.

Czy jest na to łatwy i przyjemny sposób? Czy istnieje lepszy sposób rozwiązania tego problemu?

Zaktualizowano:
dodałem odpowiedź, która umożliwia użycie standardowej strony .aspx jako szablonu wiadomości e-mail. Po prostu zamień wszystkie zmienne, tak jak zwykle, użyj wiązania danych itp. Następnie po prostu przechwyć wyjście strony i voila! Masz swój e-mail w formacie HTML!

ZAKTUALIZOWANO Z CAVEAT !!!:
Używałem klasy MailDefinition na niektórych stronach aspx, ale podczas próby użycia tej klasy podczas uruchomionego procesu serwera nie powiodło się. Wydaje mi się, że było tak, ponieważ metoda MailDefinition.CreateMailMessage () wymaga ważnej kontrolki do odniesienia, mimo że nie zawsze coś robi. Z tego powodu poleciłbym moje podejście przy użyciu strony aspx lub podejście Mun przy użyciu strony ascx, które wydaje się nieco lepsze.

John Bubriski
źródło
Innym rozwiązaniem byłoby użycie AlphaMail do tworzenia i wysyłania wiadomości e-mail przy użyciu C # i języka szablonów Comlang .
Timothy E. Johansson,
1
@JohnBubriski: Pracuję wokół problemu sterowania pan wspomniał w „aktualizowana o zastrzeżenie” przy użyciu new System.Web.UI.Control()na przykład: mailDefinition.CreateMailMessage("[email protected]", iDictionaryReplacements, new System.Web.UI.Control()).
Theophilus
Tak, ja też to zrobiłem, ale biorąc pod uwagę pojawienie się Razora, to staje się mniej dobrym pomysłem.
John Bubriski

Odpowiedzi:

73

Jest tu już mnóstwo odpowiedzi, ale natknąłem się na świetny artykuł o tym, jak używać Razor z szablonami wiadomości e-mail. Razor został wypchnięty za pomocą ASP.NET MVC 3, ale MVC nie jest wymagany do korzystania z Razor. To całkiem sprytne przetwarzanie szablonów wiadomości e-mail

Jak stwierdzono w artykule: „Najlepszą rzeczą w Razor jest to, że w przeciwieństwie do swojego poprzednika (formularzy internetowych) nie jest on powiązany ze środowiskiem internetowym, możemy z łatwością hostować go poza siecią i używać go jako silnika szablonów do różnych celów”.

Generowanie wiadomości e-mail w formacie HTML za pomocą RazorEngine - Część 01 - Wprowadzenie

Wykorzystywanie szablonów Razor poza ASP.NET: nie są one już tylko dla HTML!

Inteligentniejsze szablony wiadomości e-mail w ASP.NET z RazorEngine

Podobna kontrola jakości Stackoverflow

Tworzenie szablonów przy użyciu nowego interfejsu API RazorEngine

Korzystanie z Razor bez MVC

Czy można używać Razor View Engine poza asp.net

Mike Barlow - BarDev
źródło
1
+1, ale bądź ostrożny, jeśli użytkownicy dostarczają szablony, ponieważ mogą uruchamiać kod C # z szablonu, dając im o wiele więcej możliwości w Twoim systemie, niż prawdopodobnie byś chciał.
AaronLS
Co myślisz o bezpieczeństwie. Korzystanie z tego silnika szablonów umożliwia sformatowanie całego systemu plików. Podoba mi się silnik, ale to zmusza mnie do przyjrzenia się innym silnikom.
der_chirurg,
55

Możesz także spróbować załadować kontrolkę, a następnie wyrenderować ją na ciąg i ustawić jako treść 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();

Następnie możesz utworzyć swój e-mail w zwykły sposób:

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

Kontrolka użytkownika może zawierać inne kontrolki, takie jak nagłówek i stopka, a także korzystać z funkcji, takich jak powiązanie danych.

Mun
źródło
Jakoś przegapiłem tę odpowiedź za pierwszym razem ... niezła. Podobne do mojego rozwiązania, ale z ascx zamiast aspx. Nadal uważam, że aspx byłby lepszy, ponieważ oferowałby pełną stronę zamiast kontrolki, ale tak właśnie myślę.
John Bubriski
Tak, możesz użyć dowolnego rozwiązania ... Działają w ten sam sposób. Jedną z zalet tego podejścia jest konsekwencja. Na przykład możesz pokazać użytkownikowi podsumowanie zamówienia i zawrzeć dokładnie to samo w wiadomości e-mail z potwierdzeniem, ponownie używając tego samego elementu sterującego.
Mun
Drobny punkt, ale brakuje wiersza do zadeklarowania StringBuilder w pierwszym bloku kodu.
Kirschstein
9
Przykład nie wyjaśnia, gdzie znajduje się kod, czy jest to strona ?, ponieważ LoadControl jest metodą strony / kontroli.
Shrage Smilowitz
@Mun, ładujesz usercontrol do zmiennej o nazwie ctrl i nigdy więcej nie odwołujesz się do niej w swoim kodzie. Jak to ma działać?
The Muffin Man
35

Możesz wypróbować klasę MailDefinition

John Sheehan
źródło
4
Chcę tylko zaznaczyć, że jest to dobre dla podstawowych wiadomości e-mail, ale nie jest to nic skomplikowanego. Klasa MailDefinition nie obsługuje wiązania danych. Jedyne, co naprawdę robi, to oferowanie zamienników ciągów. Chociaż jest również wbudowany w Kreator tworzenia konta członkostwa.
John Bubriski
4
Klasa MailDefinition musi uzyskać Control, aby renderować zawartość na podstawie szablonu. Niezbyt dobrze.
Yuki,
17

Jeśli chcesz przekazać parametry, takie jak nazwy użytkowników, nazwy produktów itp., Możesz użyć silnika szablonów Open Source NVelocity do tworzenia ostatecznych wiadomości e-mail / HTML.

Przykład szablonu 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

Generowanie treści wiadomości przez MailTemplate.vm w Twojej aplikacji:

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

Wynikowa treść wiadomości to:

Przykładowy szablon wiadomości e-mail autorstwa ScarletGarden .

Przykład dla każdego:

[Data: 12.02.2009] Nazwa: Pozycja 1, Wartość: 09

[Data: 21.02.2009] Nazwa: Pozycja 4, Wartość: 52

[Data: 01.03.2009] Nazwa: Pozycja 2, Wartość: 21

[Data: 23.03.2009] Nazwa: Pozycja 6, Wartość: 24

Do edycji szablonów możesz użyć FCKEditor i zapisać szablony w plikach.

Canavar
źródło
7

Składnik poczty e-mail Mail.dll zawiera silnik szablonów wiadomości e-mail:

Oto przegląd składni:

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

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

</body>
</html>

A kod, który ładuje szablon, wypełnia dane z obiektu C # i wysyła e-mail:

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

Możesz uzyskać więcej informacji na temat wpisu na blogu silnika szablonów wiadomości e-mail .

Lub po prostu pobierz komponent poczty e-mail Mail.dll i spróbuj.

Zwróć uwagę, że jest to produkt komercyjny, który stworzyłem.

Paweł Leśnikowski
źródło
6

Jeśli elastyczność jest jednym z Twoich wymagań wstępnych, XSLT może być dobrym wyborem, który jest w pełni obsługiwany przez platformę .NET i możesz nawet pozwolić użytkownikowi edytować te pliki. Ten artykuł ( http://www.aspfree.com/c/a/XML/XSL-Transformations-using-ASP-NET/ ) może być przydatny na początek (msdn ma więcej informacji na ten temat). Jak powiedział ScarletGarden, NVelocity to kolejny dobry wybór, ale wolę XSLT ze względu na jego "wbudowaną" obsługę frameworka .NET i niezależność od platformy.

Everton
źródło
Nigdy wcześniej o tym nie myślałem, ale po wypróbowaniu wielu innych metod okazało się, że działa to świetnie w połączeniu z dodaniem IXmlSerializableinterfejsu do moich zajęć. Wystarczy kilka linijek, aby moja klasa wysłała wiadomość e-mail.
cjbarth
Urgh, śniłem koszmary o XSLT. Prawdopodobnie najbardziej nieintuicyjny język programowania / znaczników, z jakim pracowałem. I niemożliwe do utrzymania dla innych, a nawet dla siebie 1 miesiąc po pierwszym zakodowaniu XSLT.
PussInBoots
5

Myślę, że możesz też zrobić coś takiego:

Utwórz stronę i .aspx i umieść to na końcu metody OnLoad lub wywołaj ją ręcznie.

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

Nie jestem pewien, czy są z tym jakieś potencjalne problemy, ale wygląda na to, że zadziała. W ten sposób możesz użyć w pełni funkcjonalnej strony .aspx zamiast klasy MailDefinition, która obsługuje tylko zamiany tekstu.

John Bubriski
źródło
Chociaż klasa MailDefinition to dobry początek, jest nieco elementarna. Ta metoda powinna obsługiwać znacznie więcej funkcji, takich jak wiązanie danych, a może nawet śledzenie. Jakieś przemyślenia na ten temat lub potencjalne problemy?
John Bubriski
Wspaniały! Czy miałeś z tym jakieś problemy?
John Bubriski
Więc pozwolisz swoim użytkownikom edytować pliki .aspx, gdy będą musieli wprowadzić zmiany w szablonie poczty? Nazwałbym to potencjalnym problemem.
Bryan,
Nie sądziłbym, że przynajmniej nie stanowi to większego ryzyka niż inne szablony, które mogliby edytować. Oczywiście, gdyby wiedzieli, co robią, mogliby wyrządzić krzywdę, ale przynajmniej w tym przypadku jest to mało prawdopodobne. Nie byłaby to skomplikowana strona .aspx, a raczej szablon z symbolami zastępczymi.
John Bubriski
Wiem, że minęło trochę czasu, ale czy pamiętasz swoje ostateczne rozwiązanie? Nie udało mi się uzyskać tego konkretnego podejścia do pracy z plikiem Page, przynajmniej przy użyciu ogólnej metody rozszerzenia do renderowania. Tak więc przeszedłem na UserControl; zobacz moją odpowiedź poniżej. Jak na razie wygląda na to, że działa dobrze ... Chciałbym się dowiedzieć, jak wtedy to wypracowałeś.
InteXX
4

Jasne, że możesz stworzyć szablon html i polecam również szablon tekstowy. W szablonie możesz po prostu umieścić [BODY] w miejscu, w którym miałaby zostać umieszczona treść, a następnie możesz po prostu przeczytać szablon i zastąpić treść nową treścią. Możesz wysłać wiadomość e-mail za pomocą .Nets Mail Class. Musisz tylko zapętlić wysyłanie wiadomości e-mail do wszystkich odbiorców po początkowym utworzeniu wiadomości e-mail. U mnie zadziałało jak urok.

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);
Josh Mein
źródło
Możesz wyciąć rzeczy ze StreamReadera i zastąpić je File.ReadAllText (ścieżka)
John Sheehan
To dobry początek, ale zapewnia tylko funkcjonalność nagłówka i stopki. To naprawdę nie pomaga w przypadku samego ciała.
John Bubriski
Wszystko, co musisz zrobić, to wprowadzić żądaną treść do pól HTMLBody i TextBody lub możesz oczywiście przechowywać je również w plikach
Josh Mein
4

Oto jeszcze jedna alternatywa, która wykorzystuje przekształcenia XSL do bardziej złożonych szablonów wiadomości e-mail: Wysyłanie wiadomości e-mail w formacie HTML z aplikacji .NET .

Alek Davis
źródło
2
Podobnie jak link. Dzięki! Mój mózg zaczął się obracać i zdałem sobie sprawę, że mogę pójść o krok dalej i mam szablon XSLT, który przenosi obiekt XML Serializable lub kontrakt danych WCF bezpośrednio do formatu html-email. Nagle miałbym szablony e-maili z „silnym typowaniem” poprzez rzeczywiste klasy serializowalne!
CodingWithSpike
2

Zachowaj ostrożność, filtry SPAM wydają się blokować wygenerowany przez ASP.net html, najwyraźniej z powodu ViewState, więc jeśli zamierzasz to zrobić, upewnij się, że utworzony kod HTML jest czysty.

Osobiście rozważałbym użycie Asp.net MVC, aby osiągnąć pożądane rezultaty. lub NVelocity jest w tym całkiem niezłe

danswain
źródło
1

Co byłoby idealne, gdyby w jakiś sposób użyć strony .ASPX jako szablonu, a następnie po prostu powiedz mojemu kodowi, aby wyświetlał tę stronę, i użyj kodu HTML zwróconego w wiadomości e-mail.

Możesz po prostu skonstruować żądanie WebRequest, aby trafić na stronę ASPX i uzyskać wynikowy kod HTML. Przy odrobinie pracy prawdopodobnie można to zrobić bez WebRequest. PageParser i Response.Filter pozwolą ci uruchomić stronę i przechwycić wynik ... chociaż mogą istnieć bardziej eleganckie sposoby.

Mark Brackett
źródło
1

Miałem podobne wymaganie w przypadku 1 z projektów, w których każdego dnia trzeba było wysyłać ogromną liczbę e-maili, a klient chciał mieć pełną kontrolę nad szablonami HTML dla różnych typów wiadomości e-mail.

ze względu na dużą liczbę e-maili do wysłania głównym problemem była wydajność.

to, co wymyśliliśmy, to statyczna zawartość na serwerze sql, gdzie zapisujesz całe znaczniki szablonu html (wraz z miejscami, takimi jak [UserFirstName], [UserLastName], które są zastępowane prawdziwymi danymi w czasie wykonywania) dla różnych typów wiadomości e-mail

następnie załadowaliśmy te dane do pamięci podręcznej asp.net - więc nie czytamy w kółko szablonów html - ale tylko wtedy, gdy zostaną faktycznie zmienione

daliśmy klientowi edytor WYSIWYG do modyfikowania tych szablonów za pośrednictwem formularza internetowego administratora. po dokonaniu aktualizacji resetujemy pamięć podręczną asp.net.

a potem mieliśmy oddzielną tabelę dla dzienników poczty e-mail - gdzie każdy wysłany e-mail był rejestrowany. ta tabela zawiera pola o nazwach emailType, emailSent i numberOfTries.

po prostu uruchamialiśmy zadanie co 5 minut dla ważnych typów wiadomości e-mail (takich jak rejestracja nowego członka, zapomniałem hasła), które należy wysłać jak najszybciej

co 15 minut wykonywaliśmy kolejne zadanie dla mniej ważnych typów wiadomości e-mail (takich jak e-maile promocyjne, e-maile z wiadomościami itp.)

w ten sposób nie blokujesz wysyłania nieprzerwanych e-maili przez serwer i przetwarzasz je wsadowo. po wysłaniu wiadomości e-mail ustaw w polu emailSent wartość 1.

Raj
źródło
Ale jak radziłeś sobie z kolekcjami?
Riri,
1
Zrobiłem to również i zadziałało dobrze. Ponadto możesz historycznie cofnąć się i zobaczyć zapisy wysłanych wiadomości e-mail, jeśli lubisz raporty.
Mark Glorie
1

Należy pamiętać, że rozwiązania aspx i ascx wymagają bieżącego HttpContext, więc nie można ich używać asynchronicznie (np. W wątkach) bez dużego nakładu pracy.

Rosco
źródło
1

Myślę, że łatwą odpowiedzią jest MvcMailer. Jest to pakiet NuGet, który umożliwia używanie ulubionego silnika widoku do generowania wiadomości e-mail. Zobacz pakiet NuGet tutaj i dokumentację projektu

Mam nadzieję, że to pomoże!

Sohan
źródło
Hmm, dziwne, że ta odpowiedź nie przyciągnęła tak dużej uwagi ?!
PussInBoots
1

DotLiquid to kolejna opcja. Określasz wartości z modelu klasy, {{ user.name }}a następnie w czasie wykonywania podajesz dane w tej klasie i szablon ze znacznikami, a wartości zostaną scalone za Ciebie. Jest to podobne do używania silnika szablonów Razor na wiele sposobów. Obsługuje bardziej złożone rzeczy, takie jak pętle i różne funkcje, takie jak ToUpper. Fajne jest to, że są one „bezpieczne”, więc użytkownik, który tworzy szablony, nie może zawiesić systemu ani napisać niebezpiecznego kodu, tak jak w przypadku Razor: http://dotliquidmarkup.org/try-online

AaronLS
źródło
0

Jeśli jesteś w stanie pozwolić pozwolenie ASPNET i związane z nimi użytkownikom na odczyt i zapis pliku, można łatwo korzystać z pliku HTML przy użyciu standardowych String.Format()elementów zastępczych ( {0}, {1:C}etc.) do osiągnięcia tego celu.

Tylko wczytywane w pliku jako ciąg znaków, przy użyciu klas z System.IOprzestrzeni nazw. Gdy już masz ten ciąg, przekaż go jako pierwszy argument do String.Format()i podaj parametry.

Zachowaj ten ciąg i używaj go jako treści wiadomości e-mail. W zasadzie gotowe. Robimy to obecnie na dziesiątkach (co prawda małych) witrynach i nie mieliśmy żadnych problemów.

Powinienem zauważyć, że działa to najlepiej, jeśli (a) nie wysyłasz milionów e-maili na raz, (b) nie personalizujesz każdego e-maila (w przeciwnym razie zjadasz tonę ciągów) i (c ) sam plik HTML jest stosunkowo mały.

John Rudy
źródło
0

Ustaw zestaw Wiadomość e-mail IsBodyHtml = true

Weź swój obiekt, który zawiera treść wiadomości e-mail Serializuj obiekt i użyj xml / xslt do wygenerowania treści html.

Jeśli chcesz zrobić AlternateViews, zrób to samo, co jmein używa tylko innego szablonu xslt do tworzenia zwykłej zawartości tekstowej.

Jedną z głównych zalet jest to, że jeśli chcesz zmienić układ, wystarczy zaktualizować szablon xslt.

Bob Woźny
źródło
0

Spójrz na SubSonic (www.subsonicproject.com). Robią dokładnie to, aby wygenerować kod - szablon jest standardowym ASPX i wyprowadza C #. Ta sama metoda byłaby wielokrotnego użytku w Twoim scenariuszu.

jvenema
źródło
0

Używałbym biblioteki szablonów, takiej jak TemplateMachine . pozwala to przeważnie umieścić szablon wiadomości e-mail razem ze zwykłym tekstem, a następnie użyć reguł do wstrzykiwania / zastępowania wartości w razie potrzeby. Bardzo podobny do ERB w Rubim. Pozwala to oddzielić generowanie treści wiadomości e-mail bez zbytniego wiązania się z czymś takim jak ASPX itp., A po wygenerowaniu treści za pomocą tego można wysłać e-mail.

MikeJ
źródło
0

Podoba mi się odpowiedź Raja. Programy takie jak ListManager i frameworki, takie jak DNN, robią podobne rzeczy, a jeśli wymagana jest łatwa edycja przez nietechnicznych użytkowników, edytory WYSIWYG do modyfikowania HTML przechowywanego w SQL są przeważnie łatwym, prostym sposobem i mogą łatwo edytować nagłówki niezależnie od stopek, itp., a także za pomocą tokenów do dynamicznego wstawiania wartości.

Jedną rzeczą, o której należy pamiętać, jeśli używasz powyższej metody (lub innej, naprawdę), jest ścisłe i ostrożne wybieranie typów stylów i tagów, które możesz wstawiać redaktorom. Jeśli uważasz, że przeglądarki są wybredne, poczekaj, aż zobaczysz, jak inaczej klienci poczty e-mail renderują to samo ...

Nacięcie
źródło
0

Podobnie jak odpowiedź Canavara, ale zamiast NVelocity zawsze używam „ StringTemplate ”, do którego szablon z pliku konfiguracyjnego lub ładuję plik zewnętrzny za pomocą File.ReadAllText () i ustawiam wartości.

To projekt Java, ale port C # jest solidny i użyłem go w kilku projektach (właśnie użyłem go do tworzenia szablonów wiadomości e-mail przy użyciu szablonu w zewnętrznym pliku).

Alternatywy są zawsze dobre.

Bryan Bailliache
źródło
0

Oto prosty sposób wykorzystania klasy WebClient :

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

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

    return htmlBody;
}

Następnie nazwij to tak:

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

Oczywiście CSS będzie musiał być wbudowany, aby pokazać style strony internetowej w większości klientów poczty e-mail (takich jak Outlook). Jeśli Twój e-mail wyświetla dynamiczną zawartość (np. Nazwę klienta), to polecam użycie QueryStrings w Twojej witrynie do wypełnienia danych. (np. http://www.yourwebsite.com?CustomerName=Bob )

ROFLwTIME
źródło
Schludnie, chociaż myślę, że większość innych odpowiedzi robi to bez wysyłania żądania internetowego z powrotem do witryny, tj. Konieczności hostowania treści wiadomości e-mail w witrynie.
Rup
@Rup Zrozumiałe, ale należy pamiętać, że często ludzie i tak chcą zobaczyć „wersję internetową” wiadomości e-mail. To rozwiązanie sprawdza się idealnie w tym scenariuszu.
ROFLwTIME,
0

@bardev zapewnia dobre rozwiązanie, ale niestety nie jest ono idealne we wszystkich przypadkach. Mój był jednym z nich.

Używam formularzy internetowych na stronie internetowej (przysięgam, że nigdy więcej nie użyję strony internetowej - co za PITA) w VS 2013.

Wypróbowałem sugestię Razor, ale będąc stroną internetową, nie dostałem najważniejszego IntelliSense, który IDE zapewnia w projekcie MVC. Lubię też używać projektanta do moich szablonów - idealne miejsce na UserControl.

Znowu Nix na Razor.

Więc zamiast tego wymyśliłem ten mały framework (porady dotyczące kapeluszy dla @mun dla UserControl i @imatoria dla silnego pisania). Jedynym potencjalnym problemem, jaki widzę, jest to, że musisz uważać, aby nazwa pliku .ASCX była zsynchronizowana z nazwą klasy. Jeśli zbłądzisz, pojawi się błąd wykonania.

FWIW: W moich testach przynajmniej wywołanie RenderControl () nie lubi kontrolki Page, więc wybrałem UserControl.

Jestem prawie pewien, że zawarłem tutaj wszystko; daj mi znać, jeśli coś pominąłem.

HTH

Stosowanie:

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

Klasa podstawowa:

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

Klasa „fabryki”:

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

Klasa szablonu:

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

Nagłówek 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>

Stopka ASCX:

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

</body>
</html>

Szablon 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" />

Plik kodu szablonu 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

Pomocnicy:

'
' 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
źródło
0

Po prostu wrzucam bibliotekę, której używam do miksu: https://github.com/lukencode/FluentEmail

Renderuje wiadomości e-mail za pomocą RazorLight , używa stylu płynnego do tworzenia wiadomości e-mail i obsługuje wielu nadawców po wyjęciu z pudełka. Zawiera również metody rozszerzające dla ASP.NET DI. Prosty w użyciu, niewielka konfiguracja, z obsługą zwykłego tekstu i HTML.

ahong
źródło