使用 Razor 產生客製化 Email 內容

多年下來,寫程式發 Email 通知的需求做過 N 回,其中寄給客戶的通知為求美觀常需採用 HTML 格式,而客戶姓名、通知內容等要隨客戶動態改變,嚴格來說也是一種套表。過去我慣用一套自己發明的「特別註記+Replace」做法,例如:

var tmpl = "<span>[$Name$]</span> 您好,您的等侯順位為<span>[$SeqNo$]</span>";
var dict = new Dictionary<string, string>()
{
    ["Name"] = "Jeffrey",
    ["SeqNo"] = "007"
};
var res = System.Text.RegularExpressions.Regex.Replace(
    tmpl, @"\[\$(?<n>.+?)\$\]", m =>
    {
        var n = m.Groups["n"].Value;
        return dict.ContainsKey(n) ? dict[n] : "<" + n + ">";
    });
Console.WriteLine(res);
Console.Read();

土砲做法雖然簡陋,不能 IF ELSE 也沒法跑迴圈,倒也淺顯易懂,就這麼一用十幾年 XD

最近專案又有類似需求打算重操舊業,轉念一想,一帖老方子從 VB6 寫到 C# 6 未免太不長進,該想想有沒有更好的方法。接著馬上有個念頭浮現腦海 - 寫了那麼多 ASP.NET MVC 見識過 CSHTML 的威力,既然信件內文也是 HTML,為什麼不用 Razor 來套版呢?

爬文很快找到順手的兵刃 – RazorEngine,一個允許在任何 .NET 專案(不必是 ASP.NET MVC)使用 Razor 的程式庫:

來個實例,假設我有個中獎通知函要動態改變中獎者姓名、頭銜、獎項內容與日期,若用 Razor 來寫會像這樣(MailTemplate.cshtml):

@model RazorMailTmpl.Models.MailData
 
<!DOCTYPE html>
 
<html>
<head>
    <meta charset="utf-8" />
    <title>Razor Mail Template Demo</title>
    <style>
        li { color: #0000ff; }
        .due { color: orangered; }
    </style>
</head>
<body>
<p>親愛的 @Model.WinnerName @Model.Title,</p>
<p>感謝您參加部落格讀者2017年終摸彩,在此恭喜您獲得以下獎項:</p>
<ul>
    @foreach (var prize in Model.Prizes)
    {
        <li>@prize</li>
    }
</ul>
<p>
    請在 
    <span class="due">@Model.DueDate.ToString("yyyy/MM/dd")</span>
    前連絡謎之聲領取獎項。
</p>
<p>再次恭喜您幸運中獎!</p>
<p>Regards,<br/>黑暗執行緒部落格抽獎小組</p>
</body>
</html>

接著宣告一個 MailData 資料型別,這樣在編輯 cshtml 時才能享受強型別與 Inetllisense 提示:

using System;
 
namespace RazorMailTmpl.Models
{
    public class MailData
    {
        public string WinnerName { get; set; }
        public string Title { get; set; }
        public string[] Prizes { get; set; }
        public DateTime DueDate { get; set; }
 
    }
}

要用 RazorEngine 套表很簡單,先建好 MailData 物件,使用 Engin.Razor.AddTemplate() 載入範本,引擎內建 Cache 機制,接著呼叫 Run 或 Compile 以 Cache Key 取出範本進行編譯運算,很快就能得到套表後的 HTML 字串結果:

using RazorEngine;
using RazorEngine.Templating;
using RazorMailTmpl.Models;
using System;
 
namespace RazorMailTmpl
{
    class Program
    {
        static void Main(string[] args)
        {
            var mailData = new MailData()
            {
                WinnerName = "Jeffrey",
                DueDate = new DateTime(2018, 2, 14),
                Title = "老司機",
                Prizes = new string[]
                {
                    "32G USB 行動碟一支",
                    "Visual Studio 2017 紀念貼紙一組",
                    "法拉帝(Ferretti) 660 豪華遊艇(20米)一艘"
                }
            };
            //將Template存入Cache以利重複使用
            Engine.Razor.AddTemplate(
                "MailBody", // Cache Key
                System.IO.File.ReadAllText("MailTemplate.cshtml"));
            //傳入Cache Key、Model物件型別、Model物件取得套表結果
            var result = 
                Engine.Razor.RunCompile("MailBody", typeof(MailData), mailData);
 
            //除了RunCompile,也可Compile一次,Run多次以提高效能
            Engine.Razor.Compile("MailBody", typeof(MailData));
            Engine.Razor.Run("MailBody", typeof(MailData), mailData);
 
            System.IO.File.WriteAllText("Result.html", result);
        }
    }
}

薑!薑!薑!薑~ 完成。

官方文件的說明挺詳細,相信有 MVC cshtml 經驗的同學很快就能上手,祝大家套表愉快。

歡迎推文分享:
Published 05 February 2018 08:55 PM 由 Jeffrey
Filed under: ,
Views: 6,077



意見

# 阿翰 said on 05 February, 2018 08:01 AM

驚呆了

一直在想T4模板可以使用razor語法的方法

或許這個方式可以,來嘗試看看

# Peter said on 05 February, 2018 08:21 AM

這種方式是不是不支援 @Html.DisplayName 這種 HtmlHelper ?

# Jeffrey said on 05 February, 2018 08:49 PM

to Peter, Html 屬性源自 WebViewPage,其型別為 HtmlHelper 又跟 ViewContext、IViewDataContainer 緊密綑綁,硬要在 RazorEngine 使用並非不可能,但得模擬很多 MVC 機制的細節,複雜遠高於其所帶來的便利性,不划算。

# Alex Lee said on 16 April, 2018 09:21 PM

這東西 除了 EMail 套版之外

還可以 拿來套用 call 第三方 SOAP 服務時所需的 XML

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<February 2018>
SunMonTueWedThuFriSat
28293031123
45678910
11121314151617
18192021222324
25262728123
45678910
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication