Kann ich mit ASP.NET HTML- / E-Mail-Vorlagen einrichten?

97

Ich arbeite an einer Site, die eine beträchtliche Anzahl von E-Mails versendet. Ich möchte sowohl Kopf- als auch Fußzeilentext oder sogar Vorlagen einrichten, damit die Benutzer diese E-Mails bei Bedarf einfach bearbeiten können.

Wenn ich den HTML-Code in C # -String-Literale einbetten würde, wäre dies hässlich und sie müssten sich Sorgen machen, dass sie entkommen. Das Einfügen von Flatfiles für Kopf- und Fußzeile funktioniert möglicherweise, aber etwas daran fühlt sich einfach nicht richtig an.

Was wäre ideal, wenn Sie eine .ASPXSeite irgendwie als Vorlage verwenden würden, dann sagen Sie einfach meinem Code, dass er diese Seite bereitstellen soll, und verwenden Sie den für die E-Mail zurückgegebenen HTML-Code.

Gibt es eine schöne und einfache Möglichkeit, dies zu tun? Gibt es einen besseren Weg, um dieses Problem zu lösen?

Aktualisiert:
Ich habe eine Antwort hinzugefügt, mit der Sie eine ASPX-Standardseite als E-Mail-Vorlage verwenden können. Ersetzen Sie einfach alle Variablen wie gewohnt, verwenden Sie die Datenbindung usw. Erfassen Sie dann einfach die Ausgabe der Seite und voila! Sie haben Ihre HTML-E-Mail!

AKTUALISIERT MIT CAVEAT !!!:
Ich habe die MailDefinition-Klasse auf einigen Aspx-Seiten verwendet, aber beim Versuch, diese Klasse während eines laufenden Serverprozesses zu verwenden, ist sie fehlgeschlagen. Ich glaube, das lag daran, dass für die MailDefinition.CreateMailMessage () -Methode ein gültiges Steuerelement zum Verweisen erforderlich ist, obwohl dies nicht immer der Fall ist. Aus diesem Grund würde ich meinen Ansatz mit einer Aspx-Seite oder Muns Ansatz mit einer Ascx-Seite empfehlen, was etwas besser zu sein scheint.

John Bubriski
quelle
Eine andere Lösung wäre die Verwendung von AlphaMail zum Erstellen und Senden Ihrer E-Mails mit C # und der Comlang- Vorlagensprache.
Timothy E. Johansson
1
@ JohnBubriski: Ich arbeite um das Kontrollproblem, das Sie in "UPDATED WITH CAVEAT" erwähnt haben, mit new System.Web.UI.Control(): mailDefinition.CreateMailMessage("[email protected]", iDictionaryReplacements, new System.Web.UI.Control()).
Theophilus
Ja, das habe ich auch getan, aber angesichts des Aufkommens von Razor wird dies immer weniger eine gute Idee.
John Bubriski

Antworten:

73

Hier gibt es bereits eine Menge Antworten, aber ich bin auf einen großartigen Artikel gestoßen, in dem es darum geht, wie man Razor mit E-Mail-Vorlagen verwendet. Razor wurde mit ASP.NET MVC 3 gepusht, MVC ist jedoch nicht erforderlich, um Razor zu verwenden. Dies ist eine ziemlich raffinierte Verarbeitung von E-Mail-Vorlagen

In dem Artikel heißt es: "Das Beste an Razor ist, dass es im Gegensatz zu seinem Vorgänger (Webformulare) nicht an die Webumgebung gebunden ist. Wir können es problemlos außerhalb des Webs hosten und als Vorlagen-Engine für verschiedene Zwecke verwenden."

Generieren von HTML-E-Mails mit RazorEngine - Teil 01 - Einführung

Nutzung von Rasiermesser-Vorlagen außerhalb von ASP.NET: Sie sind nicht mehr nur für HTML gedacht!

Intelligentere E-Mail-Vorlagen in ASP.NET mit RazorEngine

Ähnliche Stackoverflow-Qualitätssicherung

Vorlagen mit der neuen RazorEngine-API

Verwenden von Razor ohne MVC

Ist es möglich, Razor View Engine außerhalb von asp.net zu verwenden?

Mike Barlow - BarDev
quelle
1
+1, aber seien Sie vorsichtig, wenn Benutzer die Vorlagen bereitstellen, da sie C # -Code aus der Vorlage ausführen können, wodurch sie in Ihrem System viel mehr Leistung erhalten, als Sie wahrscheinlich möchten.
AaronLS
Was denkst du über Sicherheit? Mit dieser Template-Engine können Sie möglicherweise das gesamte Dateisystem formatieren. Ich mag den Motor, aber das zwingt mich, mir andere Motoren anzuschauen.
der_chirurg
55

Möglicherweise möchten Sie auch versuchen, ein Steuerelement zu laden, es dann in eine Zeichenfolge zu rendern und dieses als HTML-Text festzulegen:

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

Sie können dann Ihre E-Mail wie gewohnt erstellen:

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

Ihr Benutzersteuerelement kann andere Steuerelemente enthalten, z. B. eine Kopf- und Fußzeile, und auch Funktionen wie die Datenbindung nutzen.

Mun
quelle
Ich habe diese Antwort beim ersten Mal irgendwie verpasst ... schön. Ähnlich wie bei meiner Lösung, jedoch mit einem Ascx anstelle eines Aspx. Ich denke immer noch, dass Aspx besser wäre, da es eine vollständige Seite anstelle eines Steuerelements bieten würde, aber genau das denke ich.
John Bubriski
Ja, Sie könnten beide Lösungen verwenden ... Sie funktionieren auf die gleiche Weise. Ein Vorteil dieses Ansatzes ist die Konsistenz. Sie können einem Benutzer beispielsweise eine Bestellübersicht anzeigen und genau dasselbe in die Bestätigungs-E-Mail aufnehmen, indem Sie dasselbe Steuerelement wiederverwenden.
Mun
Kleiner Punkt, aber Sie vermissen eine Zeile, um einen StringBuilder im ersten Codeblock zu deklarieren.
Kirschstein
9
Das Beispiel erklärt nicht, wo sich der Code befindet, ist es eine Seite?, Da LoadControl eine Seiten- / Steuerungsmethode ist.
Shrage Smilowitz
@Mun, Sie laden die Benutzersteuerung in eine Variable namens ctrl und verweisen in Ihrem Code nie wieder darauf. Wie soll das funktionieren?
Der Muffin-Mann
35

Sie können die MailDefinition-Klasse ausprobieren

John Sheehan
quelle
4
Ich möchte nur darauf hinweisen, dass dies gut für einfache E-Mails ist, aber nichts Komplexes. Die MailDefinition-Klasse unterstützt keine Datenbindung. Das einzige, was es wirklich tut, ist das Ersetzen von Saiten. Es ist jedoch auch in den Assistenten zum Erstellen von Mitgliedskonten integriert.
John Bubriski
4
Die MailDefinition-Klasse muss ein Steuerelement zum Rendern von Vorlageninhalten erhalten. Nicht so gut.
Yuki
17

Wenn Sie Parameter wie Benutzernamen, Produktnamen usw. übergeben möchten, können Sie die Open Source Template Engine NVelocity verwenden , um Ihre endgültigen E-Mails / HTML- Dateien zu erstellen.

Ein Beispiel für eine NVelocity-Vorlage ( 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

Generieren von Mail Body durch MailTemplate.vm in Ihrer Anwendung:

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

Der Ergebnis-Mail-Text lautet:

Eine Beispiel-E-Mail-Vorlage von ScarletGarden .

Für jedes Beispiel:

[Datum: 12.02.2009] Name: Punkt 1, Wert: 09

[Datum: 21.02.2009] Name: Punkt 4, Wert: 52

[Datum: 01.03.2009] Name: Punkt 2, Wert: 21

[Datum: 23.03.2009] Name: Punkt 6, Wert: 24

Zum Bearbeiten der Vorlagen können Sie möglicherweise FCKEditor verwenden und Ihre Vorlagen in Dateien speichern.

Canavar
quelle
7

Die Mail.dll-E-Mail-Komponente enthält eine E-Mail-Vorlagen-Engine:

Hier ist die Syntaxübersicht:

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

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

</body>
</html>

Und der Code, der die Vorlage lädt, Daten aus dem c # -Objekt füllt und eine E-Mail sendet:

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

Weitere Informationen finden Sie im Blogbeitrag der E-Mail-Vorlagen-Engine .

Oder laden Sie einfach die E-Mail-Komponente Mail.dll herunter und probieren Sie es aus.

Bitte beachten Sie, dass dies ein kommerzielles Produkt ist, das ich erstellt habe.

Pawel Lesnikowski
quelle
6

Wenn Flexibilität eine Ihrer Voraussetzungen ist, ist XSLT möglicherweise eine gute Wahl, die vollständig von .NET Framework unterstützt wird, und Sie können den Benutzer sogar diese Dateien bearbeiten lassen. Dieser Artikel ( http://www.aspfree.com/c/a/XML/XSL-Transformations-using-ASP-NET/ ) kann für den Anfang hilfreich sein (msdn enthält weitere Informationen dazu). Wie von ScarletGarden gesagt, ist NVelocity eine weitere gute Wahl, aber ich bevorzuge XSLT wegen seiner "integrierten" .NET Framework-Unterstützung und Plattformunabhängigkeit.

Everton
quelle
Ich hatte noch nie darüber nachgedacht, aber nachdem ich viele andere Methoden ausprobiert hatte, fand ich, dass dies in Kombination mit dem Hinzufügen der IXmlSerializableSchnittstelle zu meinen Klassen großartig funktionierte . In nur wenigen Zeilen kann ich meine Klasse in eine E-Mail verwandeln.
CJBarth
Urgh, ich habe Albträume von XSLT geträumt. Wahrscheinlich die nicht intuitivste Programmier- / Markup-Sprache, mit der ich gearbeitet habe. Und unmöglich für andere und sogar für sich selbst 1 Monat nach dem ersten Codieren Ihres XSLT zu warten.
PussInBoots
5

Ich denke, Sie könnten auch so etwas tun:

Erstellen Sie eine ASPX-Seite und fügen Sie diese am Ende der OnLoad-Methode ein oder rufen Sie sie manuell auf.

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

Ich bin mir nicht sicher, ob es potenzielle Probleme damit gibt, aber es sieht so aus, als würde es funktionieren. Auf diese Weise können Sie anstelle der MailDefinition-Klasse, die nur Textersetzungen unterstützt, eine ASPX-Seite mit vollem Funktionsumfang verwenden.

John Bubriski
quelle
Die MailDefinition-Klasse ist zwar ein guter Anfang, aber etwas rudimentär. Diese Methode sollte viel mehr Funktionen wie Datenbindung und möglicherweise sogar Ablaufverfolgung unterstützen. Irgendwelche Gedanken dazu oder mögliche Fallstricke?
John Bubriski
Toll! Hattest du irgendwelche Probleme damit?
John Bubriski
Lassen Sie Ihre Benutzer also die ASPX-Dateien bearbeiten, wenn sie Änderungen an der E-Mail-Vorlage vornehmen müssen? Ich würde das ein potenzielles Problem nennen.
Bryan
Ich würde zumindest nicht denken, dass dies kein größeres Risiko darstellt als andere Vorlagen, die sie bearbeiten könnten. Zugegeben, wenn sie wüssten, was sie tun, könnten sie Schaden anrichten, aber zumindest in diesem Fall ist dies unwahrscheinlich. Es wäre keine komplexe ASPX-Seite, sondern eher eine Vorlage mit Platzhaltern.
John Bubriski
Ich weiß, es ist eine Weile her, aber erinnern Sie sich an Ihre endgültige Lösung? Ich war nicht in der Lage, diesen speziellen Ansatz zum Arbeiten mit a zu bringen Page, zumindest wenn eine generische Erweiterungsmethode für das Rendern verwendet wurde. Also wechselte ich zu UserControl; siehe meine Antwort unten. Bisher scheint es gut zu funktionieren ... Es würde mich interessieren, wie Sie es damals ausgearbeitet haben.
InteXX
4

Sicher können Sie eine HTML-Vorlage erstellen und ich würde auch eine Textvorlage empfehlen. In der Vorlage können Sie einfach [KÖRPER] an der Stelle platzieren, an der der Körper platziert werden soll. Anschließend können Sie einfach die Vorlage einlesen und den Körper durch den neuen Inhalt ersetzen. Sie können die E-Mail mit .Nets Mail Class senden. Sie müssen nur das Senden der E-Mail an alle Empfänger durchlaufen, nachdem Sie die E-Mail erstellt haben. Arbeitete wie ein Zauber für mich.

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
quelle
Sie können das StreamReader-Zeug ausschneiden und durch File.ReadAllText (Pfad)
John Sheehan
Dies ist ein guter Anfang, bietet jedoch nur Funktionen für eine Kopf- und Fußzeile. Dies hilft nicht wirklich mit dem Körper selbst.
John Bubriski
Der Körper, den Sie nur tun müssen, ist, den gewünschten Körperinhalt in die HTMLBody- und TextBody-Felder einzugeben, oder Sie können sie natürlich auch in Dateien speichern
Josh Mein
4

Hier ist eine weitere Alternative, die XSL-Transformationen für komplexere E-Mail-Vorlagen verwendet: Senden von HTML-basierten E-Mails aus .NET-Anwendungen .

Alek Davis
quelle
2
Wie der Link. Vielen Dank! Mein Gehirn begann sich zu drehen und erkannte, dass ich noch einen Schritt weiter gehen und eine XSLT-Vorlage haben konnte, die ein XML Serializable-Objekt oder einen WCF-Datenvertrag direkt in das HTML-E-Mail-Format überträgt. Plötzlich hätte ich "stark typisierte" E-Mail-Vorlagen durch tatsächlich serialisierbare Klassen!
CodingWithSpike
2

Seien Sie vorsichtig, wenn Sie dies tun. SPAM-Filter scheinen das von ASP.net generierte HTML zu blockieren, anscheinend aufgrund von ViewState. Wenn Sie dies tun, stellen Sie sicher, dass das erzeugte HTML sauber ist.

Ich persönlich würde die Verwendung von Asp.net MVC prüfen, um die gewünschten Ergebnisse zu erzielen. oder NVelocity ist ziemlich gut darin

danswain
quelle
1

Was wäre ideal, wenn Sie eine ASPX-Seite irgendwie als Vorlage verwenden würden, dann sagen Sie einfach meinem Code, dass er diese Seite bereitstellen soll, und verwenden Sie den für die E-Mail zurückgegebenen HTML-Code.

Sie können einfach eine WebRequest erstellen, um eine ASPX-Seite aufzurufen und den resultierenden HTML-Code abzurufen. Mit etwas mehr Arbeit können Sie es wahrscheinlich ohne WebRequest erledigen. Mit einem PageParser und einem Response.Filter können Sie die Seite ausführen und die Ausgabe erfassen ... obwohl es möglicherweise elegantere Möglichkeiten gibt.

Mark Brackett
quelle
1

Ich hatte eine ähnliche Anforderung bei einem der Projekte, bei denen Sie jeden Tag eine große Anzahl von E-Mails senden mussten, und der Kunde wollte die vollständige Kontrolle über HTML-Vorlagen für verschiedene Arten von E-Mails.

Aufgrund der großen Anzahl der zu sendenden E-Mails war die Leistung ein Hauptanliegen.

Was wir uns ausgedacht haben, war statischer Inhalt auf einem SQL Server, auf dem Sie das gesamte HTML-Vorlagen-Markup (zusammen mit Platzhaltern wie [UserFirstName], [UserLastName], die zur Laufzeit durch echte Daten ersetzt werden) für verschiedene Arten von E-Mails speichern

Dann haben wir diese Daten in den asp.net-Cache geladen - damit wir die HTML-Vorlagen nicht immer wieder lesen - sondern nur, wenn sie tatsächlich geändert werden

Wir haben dem Client einen WYSIWYG-Editor zur Verfügung gestellt, um diese Vorlagen über ein Admin-Webformular zu ändern. Wann immer Aktualisierungen vorgenommen wurden, setzen wir den asp.net-Cache zurück.

und dann hatten wir eine separate Tabelle für E-Mail-Protokolle - in der jede zu sendende E-Mail protokolliert wurde. Diese Tabelle enthielt Felder mit den Namen emailType, emailSent und numberOfTries.

Wir haben einfach alle 5 Minuten einen Job für wichtige E-Mail-Typen (wie Anmeldung eines neuen Mitglieds, vergessenes Passwort) ausgeführt, die so schnell wie möglich gesendet werden müssen

Wir haben alle 15 Minuten einen weiteren Job für weniger wichtige E-Mail-Typen ausgeführt (wie Werbe-E-Mail, Nachrichten-E-Mail usw.).

Auf diese Weise blockieren Sie nicht Ihren Server, der ununterbrochen E-Mails sendet, und Sie verarbeiten E-Mails im Stapel. Sobald eine E-Mail gesendet wurde, setzen Sie das Feld emailSent auf 1.

Raj
quelle
Aber wie sind Sie mit Sammlungen umgegangen?
Riri
1
Ich habe das auch gemacht und es hat gut funktioniert. Außerdem können Sie in der Vergangenheit die Aufzeichnungen der gesendeten E-Mails anzeigen, wenn Berichte Ihr Ding sind.
Mark Glorie
1

Beachten Sie, dass die Lösungen aspx und ascx einen aktuellen HttpContext erfordern und daher nicht ohne viel Arbeit asynchron (z. B. in Threads) verwendet werden können.

Rosco
quelle
1

Ich denke, die einfache Antwort ist MvcMailer. Mit diesem NuGet-Paket können Sie Ihre bevorzugte Ansichts-Engine zum Generieren von E-Mails verwenden. Sehen Sie das NuGet-Paket hier und das Projektdokumentation

Ich hoffe es hilft!

Sohan
quelle
Hmm, seltsam, dass diese Antwort nicht so viel Aufmerksamkeit hat?!
PussInBoots
1

DotLiquid ist eine weitere Option. Sie geben Werte aus einem Klassenmodell an, {{ user.name }}und zur Laufzeit stellen Sie die Daten in dieser Klasse und die Vorlage mit dem Markup bereit. Die Werte werden dann für Sie zusammengeführt. Es ähnelt in vielerlei Hinsicht der Verwendung der Razor-Template-Engine. Es unterstützt komplexere Dinge wie Schleifen und verschiedene Funktionen wie ToUpper. Das Schöne ist, dass diese "sicher" sind, damit Benutzer, die die Vorlagen erstellen, Ihr System nicht zum Absturz bringen oder unsicheren Code schreiben können, wie Sie es in Rasiermesser tun würden: http://dotliquidmarkup.org/try-online

AaronLS
quelle
0

Wenn Sie dem ASPNET und den zugeordneten Benutzern die Berechtigung zum Lesen und Schreiben einer Datei gewähren können, können Sie problemlos eine HTML-Datei mit Standardplatzhaltern verwenden String.Format()( {0},{1:C} usw.) , dies zu erreichen.

Lesen Sie die Datei lediglich als Zeichenfolge mit Klassen aus dem System.IONamespace ein. Wenn Sie diese Zeichenfolge haben, übergeben Sie sie als erstes Argument anString.Format() und geben Sie die Parameter an.

Behalten Sie diese Zeichenfolge bei und verwenden Sie sie als Textkörper der E-Mail, und Sie sind im Wesentlichen fertig. Wir tun dies heute auf Dutzenden von (zugegebenermaßen kleinen) Websites und hatten keine Probleme.

Ich sollte beachten, dass dies am besten funktioniert, wenn (a) Sie nicht Millionen von E-Mails gleichzeitig senden, (b) Sie nicht jede E-Mail personalisieren (andernfalls verbrauchen Sie eine Menge Zeichenfolgen) und (c ) Die HTML-Datei selbst ist relativ klein.

John Rudy
quelle
0

Setzen Sie die E-Mail-Nachricht IsBodyHtml = true

Nehmen Sie Ihr Objekt, das Ihren E-Mail-Inhalt enthält. Serialisieren Sie das Objekt und verwenden Sie xml / xslt, um den HTML-Inhalt zu generieren.

Wenn Sie AlternateViews ausführen möchten, verwenden Sie dasselbe, dass jmein nur eine andere xslt-Vorlage verwendet, um den Nur-Text-Inhalt zu erstellen.

Einer der Hauptvorteile ist, wenn Sie Ihr Layout ändern möchten, müssen Sie nur die xslt-Vorlage aktualisieren.

Bob der Hausmeister
quelle
0

Schauen Sie sich SubSonic an (www.subsonicproject.com). Sie tun genau dies, um Code zu generieren - die Vorlage ist Standard-ASPX und gibt c # aus. Die gleiche Methode kann für Ihr Szenario wiederverwendet werden.

jvenema
quelle
0

Ich würde eine Vorlagenbibliothek wie TemplateMachine verwenden . Auf diese Weise können Sie Ihre E-Mail-Vorlage meistens mit normalem Text zusammenstellen und dann Regeln verwenden, um Werte nach Bedarf einzufügen / zu ersetzen. Sehr ähnlich zu ERB in Ruby. Auf diese Weise können Sie die Generierung des E-Mail-Inhalts trennen, ohne zu stark an ASPX usw. gebunden zu sein. Sobald der Inhalt damit generiert wurde, können Sie E-Mails versenden.

MikeJ
quelle
0

Ich mag Rajs Antwort. Programme wie ListManager und Frameworks wie DNN erledigen ähnliche Aufgaben. Wenn eine einfache Bearbeitung durch nicht technische Benutzer erforderlich ist, sind WYSIWYG-Editoren zum Ändern von in SQL gespeichertem HTML-Code eine meist einfache und unkomplizierte Methode, mit der Sie Kopfzeilen unabhängig von Fußzeilen bearbeiten können. usw. sowie die Verwendung von Token zum dynamischen Einfügen von Werten.

Eine Sache, die Sie bei der Verwendung der oben genannten Methode (oder einer anderen) beachten sollten, ist, streng und vorsichtig zu sein, welche Arten von Stilen und Tags die Editoren einfügen dürfen. Wenn Sie der Meinung sind, dass Browser pingelig sind, warten Sie einfach, bis Sie sehen, wie unterschiedlich E-Mail-Clients dasselbe rendern ...

Nick
quelle
0

Ähnlich wie bei Canavars Antwort, aber anstelle von NVelocity verwende ich immer " StringTemplate ", mit dem ich die Vorlage aus einer Konfigurationsdatei lade, oder lade eine externe Datei mit File.ReadAllText () und setze die Werte.

Es ist ein Java-Projekt, aber der C # -Port ist solide und ich habe ihn in mehreren Projekten verwendet (nur zum Erstellen von E-Mail-Vorlagen mithilfe der Vorlage in einer externen Datei verwendet).

Alternativen sind immer gut.

Bryan Bailliache
quelle
0

Hier ist eine einfache Möglichkeit, die WebClient- Klasse zu verwenden:

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

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

    return htmlBody;
}

Dann nenne es einfach so:

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

Natürlich muss Ihr CSS eingebunden sein, damit die Stile der Webseite in den meisten E-Mail-Clients (z. B. Outlook) angezeigt werden. Wenn in Ihrer E-Mail dynamischer Inhalt angezeigt wird (z. B. Kundenname), würde ich empfehlen, QueryStrings auf Ihrer Website zum Auffüllen der Daten zu verwenden. (z. B. http://www.yourwebsite.com?CustomerName=Bob )

ROFLwTIME
quelle
Ordentlich, obwohl ich denke, dass die meisten anderen Antworten dies tun, ohne eine Webanforderung an die Site zurückzusenden, dh den E-Mail-Text auf Ihrer Site hosten zu müssen.
Rup
@ Rup Verständlich, aber denken Sie daran, dass die Leute oft eine "Web-Version" der E-Mail sehen möchten. Diese Lösung funktioniert perfekt für dieses Szenario.
ROFLwTIME
0

@bardev bietet eine gute Lösung, ist aber leider nicht in allen Fällen ideal. Meins war einer von ihnen.

Ich verwende WebForms in einer Website (ich schwöre, ich werde nie wieder eine Website verwenden - was für eine PITA) in VS 2013.

Ich habe den Razor-Vorschlag ausprobiert, aber da ich eine Website bin, habe ich nicht den wichtigen IntelliSense erhalten, den die IDE in einem MVC-Projekt liefert. Ich verwende den Designer auch gerne für meine Vorlagen - ein perfekter Ort für ein UserControl.

Wieder Nix auf Razor.

Also habe ich mir stattdessen dieses kleine Framework ausgedacht (Tipps für @mun für UserControl und @imatoria für Strong Typing). Der einzige potenzielle Problempunkt, den ich sehen kann, ist, dass Sie vorsichtig sein müssen, um Ihren .ASCX-Dateinamen mit dem Klassennamen synchron zu halten. Wenn Sie verirrt sind, wird ein Laufzeitfehler angezeigt.

FWIW: In meinen Tests mag zumindest der Aufruf von RenderControl () kein Seitensteuerelement, deshalb habe ich mich für UserControl entschieden.

Ich bin mir ziemlich sicher, dass ich hier alles aufgenommen habe. Lass es mich wissen, wenn ich etwas ausgelassen habe.

HTH

Verwendung:

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

Basisklasse:

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

"Fabrik" -Klasse:

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

Vorlagenklasse:

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-Header:

<%@ 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-Fußzeile:

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

</body>
</html>

ASCX-Vorlage:

<%@ 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 Template 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

Helfer:

'
' 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
quelle
0

Wirf einfach die Bibliothek, die ich benutze, in die Mischung: https://github.com/lukencode/FluentEmail

Es rendert E-Mails mit RazorLight , verwendet den fließenden Stil zum Erstellen von E-Mails und unterstützt sofort mehrere Absender. Es enthält auch Erweiterungsmethoden für ASP.NET DI. Einfach zu bedienen, wenig eingerichtet, mit Klartext- und HTML-Unterstützung.

ahong
quelle