Posso configurare modelli HTML / email con ASP.NET?

Sto lavorando a un sito che invierà un numero significativo di email. Voglio impostare sia il testo di intestazione e piè di pagina, o forse anche i modelli per consentire agli utenti di modificare facilmente queste e-mail se necessario.

Se incorporo l’HTML all’interno di stringhe di stringa C #, è brutto e dovrebbero preoccuparsi di eseguire l’escape. Includere file flat per l’intestazione e il piè di pagina potrebbe funzionare, ma qualcosa a riguardo non sembra giusto.

Quale sarebbe l’ideale per utilizzare in qualche .ASPX una pagina .ASPX come modello, quindi basta dire al mio codice di servire quella pagina e usare l’HTML restituito per l’e-mail.

C’è un modo semplice e facile per farlo? C’è un modo migliore per risolvere questo problema?

aggiornato:
Ho aggiunto una risposta che ti consente di utilizzare una pagina standard .aspx come modello di email. Sostituisci semplicemente tutte le variabili come faresti normalmente, usa l’associazione dati, ecc. Quindi acquisisci l’output della pagina e voilà! Hai la tua email HTML!

AGGIORNATO CON CAVEAT !!!:
Stavo usando la class MailDefinition su alcune pagine di aspx bene, ma quando provavo ad usare questa class durante un processo server che era in esecuzione, non funzionava. Credo che sia perché il metodo MailDefinition.CreateMailMessage () richiede un controllo valido come riferimento, anche se non sempre fa qualcosa. Per questo motivo, consiglierei il mio approccio usando una pagina aspx o l’approccio di Mun usando una pagina ascx, che sembra un po ‘meglio.

    Ci sono già un sacco di risposte, ma mi sono imbattuto in un grande articolo su come usare Razor con i modelli di email. Razor è stato spinto con ASP.NET MVC 3, ma MVC non è richiesto per utilizzare Razor. Questa è l’elaborazione piuttosto liscia di fare modelli di email

    Come identifica l’articolo, “La cosa migliore di Razor è che a differenza del suo predecessore (webforms) non è legato all’ambiente web, possiamo facilmente ospitarlo fuori dal Web e utilizzarlo come motore di template per vari scopi”.

    Generazione di e-mail HTML con RazorEngine – Parte 01 – Introduzione

    Sfruttare i modelli di razor al di fuori di ASP.NET: non sono solo per HTML più!

    Modelli di email più intelligenti in ASP.NET con RazorEngine

    StackTranslation QA simile

    Templating usando la nuova API RazorEngine

    Utilizzo di Razor senza MVC

    È ansible utilizzare Razor View Engine all’esterno di asp.net

    Potresti anche provare a caricare un controllo e quindi renderlo a una stringa e impostarlo come Corpo 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(); 

    Potresti quindi build la tua email come al solito:

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

    Il controllo utente potrebbe contenere altri controlli, ad esempio un’intestazione e un piè di pagina, nonché sfruttare funzionalità come l’associazione dati.

    Potresti provare la class MailDefinition

    Se si desidera passare parametri come nomi utente, nomi di prodotti, ecc., È ansible utilizzare NVelocity, il motore di template open source, per produrre l’email / HTML finale.

    Un esempio di modello di NVelocity ( MailTemplate.vm ):

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

    #end

    Generazione del corpo di posta di MailTemplate.vm nella tua applicazione:

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

    Il corpo postale del risultato è:

    Un modello di email di esempio di ScarletGarden .

    Per esempio:

    [Data: 12.02.2009] Nome: Voce 1, Valore: 09

    [Data: 21.02.2009] Nome: Voce 4, Valore: 52

    [Data: 01.03.2009] Nome: Articolo 2, Valore: 21

    [Data: 23.03.2009] Nome: Voce 6, Valore: 24

    Per modificare i modelli, è ansible utilizzare FCKEditor e salvare i modelli nei file.

    Il componente email di mail.dll include il motore del modello di email:

    Ecco la panoramica della syntax:

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

    E il codice che carica il modello, riempie i dati dall’object c # e invia una email:

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

    Puoi ottenere maggiori informazioni sul post del blog del motore di template email .

    Oppure scarica semplicemente il componente email di Mail.dll e provalo.

    Si prega di notare che questo è un prodotto commerciale che ho creato.

    Se la flessibilità è uno dei tuoi prerequisiti, XSLT potrebbe essere una buona scelta, che è completamente supportata da .NET framework e potresti anche permettere all’utente di modificare quei file. Questo articolo ( http://www.aspfree.com/c/a/XML/XSL-Transformations-using-ASP-NET/ ) potrebbe essere utile all’inizio (msdn ha più informazioni a riguardo). Come detto da ScarletGarden NVelocity è un’altra buona scelta, ma preferisco XSLT per il suo supporto per framework .NET “incorporato” e per la sua piattaforma indipendente.

    Certo, puoi creare un modello html e ti consiglio anche un modello di testo. Nel modello puoi semplicemente mettere [BODY] nel posto in cui verrà posizionato il corpo e quindi puoi semplicemente leggere nel modello e sostituire il corpo con il nuovo contenuto. È ansible inviare l’e-mail utilizzando. Mail Class. Devi solo passare attraverso l’invio dell’email a tutti i destinatari dopo aver creato l’e-mail inizialmente. Ha funzionato benissimo per me.

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

    Penso che potresti anche fare qualcosa del genere:

    Crea e .aspx, e mettilo alla fine del metodo OnLoad o chiamalo manualmente.

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

    Non sono sicuro se ci sono potenziali problemi con questo, ma sembra che funzionerebbe. In questo modo, è ansible utilizzare una pagina .aspx con funzionalità complete anziché la class MailDefinition che supporta solo sostituzioni di testo.

    Ecco un’altra alternativa che utilizza le trasformazioni XSL per modelli di posta elettronica più complessi: Invio di email basate su HTML da applicazioni .NET .

    Fai attenzione quando fai questo, i filtri SPAM sembrano bloccare HTML generato da ASP.net, apparentemente a causa di ViewState, quindi se hai intenzione di fare questo assicurati che l’Html prodotto sia pulito.

    Personalmente guarderei nell’uso di Asp.net MVC per ottenere i risultati desiderati. o NVelocity è abbastanza bravo in questo

    Quale sarebbe l’ideale per utilizzare in qualche modo una pagina .ASPX come modello, quindi basta dire al mio codice di servire quella pagina e usare l’HTML restituito per l’e-mail.

    Si potrebbe facilmente build una WebRequest per colpire una pagina ASPX e ottenere il codice HTML risultante. Con un po ‘di lavoro in più, puoi probabilmente farlo senza il WebRequest. Un PageParser e un Response.Filter consentirebbero di eseguire la pagina e catturare l’output … anche se potrebbero esserci alcuni modi più eleganti.

    Avevo un requisito simile su uno dei progetti in cui dovevi inviare un numero enorme di email ogni giorno, e il cliente voleva il controllo completo sui template html per diversi tipi di email.

    a causa dell’elevato numero di e-mail da inviare, la prestazione era una preoccupazione primaria.

    ciò che è venuto fuori è stato il contenuto statico in SQL Server in cui si salva l’intero markup del template html (insieme ai segnaposto, come [UserFirstName], [UserLastName] che vengono sostituiti con dati reali in fase di esecuzione) per diversi tipi di email

    poi abbiamo caricato questi dati nella cache di asp.net – quindi non leggiamo più e più volte i template html – ma solo quando sono effettivamente cambiati

    abbiamo dato al cliente un editor WYSIWYG per modificare questi modelli tramite un modulo web di amministrazione. ogni volta che venivano effettuati degli aggiornamenti, ripristinavamo la cache di asp.net.

    e poi abbiamo avuto una tabella separata per i log delle e-mail – dove ogni email da inviare è stata registrata. questa tabella aveva campi chiamati emailType, emailSent e numberOfTries.

    abbiamo semplicemente eseguito un lavoro ogni 5 minuti per tipi di email importanti (come la registrazione di nuovi membri, la password dimenticata) che devono essere inviati al più presto

    abbiamo eseguito un altro lavoro ogni 15 minuti per tipi di email meno importanti (come email di promozione, email di notizie, ecc.)

    in questo modo non bloccherai il tuo server inviando e-mail non-stop ed elaborerai i messaggi in batch. una volta inviata un’e-mail, imposta il campo emailSent su 1.

    Guarda SubSonic (www.subsonicproject.com). Stanno facendo esattamente questo per generare codice – il modello è ASPX standard e emette c #. Lo stesso metodo sarebbe riutilizzabile per il tuo scenario.

    Si noti che le soluzioni aspx e ascx richiedono un HttpContext corrente, quindi non possono essere utilizzate in modo asincrono (ad esempio nei thread) senza molto lavoro.

    Penso che la risposta facile sia MvcMailer. È il pacchetto NuGet che ti consente di utilizzare il tuo motore di visualizzazione preferito per generare e-mail. Vedi il pacchetto NuGet qui e la documentazione del progetto

    Spero che sia d’aiuto!

    DotLiquid è un’altra opzione. Si specificano valori da un modello di class come {{ user.name }} e quindi in fase di esecuzione si forniscono i dati in tale class e il modello con il markup e si uniranno i valori per te. È simile all’utilizzo del motore di template Razor in molti modi. Supporta cose più complesse come loop e varie funzioni come ToUpper. La cosa bella è che sono “sicuri” in modo che gli utenti che creano i modelli non possano mandare in crash il sistema o scrivere codice non sicuro come si farebbe nel razor: http://dotliquidmarkup.org/try-online

    Se si è in grado di consentire a ASPNET e agli utenti associati il ​​permesso di leggere e scrivere un file, è ansible utilizzare facilmente un file HTML con i segnaposto String.Format() standard ( {0} , {1:C} , ecc.) Per eseguire Questo.

    Leggere semplicemente il file, come una stringa, utilizzando le classi dallo spazio dei nomi System.IO . Dopo aver ottenuto quella stringa, passarla come primo argomento a String.Format() e fornire i parametri.

    Mantieni quella stringa, e usala come corpo dell’e-mail, e in pratica hai finito. Facciamo questo su dozzine di siti (certamente piccoli) oggi e non abbiamo avuto problemi.

    Dovrei notare che questo funziona meglio se (a) non invii miliardi di e-mail alla volta, (b) non stai personalizzando ciascuna e-mail (altrimenti manchi un sacco di stringhe) e (c ) il file HTML stesso è relativamente piccolo.

    Imposta il messaggio e-mail IsBodyHtml = true

    Prendi il tuo object che contiene i tuoi contenuti e-mail Serializza l’object e usa xml / xslt per generare il contenuto html.

    Se vuoi fare AlternateViews fai la stessa cosa che jmein usa solo un modello xslt diverso per creare il contenuto del testo normale.

    uno dei principali vantaggi di questo è se si desidera modificare il layout tutto ciò che è necessario aggiornare il modello xslt.

    Userei una libreria di template come TemplateMachine . questo ti consente di inserire il tuo modello di posta elettronica insieme al testo normale e quindi utilizzare le regole per iniettare / sostituire i valori secondo necessità. Molto simile a ERB in Ruby. Ciò ti consente di separare la generazione del contenuto della posta senza legarti troppo a qualcosa come ASPX, ecc. Una volta che il contenuto è stato generato con questo, puoi spedire via email.

    Mi piace la risposta di Raj. Programmi come ListManager e framework come DNN fanno cose simili, e se è richiesto un facile assembly da parte di utenti non tecnici, gli editor WYSIWYG per modificare l’HTML memorizzato in SQL è un modo per lo più semplice e diretto e può facilmente ospitare le intestazioni di editing indipendentemente dai piè di pagina, ecc., nonché l’utilizzo di token per inserire valori in modo dinamico.

    Una cosa da tenere a mente se si utilizza il metodo sopra (o qualsiasi altro) è di essere rigorosi e attenti a quali tipi di stili e tag si permettono agli editor di inserire. Se ritieni che i browser siano pignoli, aspetta di vedere come i client di posta elettronica differentemente rendono la stessa cosa …

    Simile alla risposta di Canavar, ma invece di NVelocity, utilizzo sempre ” StringTemplate ” che carica il modello da un file di configurazione, o carico un file esterno usando File.ReadAllText () e imposta i valori.

    È un progetto Java, ma la porta C # è solida e l’ho usata in diversi progetti (l’ho usata per il template di email usando il template in un file esterno).

    Le alternative sono sempre buone.

    Ecco un modo semplice utilizzando la class WebClient :

     public static string GetHTMLBody(string url) { string htmlBody; using (WebClient client = new WebClient ()) { htmlBody = client.DownloadString(url); } return htmlBody; } 

    Quindi chiamalo così:

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

    Naturalmente, il tuo CSS dovrà essere allineato per mostrare gli stili della pagina web nella maggior parte dei client di posta elettronica (come Outlook). Se la tua e-mail visualizza contenuti dinamici (ad esempio il nome del cliente), ti consigliamo di utilizzare QueryStrings sul tuo sito Web per popolare i dati. (ad esempio http://www.yourwebsite.com?CustomerName=Bob )

    @bardev offre una buona soluzione, ma sfortunatamente non è l’ideale in tutti i casi. Il mio era uno di loro.

    Sto usando WebForms in un sito Web (giuro che non utilizzerò mai più un sito Web – che PITA) in VS 2013.

    Ho provato il suggerimento di Razor, ma essendo il mio sito Web non ho ricevuto l’importantissimo IntelliSense che l’IDE offre in un progetto MVC. Mi piace anche usare il designer per i miei modelli: un posto perfetto per un UserControl.

    Nix on Razor again.

    Quindi ho creato questa piccola struttura (suggerimenti per @mun per UserControl e @imatoria per Strong Typing). Quasi l’unico potenziale punto problematico che riesco a vedere è che devi stare attento a mantenere il tuo nome file .ASCX in sincrono con il suo nome di class. Se ti allontani, otterrai un errore di runtime.

    FWIW: Nel mio test almeno la chiamata RenderControl () non mi piace come un controllo di pagina, quindi sono andato con UserControl.

    Sono abbastanza sicuro di aver incluso tutto qui; fammi sapere se ho lasciato qualcosa.

    HTH

    Uso:

     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 

    Classe Base:

     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 

    Classe “Fabbrica”:

     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 

    Classe modello:

     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 

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

    ASCIX footer:

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

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

    Name:

    Order Total:

    Order Description:

    Codice file 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 

    Helpers:

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