Puis-je configurer des modèles HTML / e-mail avec ASP.NET?

97

Je travaille sur un site qui enverra un nombre important de courriels. Je souhaite configurer le texte d'en-tête et de pied de page, ou peut-être même des modèles pour permettre aux utilisateurs de modifier facilement ces e-mails s'ils en ont besoin.

Si j'intègre le HTML dans des chaînes littérales C #, c'est moche et ils devraient s'inquiéter de s'échapper. Inclure des fichiers plats pour l'en-tête et le pied de page peut fonctionner, mais quelque chose à ce sujet ne semble pas juste.

Quel serait l'idéal d'utiliser une .ASPXpage comme modèle d'une manière ou d'une autre, puis dites simplement à mon code de servir cette page et utilisez le code HTML renvoyé pour l'e-mail.

Existe-t-il un moyen simple et agréable de le faire? Existe-t-il une meilleure façon de résoudre ce problème?

Mise à jour:
j'ai ajouté une réponse qui vous permet d'utiliser une page .aspx standard comme modèle d'e-mail. Remplacez simplement toutes les variables comme vous le feriez normalement, utilisez la liaison de données, etc. Ensuite, capturez simplement la sortie de la page, et le tour est joué! Vous avez votre e-mail HTML!

MISE À JOUR AVEC CAVEAT !!!:
J'utilisais très bien la classe MailDefinition sur certaines pages aspx, mais en essayant d'utiliser cette classe pendant un processus serveur en cours d'exécution, cela a échoué. Je crois que c'était parce que la méthode MailDefinition.CreateMailMessage () nécessite un contrôle valide pour référencer, même si elle ne fait pas toujours quelque chose. Pour cette raison, je recommanderais mon approche en utilisant une page aspx, ou l'approche de Mun utilisant une page ascx, ce qui semble un peu mieux.

John Bubriski
la source
Une autre solution serait d'utiliser AlphaMail pour créer et envoyer vos e-mails en utilisant C # et le langage de modèle Comlang .
Timothy E. Johansson
1
@JohnBubriski: travail que je autour de problèmes de contrôle que vous avez mentionné dans « mis à jour avec emptor » en utilisant new System.Web.UI.Control()comme: mailDefinition.CreateMailMessage("[email protected]", iDictionaryReplacements, new System.Web.UI.Control()).
Theophilus
Oui, je l'ai fait aussi, mais avec l'avènement de Razor, cela devient de moins en moins une bonne idée.
John Bubriski

Réponses:

73

Il y a déjà une tonne de réponses ici, mais je suis tombé sur un excellent article sur la façon d'utiliser Razor avec la création de modèles d'e-mails. Razor a été poussé avec ASP.NET MVC 3, mais MVC n'est pas obligé d'utiliser Razor. C'est un traitement assez fluide de la création de modèles d'e-mails

Comme l'indique l'article, "La meilleure chose de Razor est que, contrairement à son prédécesseur (formulaires Web), il n'est pas lié à l'environnement Web, nous pouvons facilement l'héberger en dehors du Web et l'utiliser comme moteur de modèle à diverses fins."

Générer des e-mails HTML avec RazorEngine - Partie 01 - Introduction

Exploiter les modèles Razor en dehors d'ASP.NET: ils ne sont plus réservés au HTML!

Modèles de courrier électronique plus intelligents dans ASP.NET avec RazorEngine

QA Stackoverflow similaire

Création de modèles à l'aide de la nouvelle API RazorEngine

Utilisation de Razor sans MVC

Est-il possible d'utiliser Razor View Engine en dehors de asp.net

Mike Barlow - BarDev
la source
1
+1 mais soyez prudent si les utilisateurs fournissent les modèles, car ils peuvent exécuter du code C # à partir du modèle, ce qui leur donne beaucoup plus de puissance dans votre système que vous ne le souhaiteriez probablement.
AaronLS
Que pensez-vous de la sécurité. L'utilisation de ce moteur de création de modèles permet peut-être de formater l'ensemble du système de fichiers. J'aime le moteur, mais cela m'oblige à regarder d'autres moteurs.
der_chirurg
55

Vous pouvez également essayer de charger un contrôle, puis de le rendre dans une chaîne et de le définir comme corps 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();

Vous pouvez ensuite construire votre email comme d'habitude:

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

Votre contrôle utilisateur peut contenir d'autres contrôles, tels qu'un en-tête et un pied de page, et également tirer parti de fonctionnalités telles que la liaison de données.

Mun
la source
J'ai en quelque sorte manqué cette réponse la première fois ... gentille. Similaire à ma solution, mais avec un ascx au lieu d'un aspx. Je pense toujours qu'aspx serait mieux, car il offrirait une page complète, au lieu d'un contrôle, mais c'est exactement ce que je pense.
John Bubriski
Oui, vous pouvez utiliser l'une ou l'autre solution ... Ils fonctionnent de la même manière. L'un des avantages de cette approche est la cohérence. Par exemple, vous pouvez montrer à un utilisateur un récapitulatif de commande et inclure exactement la même chose dans l'e-mail de confirmation en réutilisant le même contrôle.
Mun
Point mineur mais il vous manque une ligne pour déclarer un StringBuilder dans le premier bloc de code.
Kirschstein
9
L'exemple n'explique pas où réside le code, est-ce une page?, Car LoadControl est une méthode de page / contrôle.
Shrage Smilowitz
@Mun, vous chargez le contrôle utilisateur dans une variable appelée ctrl, et vous ne le référencez plus jamais dans votre code. Comment cela fonctionne-t-il?
The Muffin Man
35

Vous pouvez essayer la classe MailDefinition

John Sheehan
la source
4
Je veux juste souligner que c'est bon pour les courriels de base, mais pas pour tout ce qui est complexe. La classe MailDefinition ne prend pas en charge la liaison de données. La seule chose qu'il fait vraiment est d'offrir des remplacements de chaînes. Cependant, il est également intégré à l'assistant de création de compte d'adhésion.
John Bubriski
4
La classe MailDefinition doit obtenir un contrôle pour rendre le contenu basé sur un modèle. Pas si bon.
Yuki
17

Si vous souhaitez passer des paramètres tels que les noms d'utilisateurs, les noms de produits, etc., vous pouvez utiliser le moteur de modèle open source NVelocity pour produire vos e-mails / HTML finaux.

Un exemple de modèle 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

Génération du corps du courrier par MailTemplate.vm dans votre application:

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

Le corps du message de résultat est:

Un exemple de modèle d'e-mail par ScarletGarden .

Par exemple:

[Date: 12.02.2009] Nom: Item 1, Valeur: 09

[Date: 21.02.2009] Nom: Item 4, Valeur: 52

[Date: 01.03.2009] Nom: Item 2, Valeur: 21

[Date: 23.03.2009] Nom: Item 6, Valeur: 24

Pour éditer les modèles, vous pouvez peut-être utiliser FCKEditor et enregistrer vos modèles dans des fichiers.

Canavar
la source
7

Le composant de messagerie Mail.dll comprend un moteur de modèle de courrier électronique:

Voici l'aperçu de la syntaxe:

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

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

</body>
</html>

Et le code qui charge le modèle, remplit les données de l'objet c # et envoie un 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();

Vous pouvez obtenir plus d'informations sur l' article de blog du moteur de modèle d'e-mail .

Ou téléchargez simplement le composant de messagerie Mail.dll et essayez-le.

Veuillez noter qu'il s'agit d'un produit commercial que j'ai créé.

Pawel Lesnikowski
la source
6

Si la flexibilité est l'une de vos conditions préalables, XSLT peut être un bon choix, qui est entièrement pris en charge par .NET Framework et vous pourrez même laisser l'utilisateur modifier ces fichiers. Cet article ( http://www.aspfree.com/c/a/XML/XSL-Transformations-using-ASP-NET/ ) pourrait être utile pour commencer (msdn a plus d'informations à ce sujet). Comme l'a dit ScarletGarden NVelocity est un autre bon choix, mais je préfère XSLT pour son support de framework .NET "intégré" et sa plate-forme indépendante.

Everton
la source
Je n'avais jamais pensé à cela auparavant, mais après avoir essayé beaucoup d'autres méthodes, j'ai trouvé que cela fonctionnait très bien en combinaison avec l'ajout de l' IXmlSerializableinterface à mes classes. En quelques lignes, je peux demander à ma classe de se rendre par e-mail.
cjbarth
Urgh, j'ai rêvé de cauchemars sur XSLT. Probablement le langage de programmation / balisage le moins intuitif avec lequel j'ai travaillé. Et impossible à entretenir pour les autres et même pour vous-même 1 mois après le premier codage de votre XSLT.
PussInBoots
5

Je pense que vous pouvez également faire quelque chose comme ceci:

Créez une page .aspx et placez-la à la fin de la méthode OnLoad ou appelez-la manuellement.

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

Je ne sais pas s'il y a des problèmes potentiels avec cela, mais il semble que cela fonctionnerait. De cette façon, vous pouvez utiliser une page .aspx complète, au lieu de la classe MailDefinition qui prend uniquement en charge les remplacements de texte.

John Bubriski
la source
Bien que la classe MailDefinition soit un bon début, elle est un peu rudimentaire. Cette méthode devrait prendre en charge beaucoup plus de fonctionnalités telles que la liaison de données et peut-être même le traçage. Des pensées à ce sujet ou des pièges potentiels?
John Bubriski
Génial! Avez-vous rencontré des problèmes?
John Bubriski
Vous allez donc permettre à vos utilisateurs de modifier les fichiers .aspx lorsqu'ils doivent apporter des modifications au modèle de courrier électronique? J'appellerais cela un problème potentiel.
Bryan
Je ne le pense pas, du moins, pas plus de risque que d'autres modèles qu'ils pourraient modifier. Certes, s'ils savaient ce qu'ils faisaient, ils pourraient causer du tort, mais dans ce cas au moins, c'est peu probable. Ce ne serait pas une page .aspx complexe, mais plutôt un modèle avec des espaces réservés.
John Bubriski
Cela fait un moment, je sais, mais vous souvenez-vous de votre solution finale? Je n'ai pas pu faire fonctionner cette approche particulière avec a Page, du moins lors de l'utilisation d'une méthode d'extension générique pour le rendu. Ainsi je suis passé à UserControl; voir ma réponse ci-dessous. Jusqu'à présent, cela semble bien fonctionner ... Je serais intéressé de savoir comment vous vous êtes débrouillé à l'époque.
InteXX
4

Bien sûr, vous pouvez créer un modèle html et je recommanderais également un modèle de texte. Dans le modèle, vous pouvez simplement mettre [BODY] à l'endroit où le corps serait placé, puis vous pouvez simplement lire le modèle et remplacer le corps par le nouveau contenu. Vous pouvez envoyer l'e-mail à l'aide de .Nets Mail Class. Il vous suffit de boucler l'envoi de l'e-mail à tous les destinataires après avoir créé l'e-mail initialement. A fonctionné à merveille pour moi.

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
la source
Vous pouvez couper le contenu de StreamReader et le remplacer par File.ReadAllText (chemin)
John Sheehan
C'est un bon début, mais ne fournit que des fonctionnalités pour un en-tête et un pied de page. Cela n'aide pas vraiment le corps lui-même.
John Bubriski
Le corps, tout ce que vous avez à faire est d'entrer le contenu du corps souhaité dans les champs HTMLBody et TextBody ou vous pouvez bien sûr les stocker également dans des fichiers
Josh Mein
4

Voici une autre alternative qui utilise des transformations XSL pour des modèles d'e-mails plus complexes: Envoi d'e-mails HTML à partir d'applications .NET .

Alek Davis
la source
2
Comme le lien. Merci! Mon cerveau a commencé à tourner et j'ai réalisé que je pouvais aller plus loin et avoir un modèle XSLT qui prend un objet XML Serializable, ou un contrat de données WCF directement au format html-email. Tout à coup, j'aurais des modèles d'e-mails «fortement typés» à travers de véritables classes sérialisables!
CodingWithSpike
2

Soyez prudent en faisant cela, les filtres SPAM semblent bloquer le HTML généré par ASP.net, apparemment à cause de ViewState, donc si vous allez faire cela, assurez-vous que le HTML produit est propre.

Personnellement, j'envisagerais d'utiliser Asp.net MVC pour obtenir les résultats souhaités. ou NVelocity est assez bon dans ce domaine

danswain
la source
1

L'idéal serait d'utiliser une page .ASPX comme modèle d'une manière ou d'une autre, puis dites simplement à mon code de servir cette page et utilisez le HTML renvoyé pour l'e-mail.

Vous pouvez facilement créer une WebRequest pour accéder à une page ASPX et obtenir le HTML résultant. Avec un peu plus de travail, vous pouvez probablement le faire sans le WebRequest. Un PageParser et un Response.Filter vous permettraient d'exécuter la page et de capturer la sortie ... bien qu'il puisse y avoir des moyens plus élégants.

Mark Brackett
la source
1

J'avais une exigence similaire sur l'un des projets où vous deviez envoyer un grand nombre d'e-mails chaque jour, et le client voulait un contrôle complet sur les modèles html pour différents types d'e-mails.

en raison du grand nombre d'e-mails à envoyer, la performance était une préoccupation majeure.

ce que nous avons proposé, c'est du contenu statique sur le serveur SQL où vous enregistrez le balisage complet du modèle html (avec des espaces réservés, comme [UserFirstName], [UserLastName] qui sont remplacés par des données réelles au moment de l'exécution) pour différents types d'e-mails

puis nous avons chargé ces données dans le cache asp.net - nous ne lisons donc pas les modèles html encore et encore - mais seulement lorsqu'ils sont réellement modifiés

nous avons donné au client un éditeur WYSIWYG pour modifier ces modèles via un formulaire Web d'administration. chaque fois que des mises à jour sont effectuées, nous réinitialisons le cache asp.net.

puis nous avons eu une table séparée pour les journaux de courrier électronique - où chaque courrier électronique à envoyer était enregistré. cette table contenait des champs appelés emailType, emailSent et numberOfTries.

nous avons simplement exécuté un travail toutes les 5 minutes pour les types d'e-mails importants (comme l'inscription d'un nouveau membre, le mot de passe oublié) qui doivent être envoyés dès que possible

nous avons exécuté un autre travail toutes les 15 minutes pour les types d'e-mails moins importants (comme l'e-mail de promotion, l'e-mail d'actualités, etc.)

de cette façon, vous ne bloquez pas votre serveur d'envoyer des e-mails non-stop et vous traitez les e-mails par lots. une fois qu'un e-mail est envoyé, vous définissez le champ emailSent sur 1.

Raj
la source
Mais comment avez-vous géré les collections?
Riri
1
J'ai fait cela aussi et cela a bien fonctionné. De plus, vous pouvez historiquement revenir en arrière et voir les enregistrements des e-mails envoyés, si les rapports sont votre truc.
Mark Glorie
1

Notez que les solutions aspx et ascx nécessitent un HttpContext actuel, donc ne peuvent pas être utilisées de manière asynchrone (par exemple dans les threads) sans beaucoup de travail.

Rosco
la source
1

Je pense que la réponse facile est MvcMailer. C'est le package NuGet qui vous permet d'utiliser votre moteur d'affichage préféré pour générer des e-mails. Voir le package NuGet ici et la documentation du projet

J'espère que ça aide!

Sohan
la source
Hmm, étrange cette réponse n'a pas attiré autant d'attention?!
PussInBoots
1

DotLiquid est une autre option. Vous spécifiez les valeurs d'un modèle de classe en tant que {{ user.name }}, puis au moment de l'exécution, vous fournissez les données de cette classe et le modèle avec le balisage, et il fusionnera les valeurs pour vous. Il est similaire à l'utilisation du moteur de création de modèles Razor à bien des égards. Il prend en charge des choses plus complexes comme les boucles et diverses fonctions comme ToUpper. La bonne chose est que ceux-ci sont "sûrs" afin que l'utilisateur qui crée les modèles ne puisse pas planter votre système ou écrire du code dangereux comme vous le feriez dans razor: http://dotliquidmarkup.org/try-online

AaronLS
la source
0

Si vous êtes en mesure de permettre à la ASPNET et l' autorisation des utilisateurs associés à lire et écrire un fichier, vous pouvez facilement utiliser un fichier HTML à la norme des String.Format()espaces réservés ( {0}, {1:C}, etc.) pour y parvenir.

Simplement lu dans le fichier, sous forme de chaîne, en utilisant les classes de l' System.IOespace de noms. Une fois que vous avez cette chaîne, passez-la comme premier argument à String.Format()et fournissez les paramètres.

Gardez cette chaîne autour et utilisez-la comme corps de l'e-mail, et vous avez essentiellement terminé. Nous faisons cela sur des dizaines de sites (certes petits) aujourd'hui, et n'avons eu aucun problème.

Je dois noter que cela fonctionne mieux si (a) vous n'envoyez pas des millions d'e-mails à la fois, (b) vous ne personnalisez pas chaque e-mail (sinon vous mangez une tonne de chaînes) et (c ) le fichier HTML lui-même est relativement petit.

John Rudy
la source
0

Définissez l'ensemble du message électronique IsBodyHtml = true

Prenez votre objet qui contient le contenu de votre e-mail Sérialisez l'objet et utilisez xml / xslt pour générer le contenu html.

Si vous voulez faire AlternateViews, faites la même chose que jmein n'utilise qu'un modèle xslt différent pour créer le contenu en texte brut.

l'un des principaux avantages à cela est que si vous souhaitez modifier votre mise en page, il vous suffit de mettre à jour le modèle xslt.

Bob le concierge
la source
0

Regardez SubSonic (www.subsonicproject.com). Ils font exactement cela pour générer du code - le modèle est ASPX standard, et il génère c #. La même méthode serait réutilisable pour votre scénario.

jvenema
la source
0

J'utiliserais une bibliothèque de modèles comme TemplateMachine . cela vous permet principalement de mettre votre modèle de courrier électronique avec du texte normal, puis d'utiliser des règles pour injecter / remplacer des valeurs si nécessaire. Très similaire à ERB en Ruby. Cela vous permet de séparer la génération du contenu du courrier sans vous attacher trop à quelque chose comme ASPX, etc., puis une fois que le contenu est généré avec cela, vous pouvez envoyer un courrier électronique.

MikeJ
la source
0

J'aime la réponse de Raj. Des programmes comme ListManager et des frameworks comme DNN font des choses similaires, et si une édition facile par des utilisateurs non techniques est nécessaire, les éditeurs WYSIWYG pour modifier le HTML stocké dans SQL est un moyen simple et direct de procéder et peut facilement accueillir l'édition des en-têtes indépendamment des pieds de page, etc, ainsi que l'utilisation de jetons pour insérer dynamiquement des valeurs.

Une chose à garder à l'esprit si vous utilisez la méthode ci-dessus (ou n'importe laquelle, vraiment) est d'être strict et prudent sur les types de styles et de balises que vous autorisez les éditeurs à insérer. Si vous pensez que les navigateurs sont capricieux, attendez de voir à quel point les clients de messagerie rendent la même chose différemment ...

pseudo
la source
0

Similaire à la réponse de Canavar, mais au lieu de NVelocity, j'utilise toujours " StringTemplate " que je charge le modèle à partir d'un fichier de configuration, ou charge un fichier externe en utilisant File.ReadAllText () et définit les valeurs.

C'est un projet Java mais le port C # est solide et je l'ai utilisé dans plusieurs projets (je l'ai juste utilisé pour la création de modèles de courrier électronique en utilisant le modèle dans un fichier externe).

Les alternatives sont toujours bonnes.

Bryan Bailliache
la source
0

Voici un moyen simple d'utiliser la classe WebClient :

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

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

    return htmlBody;
}

Alors appelez-le comme ceci:

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

Bien sûr, votre CSS devra être intégré afin d'afficher les styles de la page Web dans la plupart des clients de messagerie (comme Outlook). Si votre e-mail affiche un contenu dynamique (ex. Nom du client), je vous recommande d'utiliser QueryStrings sur votre site Web pour remplir les données. (ex. http://www.yourwebsite.com?CustomerName=Bob )

ROFLwTIME
la source
Bien, même si je pense que la plupart des autres réponses le font sans faire de requête Web sur le site, c'est-à-dire avoir à héberger le corps de l'e-mail sur votre site.
Rup
@Rup Compréhensible, mais gardez à l'esprit que les gens veulent souvent voir une «version Web» de l'e-mail de toute façon. Cette solution fonctionne parfaitement pour ce scénario.
ROFLwTIME
0

@bardev fournit une bonne solution, mais malheureusement ce n'est pas idéal dans tous les cas. Le mien était l'un d'entre eux.

J'utilise WebForms dans un site Web (je jure que je n'utiliserai plus jamais un site Web - quel PITA) dans VS 2013.

J'ai essayé la suggestion de Razor, mais le mien étant un site Web, je n'ai pas obtenu le très important IntelliSense fourni par l'EDI dans un projet MVC. J'aime aussi utiliser le concepteur pour mes modèles - un endroit parfait pour un UserControl.

Nix sur Razor à nouveau.

Je suis donc venu avec ce petit framework à la place (chapeau à @mun pour UserControl et @imatoria pour Strong Typing). Le seul problème potentiel que je puisse voir est que vous devez faire attention à garder votre nom de fichier .ASCX synchronisé avec son nom de classe. Si vous vous égarez, vous obtiendrez une erreur d'exécution.

FWIW: Dans mes tests, au moins l'appel RenderControl () n'aime pas un contrôle Page, donc je suis allé avec UserControl.

Je suis presque sûr d'avoir tout inclus ici; faites-moi savoir si j'ai oublié quelque chose.

HTH

Usage:

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

Classe de 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 "Usine":

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 de modèle:

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

En-tête 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>

Pied de page ASCX:

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

</body>
</html>

Modèle 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" />

Fichier de code de modèle 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

Aides:

'
' 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
la source
0

Il suffit de jeter la bibliothèque que j'utilise dans le mix: https://github.com/lukencode/FluentEmail

Il rend les e-mails à l'aide de RazorLight , utilise le style fluide pour créer des e-mails et prend en charge plusieurs expéditeurs prêts à l' emploi . Il est également livré avec des méthodes d'extension pour ASP.NET DI. Simple à utiliser, peu de configuration, avec support texte et HTML.

ahong
la source