How to Mail Merge Word Documents in C

This article was translated from English: Does it need improvement?
Translated
View the article in English

IronWord 透過在 Word 範本中的 MERGEFIELD 替換碼填入您的資料來執行 C# 的合併郵件。這些資料從字典、DataSet 物件或重複區域表中提取,且不需 Microsoft Office Interop。在 Microsoft Word 或任何相容工具中建立的合併欄位可自動檢測。

郵件合併是大規模產生個性化文件的標準方法:如表格信件、發票、證書、合同和報告等,它們共用一個模板但因收件人不同而區別。 不需要手動編輯每個文件,您可以撰寫一個具有合併欄位的 .docx 範本,然後讓 IronWord 從資料來源中填入這些欄位。 每個操作皆可透過 WordDocument.MailMerge 進入點達成。

快速入門:郵件合併Word文件

載入包含 MERGEFIELD 替換碼的範本,將欄位名稱和值的字典傳遞給 Execute,並保存結果。

  1. 使用NuGet套件管理器安裝https://www.nuget.org/packages/IronWord

    PM > Install-Package IronWord
  2. 複製並運行這段程式碼片段。

    WordDocument doc = new WordDocument("template.docx");
    doc.MailMerge.Execute(new Dictionary<string, string> { { "FirstName", "Jane" }, { "Company", "Acme Corp" } });
    doc.SaveAs("output.docx");
  3. 部署以在您的實時環境中測試

    今天就開始在您的專案中使用IronWord,透過免費試用

    arrow pointer


我如何從字典中進行郵件合併?

最簡單的資料來源是以合併欄位名稱為鍵的 IDictionary<string, string>Execute 會替換每個名稱與鍵匹配的欄位。

WordDocument doc = new WordDocument("template.docx");
doc.MailMerge.Execute(new Dictionary<string, string>
{
    { "FirstName", "Jane" },
    { "LastName",  "Smith" },
    { "Company",   "Acme Corp" }
});
doc.SaveAs("output.docx");
WordDocument doc = new WordDocument("template.docx");
doc.MailMerge.Execute(new Dictionary<string, string>
{
    { "FirstName", "Jane" },
    { "LastName",  "Smith" },
    { "Company",   "Acme Corp" }
});
doc.SaveAs("output.docx");
Dim doc As New WordDocument("template.docx")
doc.MailMerge.Execute(New Dictionary(Of String, String) From {
    {"FirstName", "Jane"},
    {"LastName", "Smith"},
    {"Company", "Acme Corp"}
})
doc.SaveAs("output.docx")
$vbLabelText   $csharpLabel

提示字段名稱查找預設狀況不區分大小寫,適用於Microsoft Word。 設置 MailMerge.Options.CaseInsensitiveFieldNames = false 以要求精確大小寫匹配。)]}

您也可以提供兩組平行的字段名稱和值的序列:

doc.MailMerge.Execute(
    new[] { "FirstName", "LastName" },
    new[] { "Jane", "Smith" });
doc.MailMerge.Execute(
    new[] { "FirstName", "LastName" },
    new[] { "Jane", "Smith" });
doc.MailMerge.Execute(  
    New String() { "FirstName", "LastName" },  
    New String() { "Jane", "Smith" })
$vbLabelText   $csharpLabel

Execute(fieldNames, values) 當兩個序列長度不一致時會拋出 ArgumentException

我如何從DataTable或DataRow中進行郵件合併?

當資料來自資料庫或現有 DataSet 時,將 DataTableDataRow 直接傳遞給 Execute。 合併字段名稱對應於列名稱。 Execute(DataTable) 使用表的第一行的值,而 Execute(DataRow) 使用行的父表的欄名。

DataTable table = new DataTable();
table.Columns.Add("FirstName");
table.Columns.Add("LastName");
DataRow row = table.NewRow();
row["FirstName"] = "Jane";
row["LastName"]  = "Smith";
table.Rows.Add(row);

WordDocument doc = new WordDocument("template.docx");
doc.MailMerge.Execute(row);
doc.SaveAs("output.docx");
DataTable table = new DataTable();
table.Columns.Add("FirstName");
table.Columns.Add("LastName");
DataRow row = table.NewRow();
row["FirstName"] = "Jane";
row["LastName"]  = "Smith";
table.Rows.Add(row);

WordDocument doc = new WordDocument("template.docx");
doc.MailMerge.Execute(row);
doc.SaveAs("output.docx");
Imports System.Data

Dim table As New DataTable()
table.Columns.Add("FirstName")
table.Columns.Add("LastName")
Dim row As DataRow = table.NewRow()
row("FirstName") = "Jane"
row("LastName") = "Smith"
table.Rows.Add(row)

Dim doc As New WordDocument("template.docx")
doc.MailMerge.Execute(row)
doc.SaveAs("output.docx")
$vbLabelText   $csharpLabel

我如何填充重複表格區域?

重複區域將一個模板行變成多行,非常適合使用於發票項目或訂單清單。 在範本中,將重複內容包裹在名為 TableStart:RegionNameTableEnd:RegionName 的兩個標記欄位之間。 然後調用 ExecuteWithRegions,每一行匹配表的內容都重複該區域內容一次。

ExecuteWithRegions 接受完整的 DataSet(擴展每個名稱與表匹配的區域)、單個 DataTable(擴展名稱與 dataTable.TableName 匹配的區域),或與 DataTable 一起的區域名稱。

DataTable orders = new DataTable("Orders");
orders.Columns.Add("Item");
orders.Columns.Add("Qty");
orders.Rows.Add("Widget A", "3");
orders.Rows.Add("Widget B", "1");

DataSet ds = new DataSet();
ds.Tables.Add(orders);

WordDocument doc = new WordDocument("invoice-template.docx");
doc.MailMerge.ExecuteWithRegions(ds);
doc.MailMerge.Execute(new Dictionary<string, string> { { "CustomerName", "Jane Smith" } });
doc.SaveAs("invoice.docx");
DataTable orders = new DataTable("Orders");
orders.Columns.Add("Item");
orders.Columns.Add("Qty");
orders.Rows.Add("Widget A", "3");
orders.Rows.Add("Widget B", "1");

DataSet ds = new DataSet();
ds.Tables.Add(orders);

WordDocument doc = new WordDocument("invoice-template.docx");
doc.MailMerge.ExecuteWithRegions(ds);
doc.MailMerge.Execute(new Dictionary<string, string> { { "CustomerName", "Jane Smith" } });
doc.SaveAs("invoice.docx");
Imports System.Data
Imports System.Collections.Generic

Dim orders As New DataTable("Orders")
orders.Columns.Add("Item")
orders.Columns.Add("Qty")
orders.Rows.Add("Widget A", "3")
orders.Rows.Add("Widget B", "1")

Dim ds As New DataSet()
ds.Tables.Add(orders)

Dim doc As New WordDocument("invoice-template.docx")
doc.MailMerge.ExecuteWithRegions(ds)
doc.MailMerge.Execute(New Dictionary(Of String, String) From {{"CustomerName", "Jane Smith"}})
doc.SaveAs("invoice.docx")
$vbLabelText   $csharpLabel

請注意ExecuteWithRegions 僅填充重複區域。) 要填充區域外的標準合併欄位,請在展開區域後調用 Execute(...),如上述所示。

我如何檢查模板的合併字段?

在合併之前,您可以發現模板中包含的內容,這對於驗證模板或動態生成資料源很有用。

  • GetFieldNames() 返回文件順序中的所有值樣式合併欄位名稱,且去重。
  • GetRegionNames() 返回文件中宣告的所有 TableStart 區域的名稱。
  • GetFields() 返回每個欄位,包括 TableEnd 標記,作為 MergeField 物件。
WordDocument doc = new WordDocument("template.docx");
IReadOnlyList<string> fieldNames = doc.MailMerge.GetFieldNames();
IReadOnlyList<string> regionNames = doc.MailMerge.GetRegionNames();
// fieldNames:  ["FirstName", "LastName", "Company"]
// regionNames: ["Orders", "LineItems"]
WordDocument doc = new WordDocument("template.docx");
IReadOnlyList<string> fieldNames = doc.MailMerge.GetFieldNames();
IReadOnlyList<string> regionNames = doc.MailMerge.GetRegionNames();
// fieldNames:  ["FirstName", "LastName", "Company"]
// regionNames: ["Orders", "LineItems"]
Dim doc As New WordDocument("template.docx")
Dim fieldNames As IReadOnlyList(Of String) = doc.MailMerge.GetFieldNames()
Dim regionNames As IReadOnlyList(Of String) = doc.MailMerge.GetRegionNames()
' fieldNames:  ["FirstName", "LastName", "Company"]
' regionNames: ["Orders", "LineItems"]
$vbLabelText   $csharpLabel

每個 MergeField 暴露其 Name,完整的 Instruction 文字如文件中儲存(例如 MERGEFIELD FirstName \* MERGEFORMAT),僅針對區域標記設置的 RegionName(例如來自 "Orders""TableStart:Orders"),以及將欄位歸類為 TableStartTableEnd(重複區域的界限),或 NextRecord(在同一範本主體內推進到下一個資料記錄的 NEXT 欄位)。

我如何控制未匹配字段和空值?

合併行為透過 MailMerge.Options 配置:

選項 Default 行為
RemoveUnusedFields true 移除在資料源中不具匹配鍵的合併字段。 設置為 false 以保持其原地不動。
RemoveUnusedRegions true 移除資料來源中沒有匹配表的 TableEnd 區域。
NullValueReplacement "" 當資料來源為某欄位提供 null 值時替換的文字。
CaseInsensitiveFieldNames true 在匹配字段名稱時忽略大小寫,匹配Microsoft Word的行為。
WordDocument doc = new WordDocument("template.docx");
doc.MailMerge.Options.RemoveUnusedFields = false;
doc.MailMerge.Execute(new Dictionary<string, string> { { "FirstName", "Jane" } });
doc.SaveAs("partial-output.docx");
WordDocument doc = new WordDocument("template.docx");
doc.MailMerge.Options.RemoveUnusedFields = false;
doc.MailMerge.Execute(new Dictionary<string, string> { { "FirstName", "Jane" } });
doc.SaveAs("partial-output.docx");
Dim doc As New WordDocument("template.docx")
doc.MailMerge.Options.RemoveUnusedFields = False
doc.MailMerge.Execute(New Dictionary(Of String, String) From {{"FirstName", "Jane"}})
doc.SaveAs("partial-output.docx")
$vbLabelText   $csharpLabel

如需不使用資料來源實現簡單數值替代,請查看如何在Word文件中替換文字

常見問題

如何在C#中合併郵件Word文件?

使用WordDocument構造函式載入一個包含MERGEFIELD佔位符的Word模板,然後調用doc.MailMerge.Execute使用IDictionary, DataTable或DataRow替換每個名稱與鍵或列匹配的欄位,並使用SaveAs保存結果。在Microsoft Word中建立的合併欄位會自動被檢測到,無需安裝Microsoft Office。

IronWord郵件合併可以使用哪些資料來源?

MailMerge.Execute接受與欄位名稱和值匹配的IDictionary,兩個平行的欄位名稱和值序列,一個DataTable(使用第一行),或一個DataRow(使用其父表的欄)。MailMerge.ExecuteWithRegions接受DataSet或DataTable來展開重複的表格區域。

如何在Word郵件合併中填充重複的表格區域?

將模板中重複的內容包裹在TableStart:RegionName和TableEnd:RegionName合併字段之間,然後用DataSet或DataTable調用MailMerge.ExecuteWithRegions。該區域的內容會根據匹配表格的每一行重複一次。由於ExecuteWithRegions僅填充區域,請在之後調用Execute以填充任何標準合併字段。

我是否可以在合併之前檢查模板的合併欄位?

可以。MailMerge.GetFieldNames以文件順序返回值型別的欄位名稱,GetRegionNames返回TableStart區域名稱,GetFields返回Expose每個欄位的Name, Instruction, Kind (Value, TableStart, TableEnd, or NextRecord), 和RegionName的MergeField物件。

沒有匹配資料的合併字段會怎麼處理?

預設情況下MailMergeOptions.RemoveUnusedFields為true,因此輸出中沒有匹配鍵的資料源欄位會被移除。設置為false以保留它們。當RemoveUnusedRegions為true時,把沒有匹配的TableStart/TableEnd區域移除,並用NullValueReplacement字串替換空值。

郵件合併欄位匹配是否區分大小寫?

不。字段名稱查詢預設不區分大小寫,匹配Microsoft Word的行為。如果需要精確大小寫匹配,將MailMerge.Options.CaseInsensitiveFieldNames設置為false。

Curtis Chau
技術作家

Curtis Chau擁有Carleton大學的電腦科學學士學位,專精於前端開發,擁有Node.js、TypeScript、JavaScript和React的專業知識。Curtis熱衷於建立直觀且美觀的使用者介面,喜愛使用現代框架並建立結構良好、視覺吸引力的手冊。

除了開發,Curtis對物聯網(IoT)有濃厚的興趣,探索創新的方法來整合硬體和軟體。在空閒時間,他喜歡玩遊戲和建立Discord機器人,結合他對技術的熱愛與創造力。

準備開始了嗎?
Nuget 下載 48,355 | 版本: 2026.7 剛剛發布
Still Scrolling Icon

還在滾動?

想要快速證明嗎? PM > Install-Package IronWord
運行範例觀看您的資料變成Word檔。