C# 我可以用ASP.NET设置HTML/电子邮件模板吗?

C# 我可以用ASP.NET设置HTML/电子邮件模板吗?,c#,asp.net,email,templates,C#,Asp.net,Email,Templates,我在一个网站上工作,该网站将发送大量电子邮件。我想设置页眉和页脚文本,或者甚至模板,以便用户在需要时轻松编辑这些电子邮件 如果我将HTML嵌入到C#string文本中,这很难看,而且他们必须担心转义。包括页眉和页脚的平面文件可能会起作用,但感觉有些不对劲 理想的做法是使用.ASPX页面作为模板,然后告诉我的代码为该页面提供服务,并使用电子邮件返回的HTML 有没有一个简单的好方法?有没有更好的办法来解决这个问题 更新: 我添加了一个答案,使您能够使用标准的.aspx页面作为电子邮件模板。只需像平

我在一个网站上工作,该网站将发送大量电子邮件。我想设置页眉和页脚文本,或者甚至模板,以便用户在需要时轻松编辑这些电子邮件

如果我将HTML嵌入到C#string文本中,这很难看,而且他们必须担心转义。包括页眉和页脚的平面文件可能会起作用,但感觉有些不对劲

理想的做法是使用
.ASPX
页面作为模板,然后告诉我的代码为该页面提供服务,并使用电子邮件返回的HTML

有没有一个简单的好方法?有没有更好的办法来解决这个问题

更新:
我添加了一个答案,使您能够使用标准的.aspx页面作为电子邮件模板。只需像平常一样替换所有变量,使用数据绑定等,然后捕获页面的输出,瞧!你有你的HTML电子邮件

更新了警告!!!:

我在一些aspx页面上使用了MailDefinition类,但在运行的服务器进程中尝试使用该类时,失败了。我相信这是因为MailDefinition.CreateMailMessage()方法需要一个有效的控件来引用,即使它并不总是做一些事情。因此,我推荐我使用aspx页面的方法,或者Mun使用ascx页面的方法,这似乎更好一些。

当然可以创建html模板,我也推荐文本模板。在模板中,您只需将[BODY]放在将放置正文的位置,然后您就可以读入模板并用新内容替换正文。你可以发送 电子邮件使用.Nets邮件类。在最初创建电子邮件后,您只需循环发送电子邮件给所有收件人。这对我来说很有魅力

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

如果您能够允许ASPNET和关联用户权限读写文件,则可以轻松使用带有标准
String.Format()
占位符(
{0}
{1:C}
等)的HTML文件来完成此操作

只需使用
System.IO
命名空间中的类以字符串形式读入文件即可。获得该字符串后,将其作为第一个参数传递给
string.Format()
,并提供参数

保留该字符串,并将其用作电子邮件的正文,基本上就完成了。我们今天在几十个(诚然是小的)网站上这样做,没有任何问题


我应该注意的是,如果(a)您一次不发送数以百万计的电子邮件,(b)您不个性化每封电子邮件(否则会消耗大量字符串)和(c)HTML文件本身相对较小,那么这种方法效果最好。

如果您想传递用户名、产品名等参数,可以尝试使用。。。您可以使用开源模板引擎生成最终的电子邮件/HTML

NVelocity模板(MailTemplate.vm)的一个示例:

邮件正文的结果是:

电子邮件模板示例 斯卡利花园

例如:

[日期:12.02.2009]名称:项目1, 价值:09

[日期:21.02.2009]名称:第4项, 价值:52

[日期:2009年3月1日]名称:第2项, 价值:21

[日期:23.03.2009]名称:第6项, 数值:24

对于编辑模板,您可以使用模板并将其保存到文件中

理想的做法是以某种方式使用.ASPX页面作为模板,然后告诉我的代码为该页面提供服务,并使用电子邮件返回的HTML


您可以轻松地构造一个WebRequest来点击一个ASPX页面并获得结果HTML。再多做一点工作,您就可以在不使用WebRequest的情况下完成它。PageParser和Response.Filter将允许您运行页面并捕获输出…尽管可能有一些更优雅的方法。

您可能还希望尝试加载控件,然后将其呈现为字符串,并将其设置为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();
然后,您可以像往常一样构建电子邮件:

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

用户控件可以包含其他控件,如页眉和页脚,还可以利用数据绑定等功能。

设置电子邮件消息IsBodyHtml=true

将包含电子邮件内容的对象序列化 并使用xml/xslt生成html内容

如果要执行AlternateView,请执行与jmein相同的操作,即只使用不同的xslt模板来创建纯文本内容


这样做的一个主要优点是,如果您想更改布局,则只需更新xslt模板即可。

我认为您也可以这样做:

string url = "http://www.yourwebsite.com";
message.Body = GetHTMLBody(url);
创建和.aspx页面,并将其放在OnLoad方法的末尾,或者手动调用它

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

我不确定这是否有任何潜在的问题,但它看起来会起作用。这样,您可以使用功能齐全的.aspx页面,而不是只支持文本替换的MailDefinition类。

如果灵活性是您的先决条件之一,XSLT可能是一个不错的选择,它完全受.NET framework支持,您甚至可以让用户编辑这些文件。这篇文章()可能对一开始很有用(msdn有更多关于它的信息)。
正如ScarlettGarden所说,NVelocity是另一个不错的选择,但我更喜欢XSLT,因为它具有“内置的.NET框架支持和平台无关性”。

在其中一个项目中,我有类似的要求,您必须每天发送大量电子邮件,客户希望完全控制不同类型电子邮件的html模板

由于要发送的电子邮件数量很大,性能是一个主要问题

我们想到的是sql server中的静态内容,您可以在其中保存整个html模板标记(以及
    StringBuilder sb = new StringBuilder();
    StringWriter sw = new StringWriter(sb);
    HtmlTextWriter htmlTW = new HtmlTextWriter(sw);
    this.Render(htmlTW);
<html>
<body>
Hi {FirstName} {LastName},

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

</body>
</html>
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();
public static string GetHTMLBody(string url)
{
    string htmlBody;

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

    return htmlBody;
}
string url = "http://www.yourwebsite.com";
message.Body = GetHTMLBody(url);
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} <james.bond@mi6.co.uk>".ToFormat(oTemplate.Name), "Purchase Receipt", oTemplate.ToHtml)
  End Sub
End Class
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
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
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
<%@ 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>
<%@ Control Language="VB" ClassName="_Footer" %>

</body>
</html>
<%@ 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" />
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
'
' 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