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

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

Wenn ich den HTML-Code in C # -Stringliterale einbetten möchte, ist es hässlich und sie müssten sich darum sorgen, dass sie entkommen. Es könnte funktionieren, flache Dateien für die Kopf- und Fußzeile zu integrieren, aber etwas dagegen fühlt sich einfach nicht richtig an.

Was wäre ideal, wenn Sie eine .ASPX Seite als Vorlage verwenden würden .ASPX Dann sagen Sie einfach meinem Code, diese Seite zu bedienen, und verwenden Sie den für die E-Mail zurückgegebenen HTML-Code.

Gibt es einen schönen und einfachen Weg, dies zu tun? Gibt es einen besseren Weg, dieses Problem zu lösen?

Aktualisiert:
Ich habe eine Antwort hinzugefügt, mit der Sie eine Standard-ASPX-Seite als E-Mail-Vorlage verwenden können. Ersetzen Sie einfach alle Variablen, wie Sie es normalerweise tun würden, verwenden Sie Datenbindung usw. Dann erfassen Sie einfach die Ausgabe der Seite, und voila! Sie haben Ihre HTML-E-Mail!

AKTUALISIERT MIT CAVEAT !!!:
Ich habe die MailDefinition-class auf einigen aspx-Seiten problemlos verwendet, aber als ich versuchte, diese class während eines laufenden Serverprozesses zu verwenden, schlug sie fehl. Ich glaube, es war, weil die MailDefinition.CreateMailMessage () -Methode ein gültiges Steuerelement benötigt, um zu referenzieren, obwohl es nicht immer etwas tut. Aus diesem Grund würde ich meinen Ansatz mit einer Aspx-Seite oder Muns Ansatz mit einer Ascx-Seite empfehlen, die ein wenig besser scheint.

Es gibt eine Menge Antworten bereits hier, aber ich stolperte über einen tollen Artikel darüber, wie man Razor mit E-Mail-Vorlagen verwendet. Razor wurde mit ASP.NET MVC 3 gepusht, aber MVC muss Razor nicht verwenden. Dies ist eine ziemlich glatte Verarbeitung von E-Mail-Vorlagen

Im Artikel heißt es: “Das Beste an Razor ist, dass es im Gegensatz zu seinem Vorgänger (Webforms) nicht an die Webumgebung gebunden ist. Wir können es einfach außerhalb des Webs hosten und es als Vorlage für verschiedene Zwecke verwenden.”

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

Razor Templates außerhalb von ASP.NET nutzen: Sie sind nicht nur für HTML mehr!

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

Ähnliche Stackoverflow QA

Templating mit der neuen RazorEngine API

Verwenden von Razor ohne MVC

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

Sie können auch versuchen, ein Steuerelement zu laden und es dann in eine Zeichenfolge zu rendern und dies 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önnten dann Ihre E-Mail wie gewohnt erstellen:

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

Ihr Benutzersteuerelement könnte andere Steuerelemente enthalten, z. B. Kopf- und Fußzeile, und auch functionen wie die Datenbindung nutzen.

Sie könnten die MailDefinition-class ausprobieren

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

Ein Beispiel für NVelocity-Vorlage ( MailTemplate.vm ):

 A sample email template by $name. 
Foreach example :
#foreach ($item in $itemList) [Date: $item.Date] Name: $item.Name, Value: $itemValue.Value

#end

Mail-Nachricht in MailTemplate.vm in Ihrer Anwendung generieren:

 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 E-Mail-Nachrichtentext lautet:

Eine Beispiel-E-Mail-Vorlage von ScarletGarden .

Beispiel:

[Datum: 12.02.2009] Name: Artikel 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 vielleicht FCKEditor verwenden und Ihre Vorlagen in Dateien speichern.

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

Hier ist die Syntaxübersicht:

   Hi {FirstName} {LastName}, Here are your orders: {foreach Orders} Order '{Name}' sent to {Street}. {end}   

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

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

Sie können weitere Informationen zum E-Mail-Vorlagen-Engine- Blogpost erhalten.

Oder laden Sie einfach Mail.dll E-Mail-Komponente und versuchen Sie es.

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

Wenn Flexibilität eine Ihrer Voraussetzungen ist, könnte XSLT eine gute Wahl sein, die vollständig von .NET Framework unterstützt wird und Sie könnten sogar den Benutzer diese Dateien bearbeiten lassen. Dieser Artikel ( http://www.aspfree.com/c/a/XML/XSL-Transformations-using-ASP-NET/ ) könnte für einen Anfang nützlich sein (msdn hat mehr Informationen darüber). Wie von ScarletGarden gesagt, ist NVelocity eine weitere gute Wahl, aber ich bevorzuge XSLT für seine “eingebaute” .NET Framework-Unterstützung und Plattform Agnostic.

Sicher können Sie eine HTML-Vorlage erstellen und ich würde auch eine Textvorlage empfehlen. In der Vorlage kannst du einfach [KÖRPER] an die Stelle setzen, an der der Körper platziert werden soll und dann kannst du einfach die Vorlage einlesen und den Körper durch den neuen Inhalt ersetzen. Sie können die E-Mail mit der Mail-class .Nets senden. Sie müssen nur das Senden der E-Mail an alle Empfänger durchlaufen, nachdem Sie die E-Mail ursprünglich 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("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); 

Ich denke du könntest auch so etwas machen:

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 irgendwelche Probleme gibt, aber es sieht so aus, als würde es funktionieren. Auf diese Weise können Sie eine vollständige ASPX-Seite anstelle der MailDefinition-class verwenden, die nur Textersetzungen unterstützt.

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

Seien Sie vorsichtig, wenn Sie dies tun, scheinen SPAM-Filter ASP.NET-generierte HTML zu blockieren, anscheinend wegen ViewState. Wenn Sie dies tun, stellen Sie sicher, dass die erzeugte HTML sauber ist.

Ich persönlich würde Asp.net MVC verwenden, um Ihre gewünschten Ergebnisse zu erzielen. oder NVelocity ist ziemlich gut darin

Was wäre ideal, wenn Sie eine .ASPX-Seite als Vorlage verwenden würden? Dann sagen Sie einfach meinem Code, diese Seite zu bedienen, und verwenden Sie den für die E-Mail zurückgegebenen HTML-Code.

Sie könnten einfach eine WebRequest erstellen, um eine ASPX-Seite zu treffen und das resultierende HTML zu erhalten. Mit ein wenig mehr Arbeit können Sie es wahrscheinlich ohne WebRequest erledigen. Ein PageParser und ein Response.Filter erlauben Ihnen, die Seite auszuführen und die Ausgabe zu erfassen … obwohl es vielleicht elegantere Möglichkeiten gibt.

Ich hatte eine ähnliche Anforderung für eines 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 versendenden E-Mails war die performance ein Hauptanliegen.

Wir haben statische Inhalte auf dem SQL-Server erstellt, auf denen Sie die gesamte HTML-Vorlagenmarkierung (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 – also lesen wir die HTML-Templates nicht immer wieder – aber nur wenn sie tatsächlich geändert werden

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

und dann hatten wir eine separate Tabelle für E-Mail-Protokolle – wo jede zu sendende E-Mail protokolliert wurde. Diese Tabelle hatte Felder namens emailType, emailSent und numberOfTries.

Wir haben einfach alle 5 Minuten einen Job für wichtige E-Mail-Typen (wie die Registrierung eines neuen Mitglieds, Passwort vergessen) 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 (wie Werbe-E-Mail, Nachrichten-E-Mail usw.) ausgeführt.

Auf diese Weise blockierst du deinen Server nicht, indem du Non-Stop-E-Mails verschickst und Mails im Batch abarbeitest. Sobald eine E-Mail gesendet wurde, legen Sie das Feld emailSent auf 1 fest.

Schauen Sie sich SubSonic (www.subsonicproject.com) an. Sie tun genau das, um Code zu generieren – die Vorlage ist Standard-ASPX und gibt c # aus. Die gleiche Methode wäre für Ihr Szenario wiederverwendbar.

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

Ich denke, die einfache Antwort ist MvcMailer. Es ist NuGet-Paket, mit dem Sie Ihre Lieblings-View-Engine zum Generieren von E-Mails verwenden können. Sehen Sie das NuGet-Paket hier und die Projektdokumentation

Ich hoffe es hilft!

DotLiquid ist eine weitere Option. Sie geben Werte aus einem classnmodell als {{ user.name }} und stellen zur Laufzeit die Daten in dieser class und die Vorlage mit dem Markup bereit, und die Werte werden für Sie zusammengeführt. Es ist vergleichbar mit der Verwendung der Razor Templating-Engine in vielerlei Hinsicht. Es unterstützt komplexere Dinge wie Schleifen und verschiedene functionen wie ToUpper. Die nette Sache ist, dass diese “sicher” sind, so dass Benutzer, die die Vorlagen erstellen, Ihr System nicht zum Absturz bringen oder unsicheren Code schreiben können, wie Sie es in Rasierklingen tun würden: http://dotliquidmarkup.org/try-online

Wenn Sie ASPNET und den zugehörigen Benutzern die Berechtigung zum Lesen und Schreiben einer Datei String.Format() können, können Sie problemlos eine HTML-Datei mit den Standard- String.Format() Platzhaltern ( {0} , {1:C} usw.) verwenden Dies.

Lies nur die Datei als String mit classn aus dem Namespace System.IO . Sobald Sie diese Zeichenfolge haben, übergeben Sie sie als erstes Argument an String.Format() und stellen Sie die Parameter bereit.

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

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

Legen Sie die E-Mail-Nachricht fest 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 mit AlternateViews arbeiten möchten, tun Sie dasselbe, dass jmein nur eine andere xslt-Vorlage verwendet, um den reinen Textinhalt zu erstellen.

Einer der Hauptvorteile davon ist, wenn Sie Ihr Layout ändern wollen, müssen Sie nur die XSLT-Vorlage aktualisieren.

Ich würde eine Vorlagenbibliothek wie TemplateMachine verwenden . Auf diese Weise können Sie Ihre E-Mail-Vorlage hauptsächlich mit normalem Text zusammenstellen und dann nach Bedarf Regeln verwenden, um Werte einzufügen / zu ersetzen. Sehr ähnlich wie ERB in Ruby. Dies ermöglicht es Ihnen, die Generierung des Mail-Inhalts zu trennen, ohne Sie zu stark an etwas wie ASPX usw. zu binden. Wenn der Inhalt einmal generiert ist, können Sie eine E-Mail senden.

Ich mag Rajs Antwort. Programme wie ListManager und Frameworks wie DNN tun ähnliche Dinge, und wenn einfache Bearbeitung durch nicht-technische Benutzer erforderlich ist, WYSIWYG-Editoren zum Bearbeiten von HTML in SQL gespeichert ist eine meist einfache, unkomplizierte Möglichkeit zu gehen und kann Kopfzeilen unabhängig von Fußzeilen, usw., sowie die Verwendung von Tokens zum dynamischen Einfügen von Werten.

Eine Sache, die Sie im Auge behalten sollten, wenn Sie die obige Methode (oder irgendeine, wirklich) verwenden, ist streng und vorsichtig zu sein, welche Arten von Stilen und Tags Sie den Editoren erlauben einzufügen. Wenn Sie denken, Browser sind knifflig, warten Sie einfach, bis Sie sehen, wie anders E-Mail-Clients dasselbe rendern …

Ähnlich wie bei Canavar, verwende ich aber anstelle von NVelocity immer ” StringTemplate “, das 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 (benutze ihn einfach für E-Mail-Templating mit der Vorlage in einer externen Datei).

Alternativen sind immer gut.

Hier ist ein einfacher Weg, die WebClient- class 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, um die Stile der Webseite in den meisten E-Mail-Clients (z. B. Outlook) anzuzeigen. Wenn Ihre E-Mail dynamischen Inhalt anzeigt (z. B. Kundenname), würde ich empfehlen, QueryStrings auf Ihrer Website zu verwenden, um die Daten zu füllen. (zB http://www.yourwebsite.com?CustomerName=Bob )

@ Bardev bietet eine gute Lösung, aber leider ist es 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 das wichtige IntelliSense, das die IDE in einem MVC-Projekt liefert, nicht bekommen. Ich benutze auch gerne den Designer für meine Vorlagen – ein perfekter Ort für ein UserControl.

Nix auf razor wieder.

Also habe ich dieses kleine Framework entwickelt (tippt auf @mun für UserControl und @imatoria für Strong Typing). Nur der einzige potentielle Problempunkt, den ich sehen kann, ist, dass Sie darauf achten müssen, dass Ihr .ASCX-Dateiname mit seinem classnnamen übereinstimmt. Wenn Sie sich verirrt haben, erhalten Sie einen Laufzeiterrors.

FWIW: In meinen Tests mag zumindest der Aufruf von RenderControl () kein Seiten-Control, also ging ich mit UserControl.

Ich bin mir ziemlich sicher, dass ich hier alles eingeschlossen habe; lass es mich wissen, wenn ich etwas vergessen 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} ".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” -class:

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

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

ASCX Fußzeile:

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

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" %>  

Name:

Order Total:

Order Description:

ASCX-Vorlagencodedatei:

 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  Public Function AllControls(Control As Control) As List(Of Control) Return Control.Controls.Flatten End Function  Public Function FindNestedControl(Control As Control, Id As String) As Control Return Control.Controls.Flatten(Function(C) C.ID = Id).SingleOrDefault End Function  Public Function FindNestedControl(Control As Control, Type As Type) As Control Return Control.Controls.Flatten(Function(C) C.GetType = Type).SingleOrDefault End Function  Public Function Flatten(Controls As ControlCollection) As List(Of Control) Flatten = New List(Of Control) Controls.Traverse(Sub(Control) Flatten.Add(Control)) End Function  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  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  Public Function ToFormat(Template As String, ParamArray Values As Object()) As String Return String.Format(Template, Values) End Function  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}{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