2011-07-24 15 views
7

Mam aplikację internetową asp.net, która wysyła kilka e-maili do użytkowników podczas procedury rejestracji. Teraz mam je w linii z kodem, ale chciałbym trzymać je w centralnej lokalizacji, gdzie mogę je edytować bez wchodzenia w VS.Gdzie przechowywać szablony wiadomości e-mail

Jakie jest najlepsze miejsce/format do przechowywania szablonów HTML?

Odpowiedz

13

przechowywać wszystkie moje szablony e-mail na mój internetowej aplikacji ASP.NET MVC jako Razor Widoki, ale jak osadzony zasób w lekkim zespołem, że mogę łatwo odwoływać się od każdego projektu.

Szablon wygląda następująco (zauważ lokalizację):

@model Milkshake.Commerce.Model.Users.UserDto 
@using Milkshake.Core.Internationalization; 
@using Milkshake.Commerce.Model.Meta; 

@if (Language.CurrentForInterface.TwoLetterISOLanguageName.Equals("da")) 
{ 

<h1>Hej @Model.FirstName</h1> 

<p> 
    Din nye brugerkonto til Milkshake Commerce er blevet oprettet. 
</p> 

<p> 
    Gå til dine <a href="http://@ShopSettings.Instance.Domain.TrimEnd('/')/Account">konto indstillinger</a>, brug din e-mail adresse som adgangskode og du vil blive videreført til dine konto indstillinger, hvor du kan ændre din adgangskode. 
</p> 

<p>Ha' en god dag!</p> 
<h2>The Milkshake Commerce Team!</h2> 

} 
else 
{ 

<h1>Hi @Model.FirstName</h1> 

<p> 
    Your new user account for Milkshake Commerce has been created for you. 
</p> 

<p> 
    Go to your <a href="http://@ShopSettings.Instance.Domain.TrimEnd('/')/Account">user account page</a>, use your e-mail address as password and you'll be taken directly to your account page where you can change your password. 
</p> 

<p>Have a nice day!</p> 
<h2>The Milkshake Commerce Team!</h2> 

} 

to mam "master" szablon, zwany _AppEmailTemplate.cshtml:

@using Milkshake.Commerce.Model.Resources 

<!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd> 

<html xmlns="http://www.w3.org/1999/xhtml"> 

    <head> 
     <title></title> 

     <style type="text/css"> 
      body 
      { 
       font-family: Arial, Helvetica; 
      } 
      .layout-wrapper 
      { 
       width: 600px; 
      } 
      .header 
      { 
       background-color: #242225; 
      } 
      .header img 
      { 
       display: block; 
      } 
      .content 
      { 
       background-color: #ffffff; padding: 10px 20px; border: 10px solid #eaeaea; border-top: none; 
      } 
      .footer 
      { 
       padding: 20px; padding-top: 5px; font-size: 10px; color: #cccccc; 
      } 
      p 
      { 
       font-size: 14px; 
      } 
      p.company-details 
      { 
       font-size: 12px; 
      } 
      h1 
      { 
       font-size: 20px; 
      } 
      h2 
      { 
       font-size: 16px; 
      } 
     </style> 
     <style type="text/css" id="mobile"> 
      @@media only screen and (max-device-width: 480px) { 
       body 
       { 
       } 
       .layout-wrapper 
       { 
        width: 480px !important; 
       } 
       .header 
       { 
        background-color: transparent !important; 
       } 
       .header img 
       { 
        width: 480px !important; 
       } 
       .content 
       { 
        border: none !important; 
       } 
       .footer 
       { 
        padding-top: 15px !important; 
       } 
       p 
       { 
        font-size: 22px !important; 
       } 
       h1 
       { 
        font-size: 28px !important; 
       } 
       h2 
       { 
        font-size: 24px !important; 
       } 
      } 
     </style> 
    </head> 

    <body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0" bgcolor="#f1f1f1"> 

     <table width="100%" cellpadding="0" cellspacing="0" bgcolor="#f1f1f1"> 
      <tr> 
       <td valign="top" align="center"> 

        <table cellpadding="0" cellspacing="0" width="100%" height="80"> 
         <tr> 
          <td class="header" align="center"> 
           <table cellpadding="0" cellspacing="0" width="600" height="80" class="layout-wrapper" style="width: 600px;"> 
            <tr> 
             <td> 
              <img src="http://example.com/email-header.png" alt="Milkshake Commerce" /> 
             </td> 
            </tr> 
           </table> 
          </td> 
         </tr> 
        </table> 

        <table cellpadding="0" cellspacing="0" width="600" class="layout-wrapper"> 
         <tr> 
          <td class="content" align="left"> 
           #¤#¤CONTENTSECTION#¤#¤ 
          </td> 
         </tr> 
         <tr> 
          <td class="footer" align="left"> 
           <p>@Text.appEmailDisclaimer</p> 
           <p>@Text.appEmailFooterAd.UrlDecode()</p> 
           <p class="company-details"><i>Company name etc.</i></p> 
          </td> 
         </tr> 
        </table> 

       </td> 
      </tr> 
     </table> 

    </body> 

</html> 

Aby faktycznie wysłać wiadomość e-mail, I użyj RazorEngine do renderowania:

public void SendSystemEmail<T>(string templateName, string subject, string fromName, string recipientEmail, T model) 
{ 
    dynamic template = this.GetEmailTemplate(templateName); 
    string layoutBody = RazorEngine.Razor.Parse(template.Layout as string, model); 
    string emailBody = RazorEngine.Razor.Parse(template.Template as string, model); 

    emailBody = layoutBody.Replace(CONTENTSECTIONREPLACETOKEN, emailBody); 

    PreMailer.Net.PreMailer pm = new PreMailer.Net.PreMailer(); 
    emailBody = pm.MoveCssInline(emailBody, true); 

    EmailDto email = new EmailDto(); 
    email.Body = emailBody; 
    email.IsBodyHtml = true; 
    email.FromEmail = "[email protected]"; 
    email.ReplyToEmail = email.FromEmail; 
    email.FromName = fromName; 
    email.RecipientEmail = recipientEmail; 
    email.Subject = subject; 
    email.Type = EmailTypes.Transactional; 

    if (String.IsNullOrWhiteSpace(email.FromName)) 
    { 
     email.FromName = "Milkshake Software"; 
    } 

    this.SendMailMessages(new List<EmailDto>() { email }, false); 
} 

Powyższy kod wykorzystuje mój własny EmailDto objec t. Tutaj możesz bezpośrednio utworzyć instancję [MailMessage][2] bezpośrednio i wysłać ją przy użyciu [SmtpClient][3].

Ponadto, aby uzyskać najlepsze renderowanie we wszystkich klientach poczty e-mail, używam własnej biblioteki PreMailer.Net, aby przenieść wszystkie CSS w linii. Przeczytaj my blog post here, aby uzyskać więcej informacji.(Kod jest Github)

GetEmailTemplate robi to:

/// <summary> 
/// Gets the email template. 
/// </summary> 
/// <param name="templateName">Name of the template.</param> 
/// <returns>Returns the e-mail template.</returns> 
private dynamic GetEmailTemplate(string templateName) 
{ 
    string masterTemplateContents = this.GetTemplateFileContents("_AppEmailTemplate.cshtml"); 
    string templateContents = this.GetTemplateFileContents(templateName + ".html.cshtml"); 

    return new { Layout = masterTemplateContents, Template = templateContents }; 
} 

/// <summary> 
/// Gets the template file contents. 
/// </summary> 
/// <param name="templateFileName">The name of the template file.</param> 
/// <returns>Returns the contents of the template file.</returns> 
private string GetTemplateFileContents(string templateFileName) 
{ 
    return this.GetEmailFileContents("Templates", templateFileName); 
} 

/// <summary> 
/// Gets the email file contents. 
/// </summary> 
/// <param name="lastNamespaceToken">The last namespace token.</param> 
/// <param name="templateFileName">The name of the template file.</param> 
/// <returns> 
/// Returns the contents of the template file. 
/// </returns> 
private string GetEmailFileContents(string lastNamespaceToken, string templateFileName) 
{ 
    var assembly = Assembly.GetExecutingAssembly(); 

    if (assembly != null) 
    { 
     StringBuilder sb = new StringBuilder(); 

     using (StreamReader sr = new StreamReader(assembly.GetManifestResourceStream(String.Format("MyApp.BusinessLogic.Communication.{0}.{1}", lastNamespaceToken, templateFileName)))) 
     { 
      while (!sr.EndOfStream) 
      { 
       var line = sr.ReadLine(); 

       if (!line.StartsWith("@model")) 
       { 
        sb.AppendLine(line); 
       } 
      } 
     } 

     return sb.ToString(); 
    } 

    return null; 
} 
0

To zależy od tego, jak często szablony się zmienią i od kogo zostaną zmienione. Np:

Zmienione przez użytkowników aplikacji, zmiany są pilne i potencjalnie częste:

  • Prawdopodobnie najlepiej przechowywane w bazie danych i ładowany za każdym razem, e-mail zostanie wysłana.

Zmienione przez deweloperów (czyli Ty), zmiany są rzadkie i nie urgen:

  • pliki tekstowe na serwerze internetowym, załadować je do pamięci podręcznej i przechowywać je tam, tylko przeładunku je gdy bufor spadnie lub aplikacja uruchomi się ponownie.
0

Możesz przechowywać szablony wiadomości e-mail w numerze .html file. Następnie sformatuj go w sposób, który będzie obsługiwał parametr, który chcesz uwzględnić. na przykład

<head> 
<title></title> 
</head> 
<body> 
    Hello <!--Name--> , 
    This is a test template 
    User Name: <!--UserName--> 
    ............................. 
    ............................. 
</body> 
</html> 

Kiedykolwiek wysłać e-mail do użytkownika, który chcesz ustawić szablon jako konkretnego użytkownika, dzięki czemu można zastąpić parametr przy starcie.

1

Polecam przechowywanie szablonów wiadomości e-mail w pliku XML, który pozwoli na skalowalność w przyszłości poprzez dodanie atrybutów do szablonu poczty, a także umożliwi łatwą edycję.

+0

Użyłem plików xml na mojej stronie internetowej i dało to radykalne skalowanie funkcji obsługiwanych przez szablony e-mail. –

0

Dziękuję wszystkim za dając wgląd w jaki sposób są one obsługi. Zebrałem tutaj dużo wiedzy. Lubiłem @MartinHN używając parsera Razor z konkretnym modelem danych.

Jednak coś, co nie zadziałało zbyt dobrze dla mnie.

Wymagania:

  • muszę przechowywać szablony e-mail tak, że mogę wyświetlać to samo
    Partnerów w każdej chwili. Dlatego powinien on być dostępny do przeglądania intranetu - najlepiej poprzez stronę internetową Sae jako hostowany interfejs API.

  • Projektanci front endowi powinni mieć możliwość łatwej modyfikacji szablonów. Dlatego chcę przechowywać go w prostym formacie HTML, aby projektant nie musiał przechodzić przez zbyt wiele technicznych szczegółów.

  • Szablony wiadomości e-mail powinny być łatwo dostępne dla modyfikacji dla administratorów (wymagania na przyszłość). W niedalekiej przyszłości pojawią się różne powiadomienia SMS, ekranowe. Dlatego szablony różnią się od siebie.

podstawie tych wymagań, zrobiłem następujący:

  1. Ponieważ używałem MVC, stworzyłem folder o nazwie "statyczne", czyli dostępne mają być przeglądane bezpośrednio (i silnik MVC/http handler wykluczyć ten folder z wykonywania swoich działań MVC).

    Z takim podejściem mogę łatwo osiągnąć pierwszego wymogu i mogę wysłać moje odnośnik do podmiotami jak http://api.aksdfjl.com/static/welcomeemailtemplate.html

  2. Każdy szablon email dał własny html, więc łatwo było dla projektanta do uzyskać dostęp do tego samego i odsyłać go do repozytorium jako skrótu do mojego folderu repozytorium. HTML ma wbudowany CSS i jest całkowicie niezależny html na pocztę elektroniczną.

  3. Ostatnim głównym wymaganiem było zachowanie tego projektu, a użytkownik może je zmodyfikować. Cóż, zdecydowanie nie chcę w ogóle zajmować się systemem plików. To, co zrobiłem, to teraz te powiadomienia do bazy danych, a ja je zainicjuję raz. Następnie panel administracyjny ma edytor wysiwyg html, który może dać im szybki podgląd, a także kontrolę nad tym, co powinien wysłać.

Teraz chciałem się upewnić, że przyszłe wymagania są łatwo obchodzić, a ponieważ moja firma wprowadzając różne powiadomień dla różnych trybach, takich jak e-mail, ekran powiadomień SMS. Zdecydowałem się rozszerzyć projekt oprogramowania za pomocą XML inicjalizatora szablonu, który przechowuje te odpowiedzi.

Matka wszystkich szablonów o nazwie - MessageTemplates.xml przechowuje różne informacje potrzebne do zainicjowania różnych typów szablonów, np. e-mail, sms, screen i in.

enter image description here

Oto jak kod wygląda teraz.

[HttpGet] 
     [Route("applications/initializenotificationtemplate")] 
     public IHttpActionResult InitializeNotificationTemplate() 
     { 
      return 
       InitializeNotificationTemplate(Path.Combine(HostingEnvironment.ApplicationPhysicalPath, 
        @"Static\InitializeData\MessageTemplates.xml")); 
     } 




[NonAction] 
     public IHttpActionResult InitializeMailTemplate(string filePath) 
     { 
      try 
      { 
       _applicationService.InitializeTemplate(filePath); 
       return Ok("Application Notification templates are initialized."); 
      } 
      catch (Exception ex) 
      { 
       return InternalServerError(ex); 
      } 
     } 

_applicationService.InitializeTemplate ma następującą definicję:

public bool InitializeTemplate(string filePath) 
     { 
      if (string.IsNullOrEmpty(filePath)) 
      { 
       throw new ArgumentNullException("File Path"); 
      } 

      if (!File.Exists(filePath)) 
      { 
       throw new FileNotFoundException(filePath); 
      } 


      var data = _notificationTemplateService.Get(); 
      var exceptionMessages = string.Empty; 

      if (data != null) 
      { 
       var historicalTemplates = data.ToList(); 
       historicalTemplates.ForEach((d) => _notificationTemplateService.Delete(d, out exceptionMessages)); 
      } 

      XDocument xmlDocument = XDocument.Load(filePath); 
      IEnumerable<NotificationTemplate> templates = (from template in xmlDocument.Descendants("Template") 
                  select new NotificationTemplate() 
                  { 
                   Title = template.Element("Subject").Value, 
                   Description = template.Element("Body").Value, 
                   Type = (NotificationTypeOptions)Enum.Parse(typeof(NotificationTypeOptions), template.Element("Type").Value, true), 
                   Category = (NotificationCategoryOptions)Enum.Parse(typeof(NotificationCategoryOptions), template.Attribute("category").Value, true), 
                  }).ToList(); 

      foreach (var t in templates) 
      { 
       var path = Path.Combine(Path.GetDirectoryName(filePath), Regex.Replace(t.Description, @"\t|\n|\r| ", "")); 
       if (File.Exists(path)) 
       { 
        StreamReader reader = new StreamReader(path); 
        t.Description = reader.ReadToEnd(); 
       } 
       else 
       { 
        t.Description = string.Empty; 
       } 
      } 

      return _notificationTemplateService.InsertRange(templates, out exceptionMessages); 
     } 

to jak wygląda mój model, który jest taki sam jak pierwszy model bazy danych (code - podejście EF).

public class NotificationTemplate : IdentityBase 
    { 
     public string Category { get; set; } 
     public NotificationTypeOptions Type { get; set; } 
     public string Title { get; set; } 
     public string Description { get; set; } 

     public NotificationTemplate() 
     { 
      Type = NotificationTypeOptions.Email; 
     } 
    } 

[Flags] 
    public enum NotificationTypeOptions 
    { 
     Email = 0, 
     Screen = 1, 
    } 

Po raz pierwszy, gdy zainstalować mój wniosek Wzywam zainicjować wywołanie API, które instalują swoje szablony powiadomień w bazie danych i dostępne i gotowe do użycia są wszystkie inne opcje.

Dzięki takiemu podejściu sprawiłem, że wszyscy byli zadowoleni w organizacji i ma wielką siłę, aby rozszerzyć tę dziedzinę, dzięki czemu łatwiej jest mi również wprowadzić nowe szablony.

Powiązane problemy