Aspose.Words for .NET下载地址 https://soft51.cc/software/175811283999782847
邮件合并(Mail Merge)是文档处理中的重要功能,它将固定的模板内容与动态数据相结合,批量生成个性化文档。Aspose.Words for .NET 提供了强大的邮件合并 API,本教程将全面介绍其核心概念和实际应用。
邮件合并涉及三个核心要素:
using Aspose.Words;
using System.Data;
public static void BasicMailMerge()
{
// 创建文档模板
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.Write("尊敬的 ");
builder.InsertField("MERGEFIELD CustomerName \\* MERGEFORMAT", "«CustomerName»");
builder.Write(" 先生/女士:\n\n");
builder.Write("您的订单 ");
builder.InsertField("MERGEFIELD OrderNumber \\* MERGEFORMAT", "«OrderNumber»");
builder.Write(" 金额为 ");
builder.InsertField("MERGEFIELD Amount \\# \"¥#,##0.00\"", "«Amount»");
builder.Write(" 已确认。\n\n谢谢!");
// 创建数据源
DataTable data = new DataTable();
data.Columns.Add("CustomerName");
data.Columns.Add("OrderNumber");
data.Columns.Add("Amount", typeof(decimal));
data.Rows.Add("张三", "ORD-001", 1299.00m);
data.Rows.Add("李四", "ORD-002", 2599.50m);
data.Rows.Add("王五", "ORD-003", 999.99m);
// 执行合并
doc.MailMerge.Execute(data);
doc.Save("basic_merge_result.docx");
}
public static void ConfigureMergeOptions()
{
Document doc = new Document("template.docx");
// 配置合并选项
doc.MailMerge.CleanupOptions =
MailMergeCleanupOptions.RemoveEmptyParagraphs |
MailMergeCleanupOptions.RemoveContainingFields |
MailMergeCleanupOptions.RemoveUnusedFields;
doc.MailMerge.UseNonMergeFields = true;
doc.MailMerge.PreserveUnusedTags = false;
doc.MailMerge.TrimWhitespaces = true;
// 字段映射
doc.MailMerge.MappedDataFields.Add("CustomerName", "客户姓名");
DataTable data = CreateSampleData();
doc.MailMerge.Execute(data);
doc.Save("configured_merge.docx");
}
public static void UseDataTable()
{
Document doc = new Document("employee_template.docx");
// 创建结构化数据
DataTable employees = new DataTable("Employees");
employees.Columns.Add("ID", typeof(int));
employees.Columns.Add("Name");
employees.Columns.Add("Department");
employees.Columns.Add("Salary", typeof(decimal));
employees.Columns.Add("HireDate", typeof(DateTime));
employees.Rows.Add(1, "张三", "技术部", 8000.00m, DateTime.Parse("2020-01-15"));
employees.Rows.Add(2, "李四", "销售部", 7500.00m, DateTime.Parse("2019-08-20"));
employees.Rows.Add(3, "王五", "人事部", 6800.00m, DateTime.Parse("2021-03-10"));
doc.MailMerge.Execute(employees);
doc.Save("employee_reports.docx");
}
public class CustomerDataSource : IMailMergeDataSource
{
private readonly List<Customer> customers;
private int currentIndex = -1;
public CustomerDataSource(List<Customer> customers)
{
this.customers = customers;
}
public string TableName => "Customers";
public bool MoveNext()
{
currentIndex++;
return currentIndex < customers.Count;
}
public bool GetValue(string fieldName, out object fieldValue)
{
fieldValue = null;
if (currentIndex < 0 || currentIndex >= customers.Count)
return false;
var customer = customers[currentIndex];
switch (fieldName.ToLower())
{
case "name":
fieldValue = customer.Name;
return true;
case "email":
fieldValue = customer.Email;
return true;
case "city":
fieldValue = customer.City;
return true;
case "totalpurchases":
fieldValue = customer.TotalPurchases.ToString("C");
return true;
}
return false;
}
public IMailMergeDataSource GetChildDataSource(string tableName)
{
return null;
}
}
public class Customer
{
public string Name { get; set; }
public string Email { get; set; }
public string City { get; set; }
public decimal TotalPurchases { get; set; }
}
// 使用自定义数据源
public static void UseCustomDataSource()
{
Document doc = new Document("customer_template.docx");
var customers = new List<Customer>
{
new Customer { Name = "张三", Email = "zhang@example.com", City = "北京", TotalPurchases = 15000 },
new Customer { Name = "李四", Email = "li@example.com", City = "上海", TotalPurchases = 22000 }
};
var dataSource = new CustomerDataSource(customers);
doc.MailMerge.ExecuteWithRegions(dataSource);
doc.Save("custom_source_result.docx");
}
using System.Data.SqlClient;
public static void UseDatabaseSource()
{
Document doc = new Document("database_template.docx");
string connectionString = "Server=.;Database=Sales;Integrated Security=true";
string query = "SELECT CustomerName, OrderNumber, OrderDate, Amount FROM Orders WHERE Status = 'Completed'";
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlDataAdapter adapter = new SqlDataAdapter(query, connection);
DataTable orders = new DataTable();
adapter.Fill(orders);
doc.MailMerge.Execute(orders);
doc.Save("database_merge_result.docx");
}
}
public static void InsertMergeFields()
{
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
// 基本字段
builder.Write("客户:");
builder.InsertField("MERGEFIELD CustomerName", "«客户姓名»");
builder.WriteBreak();
// 格式化数字字段
builder.Write("金额:");
builder.InsertField("MERGEFIELD Amount \\# \"¥#,##0.00\"", "«金额»");
builder.WriteBreak();
// 格式化日期字段
builder.Write("日期:");
builder.InsertField("MERGEFIELD OrderDate \\@ \"yyyy年M月d日\"", "«日期»");
doc.Save("formatted_template.docx");
}
public static void ConditionalFields()
{
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.Write("客户等级:");
// 根据消费金额确定等级
builder.InsertField(
"IF { MERGEFIELD TotalAmount } >= 10000 \"VIP客户\" " +
"{ IF { MERGEFIELD TotalAmount } >= 5000 \"高级客户\" \"普通客户\" }",
"«客户等级»");
builder.WriteBreak();
builder.Write("享受折扣:");
builder.InsertField(
"IF { MERGEFIELD TotalAmount } >= 10000 \"9折\" " +
"{ IF { MERGEFIELD TotalAmount } >= 5000 \"9.5折\" \"无折扣\" }",
"«折扣»");
// 测试数据
DataTable table = new DataTable();
table.Columns.Add("CustomerName");
table.Columns.Add("TotalAmount", typeof(decimal));
table.Rows.Add("张三", 15000m);
table.Rows.Add("李四", 7500m);
table.Rows.Add("王五", 3000m);
doc.MailMerge.Execute(table);
doc.Save("conditional_result.docx");
}
public class CustomFieldHandler : IFieldMergingCallback
{
public void FieldMerging(FieldMergingArgs args)
{
switch (args.FieldName.ToLower())
{
case "customergrade":
HandleCustomerGrade(args);
break;
case "formattedprice":
HandleFormattedPrice(args);
break;
}
}
public void ImageFieldMerging(ImageFieldMergingArgs args)
{
if (args.FieldName == "CompanyLogo" && File.Exists("logo.png"))
{
args.ImageFileName = "logo.png";
args.ImageWidth = new MergeFieldImageDimension(100);
args.ImageHeight = new MergeFieldImageDimension(50);
}
}
private void HandleCustomerGrade(FieldMergingArgs args)
{
if (args.FieldValue is decimal totalPurchase)
{
string grade = totalPurchase switch
{
>= 10000 => "钻石客户",
>= 5000 => "黄金客户",
>= 2000 => "银牌客户",
_ => "普通客户"
};
args.Text = grade;
// 设置文本颜色
Run run = (Run)args.Field.End.PreviousSibling;
run.Font.Color = grade switch
{
"钻石客户" => System.Drawing.Color.Purple,
"黄金客户" => System.Drawing.Color.Gold,
"银牌客户" => System.Drawing.Color.Silver,
_ => System.Drawing.Color.Black
};
}
}
private void HandleFormattedPrice(FieldMergingArgs args)
{
if (args.FieldValue is decimal price)
{
args.Text = $"¥{price:N2}";
if (price > 1000)
{
Run run = (Run)args.Field.End.PreviousSibling;
run.Font.Color = System.Drawing.Color.Red;
run.Font.Bold = true;
}
}
}
}
// 使用自定义处理器
public static void UseCustomHandler()
{
Document doc = new Document("custom_template.docx");
doc.MailMerge.FieldMergingCallback = new CustomFieldHandler();
DataTable data = new DataTable();
data.Columns.Add("CustomerGrade", typeof(decimal));
data.Columns.Add("FormattedPrice", typeof(decimal));
data.Rows.Add(15000m, 2500.00m);
data.Rows.Add(3000m, 899.99m);
doc.MailMerge.Execute(data);
doc.Save("custom_handled_result.docx");
}
public static void RegionMerging()
{
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
// 创建发票模板
builder.Write("发票号:");
builder.InsertField("MERGEFIELD InvoiceNumber", "«发票号»");
builder.WriteBreak();
builder.Write("客户:");
builder.InsertField("MERGEFIELD CustomerName", "«客户名»");
builder.WriteBreak();
builder.WriteBreak();
// 创建产品明细表格
Table table = builder.StartTable();
builder.InsertCell();
builder.Write("产品");
builder.InsertCell();
builder.Write("数量");
builder.InsertCell();
builder.Write("单价");
builder.InsertCell();
builder.Write("小计");
builder.EndRow();
// 可重复的产品行
builder.InsertCell();
builder.Write("«TableStart:Products»");
builder.InsertField("MERGEFIELD ProductName", "«产品名»");
builder.InsertCell();
builder.InsertField("MERGEFIELD Quantity", "«数量»");
builder.InsertCell();
builder.InsertField("MERGEFIELD UnitPrice \\# \"¥#,##0.00\"", "«单价»");
builder.InsertCell();
builder.InsertField("MERGEFIELD Subtotal \\# \"¥#,##0.00\"", "«小计»");
builder.Write("«TableEnd:Products»");
builder.EndRow();
builder.EndTable();
builder.WriteBreak();
builder.Write("总计:");
builder.InsertField("MERGEFIELD TotalAmount \\# \"¥#,##0.00\"", "«总计»");
// 创建分层数据
DataSet dataSet = new DataSet();
// 主表
DataTable invoice = new DataTable("Invoice");
invoice.Columns.Add("InvoiceNumber");
invoice.Columns.Add("CustomerName");
invoice.Columns.Add("TotalAmount", typeof(decimal));
invoice.Rows.Add("INV-2024-001", "ABC公司", 3500.00m);
// 明细表
DataTable products = new DataTable("Products");
products.Columns.Add("ProductName");
products.Columns.Add("Quantity", typeof(int));
products.Columns.Add("UnitPrice", typeof(decimal));
products.Columns.Add("Subtotal", typeof(decimal));
products.Rows.Add("笔记本电脑", 2, 1500.00m, 3000.00m);
products.Rows.Add("无线鼠标", 5, 100.00m, 500.00m);
dataSet.Tables.Add(invoice);
dataSet.Tables.Add(products);
doc.MailMerge.ExecuteWithRegions(dataSet);
doc.Save("invoice_with_regions.docx");
}
public static void NestedRegions()
{
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.Write("销售报告\n\n");
// 销售代表区域
builder.Write("«TableStart:SalesReps»");
builder.Write("销售代表:");
builder.InsertField("MERGEFIELD RepName", "«代表姓名»");
builder.WriteBreak();
builder.Write("总销售额:");
builder.InsertField("MERGEFIELD TotalSales \\# \"¥#,##0.00\"", "«总销售额»");
builder.WriteBreak();
builder.WriteBreak();
// 客户明细(嵌套区域)
builder.Write("客户明细:\n");
builder.Write("«TableStart:Customers»");
builder.Write(" - ");
builder.InsertField("MERGEFIELD CustomerName", "«客户名»");
builder.Write(":");
builder.InsertField("MERGEFIELD CustomerSales \\# \"¥#,##0.00\"", "«销售额»");
builder.WriteBreak();
builder.Write("«TableEnd:Customers»");
builder.WriteBreak();
builder.Write("«TableEnd:SalesReps»");
// 创建嵌套数据
DataSet dataSet = new DataSet();
DataTable reps = new DataTable("SalesReps");
reps.Columns.Add("RepName");
reps.Columns.Add("TotalSales", typeof(decimal));
reps.Columns.Add("RepID", typeof(int));
reps.Rows.Add("张三", 50000m, 1);
reps.Rows.Add("李四", 60000m, 2);
DataTable customers = new DataTable("Customers");
customers.Columns.Add("CustomerName");
customers.Columns.Add("CustomerSales", typeof(decimal));
customers.Columns.Add("RepID", typeof(int));
customers.Rows.Add("ABC公司", 30000m, 1);
customers.Rows.Add("DEF企业", 20000m, 1);
customers.Rows.Add("GHI集团", 35000m, 2);
customers.Rows.Add("JKL公司", 25000m, 2);
dataSet.Tables.Add(reps);
dataSet.Tables.Add(customers);
// 建立关系
DataRelation relation = new DataRelation("RepCustomers",
reps.Columns["RepID"], customers.Columns["RepID"]);
dataSet.Relations.Add(relation);
doc.MailMerge.ExecuteWithRegions(dataSet);
doc.Save("nested_regions_report.docx");
}
public static void PreviewMerge()
{
Document template = new Document("preview_template.docx");
DataTable data = new DataTable();
data.Columns.Add("CustomerName");
data.Columns.Add("ProductName");
data.Columns.Add("Amount", typeof(decimal));
data.Rows.Add("张三", "笔记本", 5999m);
data.Rows.Add("李四", "手机", 2999m);
data.Rows.Add("王五", "平板", 1999m);
// 预览第一条记录
Document preview = template.Clone();
DataView singleRecord = new DataView(data);
singleRecord.RowFilter = "CustomerName = '张三'";
preview.MailMerge.Execute(singleRecord.ToTable());
preview.Save("preview_sample.docx");
// 获取合并字段信息
string[] fields = template.MailMerge.GetFieldNames();
Console.WriteLine("模板字段:" + string.Join(", ", fields));
// 完整合并
Document full = template.Clone();
full.MailMerge.Execute(data);
full.Save("preview_complete.docx");
Console.WriteLine($"预览完成,共处理 {data.Rows.Count} 条记录");
}
public static void MultipleFormats()
{
Document template = new Document("multi_template.docx");
DataTable data = new DataTable();
data.Columns.Add("CompanyName");
data.Columns.Add("ContactName");
data.Columns.Add("Email");
data.Rows.Add("ABC科技", "张经理", "zhang@abc.com");
data.Rows.Add("DEF企业", "李总", "li@def.com");
for (int i = 0; i < data.Rows.Count; i++)
{
Document doc = template.Clone();
DataRow row = data.Rows[i];
// 单行数据
DataTable single = data.Clone();
single.Rows.Add(row.ItemArray);
doc.MailMerge.Execute(single);
string fileName = $"company_{i + 1}_{row["CompanyName"]}";
// 多格式保存
doc.Save($"{fileName}.docx");
doc.Save($"{fileName}.pdf", SaveFormat.Pdf);
HtmlSaveOptions htmlOptions = new HtmlSaveOptions
{
ExportImagesAsBase64 = true
};
doc.Save($"{fileName}.html", htmlOptions);
}
}
public static void BatchProcessing()
{
const int BATCH_SIZE = 100;
string templatePath = "batch_template.docx";
int totalRecords = 1000;
for (int batch = 0; batch < totalRecords; batch += BATCH_SIZE)
{
Document template = new Document(templatePath);
int currentSize = Math.Min(BATCH_SIZE, totalRecords - batch);
DataTable batchData = CreateBatchData(batch, currentSize);
template.MailMerge.Execute(batchData);
template.Save($"batch_{batch / BATCH_SIZE + 1}.docx");
// 资源清理
template.Cleanup();
batchData.Dispose();
GC.Collect();
Console.WriteLine($"批次 {batch / BATCH_SIZE + 1} 完成");
}
}
private static DataTable CreateBatchData(int startIndex, int count)
{
DataTable table = new DataTable();
table.Columns.Add("ID", typeof(int));
table.Columns.Add("Name");
table.Columns.Add("Amount", typeof(decimal));
Random random = new Random();
string[] names = { "张三", "李四", "王五", "赵六" };
for (int i = 0; i < count; i++)
{
table.Rows.Add(
startIndex + i + 1,
names[random.Next(names.Length)],
random.Next(1000, 10000)
);
}
return table;
}
public class SafeBatchProcessor
{
public void ProcessWithErrorHandling(DataTable data, string templatePath)
{
List<string> errors = new List<string>();
int successCount = 0;
for (int i = 0; i < data.Rows.Count; i++)
{
try
{
ProcessSingleRecord(data.Rows[i], templatePath, i);
successCount++;
}
catch (Exception ex)
{
errors.Add($"记录 {i + 1}: {ex.Message}");
Console.WriteLine($"记录 {i + 1} 处理失败: {ex.Message}");
}
}
// 生成处理报告
Console.WriteLine($"处理完成: 成功 {successCount}, 失败 {errors.Count}");
if (errors.Count > 0)
{
File.WriteAllLines("error_log.txt", errors);
Console.WriteLine("错误详情已保存到 error_log.txt");
}
}
private void ProcessSingleRecord(DataRow record, string templatePath, int index)
{
Document template = new Document(templatePath);
DataTable single = record.Table.Clone();
single.Rows.Add(record.ItemArray);
template.MailMerge.Execute(single);
template.Save($"record_{index + 1}.docx");
template.Cleanup();
}
}
public static void GeneratePayslips()
{
Document template = new Document("payslip_template.docx");
template.MailMerge.FieldMergingCallback = new PayslipHandler();
DataTable employees = new DataTable();
employees.Columns.Add("EmployeeID");
employees.Columns.Add("Name");
employees.Columns.Add("Department");
employees.Columns.Add("BaseSalary", typeof(decimal));
employees.Columns.Add("Allowance", typeof(decimal));
employees.Columns.Add("Bonus", typeof(decimal));
employees.Columns.Add("PayDate", typeof(DateTime));
employees.Rows.Add("E001", "张三", "技术部", 8000m, 1000m, 2000m, DateTime.Now);
employees.Rows.Add("E002", "李四", "销售部", 7000m, 800m, 3000m, DateTime.Now);
foreach (DataRow employee in employees.Rows)
{
Document payslip = template.Clone();
DataTable single = employees.Clone();
single.Rows.Add(employee.ItemArray);
payslip.MailMerge.Execute(single);
string fileName = $"薪资单_{employee["EmployeeID"]}_{DateTime.Now:yyyyMM}.docx";
payslip.Save(fileName);
Console.WriteLine($"生成薪资单: {fileName}");
}
}
public class PayslipHandler : IFieldMergingCallback
{
public void FieldMerging(FieldMergingArgs e)
{
if (e.FieldName == "TotalSalary" && e.Record is DataRow row)
{
decimal total = Convert.ToDecimal(row["BaseSalary"]) +
Convert.ToDecimal(row["Allowance"]) +
Convert.ToDecimal(row["Bonus"]);
e.Text = total.ToString("C");
}
if (e.FieldName == "NetSalary" && e.Record is DataRow row2)
{
decimal total = Convert.ToDecimal(row2["BaseSalary"]) +
Convert.ToDecimal(row2["Allowance"]) +
Convert.ToDecimal(row2["Bonus"]);
decimal tax = total > 5000 ? (total - 5000) * 0.1m : 0;
e.Text = (total - tax).ToString("C");
}
}
public void ImageFieldMerging(ImageFieldMergingArgs e) { }
}
public static void GenerateContracts()
{
Document template = new Document("contract_template.docx");
DataTable contracts = new DataTable();
contracts.Columns.Add("ContractNumber");
contracts.Columns.Add("ClientName");
contracts.Columns.Add("ClientAddress");
contracts.Columns.Add("ServiceDescription");
contracts.Columns.Add("ContractAmount", typeof(decimal));
contracts.Columns.Add("SignDate", typeof(DateTime));
contracts.Columns.Add("StartDate", typeof(DateTime));
contracts.Columns.Add("EndDate", typeof(DateTime));
contracts.Rows.Add("CT-2024-001", "ABC公司", "北京市朝阳区", "软件开发服务", 100000m,
DateTime.Now, DateTime.Now.AddDays(7), DateTime.Now.AddMonths(6));
contracts.Rows.Add("CT-2024-002", "DEF企业", "上海市浦东区", "系统维护服务", 50000m,
DateTime.Now, DateTime.Now.AddDays(7), DateTime.Now.AddMonths(12));
foreach (DataRow contract in contracts.Rows)
{
Document contractDoc = template.Clone();
DataTable single = contracts.Clone();
single.Rows.Add(contract.ItemArray);
contractDoc.MailMerge.Execute(single);
// 添加页脚
foreach (Section section in contractDoc.Sections)
{
HeaderFooter footer = section.HeadersFooters[HeaderFooterType.FooterPrimary];
if (footer == null)
{
footer = new HeaderFooter(contractDoc, HeaderFooterType.FooterPrimary);
section.HeadersFooters.Add(footer);
}
DocumentBuilder builder = new DocumentBuilder(contractDoc);
builder.MoveToHeaderFooter(HeaderFooterType.FooterPrimary);
builder.Write($"合同编号:{contract["ContractNumber"]} | 第 ");
builder.InsertField("PAGE");
builder.Write(" 页,共 ");
builder.InsertField("NUMPAGES");
builder.Write(" 页");
}
string fileName = $"合同_{contract["ContractNumber"]}_{contract["ClientName"]}.docx";
contractDoc.Save(fileName);
// 同时生成PDF版本
contractDoc.Save(Path.ChangeExtension(fileName, ".pdf"), SaveFormat.Pdf);
Console.WriteLine($"生成合同: {fileName}");
}
}
本教程全面介绍了 Aspose.Words for .NET 邮件合并功能的核心内容:
Aspose.Words for .NET下载地址 https://soft51.cc/software/175811283999782847