Python实现邮件合并和批量生成个性化Word文档
作者:大丸子
邮件合并把文档模板和数据源分离:模板定义布局与固定文字,合并字段标记数据插入位置,运行时用数据源的值替换字段。一次合并产出一份文档,循环数据源即批量生成。Free Spire.Doc for Python 的 MailMerge 对象提供 Execute 方法做字段替换,配合 IF 条件字段和空区域处理,覆盖从简单替换到条件显示的常见需求。
pip install spire-doc
演示模板(template.docx)是一封客户通知信,包含 9 个合并字段(Contact Name、Company、Address、Fax、Date、OrderNumber、Product、Quantity、Amount)和 1 个 IF 条件字段(判断 Amount 是否超过 1000)。

简单字段合并
Execute 接收两个等长列表:字段名和字段值。模板中的合并字段(«Contact Name»、«Company» 等)被对应位置的值替换。
from spire.doc import *
from spire.doc.common import *
document = Document()
document.LoadFromFile("template.docx")
fieldNames = ["Contact Name", "Company", "Address", "Fax", "Date",
"OrderNumber", "Product", "Quantity", "Amount"]
fieldValues = ["John Smith", "Acme Corporation", "123 Business Ave, New York, NY 10001",
"+1 (555) 123-4567", "2026-10-19",
"ORD-2026-0847", "Wireless Headset Model X200", "25", "1875"]
document.MailMerge.Execute(fieldNames, fieldValues)
document.IsUpdateFields = True
document.SaveToFile("output_simple_merge.docx", FileFormat.Docx)
document.Close()IsUpdateFields 设为 True 让合并后文档中的所有字段重新计算并显示结果。不设置这一行,合并字段本身会被替换,但 IF 条件字段保持域代码状态,不显示判断结果。
所有字段已替换为实际值。

条件字段
IF 字段在模板中定义条件判断,合并时根据数据值选择显示内容。模板中的 IF 字段判断 Amount 是否大于 1000:超过则显示 "You qualify for our premium discount program.",否则显示 "Standard rate applies."
同一模板用两组数据合并,观察条件字段的输出差异:
fieldNames = ["Contact Name", "Company", "Address", "Fax", "Date",
"OrderNumber", "Product", "Quantity", "Amount"]
# Amount = 2400(超过 1000)
doc1 = Document()
doc1.LoadFromFile("template.docx")
fieldValues1 = ["Alice Brown", "TechGlobal Inc.", "456 Innovation Drive, San Jose, CA 95110",
"+1 (555) 987-6543", "2026-10-19",
"ORD-2026-0848", "Enterprise Server License", "3", "2400"]
doc1.MailMerge.Execute(fieldNames, fieldValues1)
doc1.IsUpdateFields = True
doc1.SaveToFile("output_conditional_premium.docx", FileFormat.Docx)
doc1.Close()
# Amount = 450(不超过 1000)
doc2 = Document()
doc2.LoadFromFile("template.docx")
fieldValues2 = ["Bob Wilson", "HomeOffice Solutions", "789 Residential St, Austin, TX 73301",
"+1 (555) 456-7890", "2026-10-19",
"ORD-2026-0849", "Desktop App Subscription", "1", "450"]
doc2.MailMerge.Execute(fieldNames, fieldValues2)
doc2.IsUpdateFields = True
doc2.SaveToFile("output_conditional_standard.docx", FileFormat.Docx)
doc2.Close()两份输出分别显示 "You qualify for our premium discount program." 和 "Standard rate applies."。条件字段在模板中只定义一次,合并时自动按数据分流,不需要在代码里写 if-else 分支。

空区域处理
当某些字段没有值时,合并后对应的段落变成空行。HideEmptyParagraphs 设为 True 会移除这些段落,使文档结构紧凑。
这里有一个需要留意的机制:HideEmptyParagraphs 判断的是整个段落是否为空,而非单个字段是否为空。如果段落中除合并字段外还有其他文字(例如 "VAT Number: «VATNumber»"),即使 VATNumber 的值为空,段落仍保留 "VAT Number: " 前缀,不会被移除。要让空区域被正确隐藏,可选字段应独占一个段落。
document = Document()
document.LoadFromFile("template_optional.docx")
document.MailMerge.HideEmptyParagraphs = True
fieldNames = ["Customer", "InvoiceNumber", "VATNumber", "DiscountCode", "Amount"]
fieldValues = ["Global Tech Ltd.", "INV-2026-3392", "", "", "3200"]
document.MailMerge.Execute(fieldNames, fieldValues)
document.IsUpdateFields = True
document.SaveToFile("output_empty_hidden.docx", FileFormat.Docx)
document.Close()VATNumber 和 DiscountCode 的值为空字符串。不设置 HideEmptyParagraphs 时,文档保留 8 个段落(含 2 个空段落);设置后减为 6 个,空字段所在的段落被完整移除。
批量生成
邮件合并的典型场景是从数据列表一次性生成多份文档。每条记录重新加载模板、执行合并、保存为独立文件:
import os
fieldNames = ["Contact Name", "Company", "Address", "Fax", "Date",
"OrderNumber", "Product", "Quantity", "Amount"]
batch_data = [
{"Contact Name": "John Smith", "Company": "Acme Corporation",
"Address": "123 Business Ave, New York, NY 10001",
"Fax": "+1 (555) 123-4567", "Date": "2026-10-19",
"OrderNumber": "ORD-2026-0847", "Product": "Wireless Headset Model X200",
"Quantity": "25", "Amount": "1875"},
{"Contact Name": "Alice Brown", "Company": "TechGlobal Inc.",
"Address": "456 Innovation Drive, San Jose, CA 95110",
"Fax": "+1 (555) 987-6543", "Date": "2026-10-19",
"OrderNumber": "ORD-2026-0848", "Product": "Enterprise Server License",
"Quantity": "3", "Amount": "2400"},
# ... 更多记录
]
os.makedirs("batch_output", exist_ok=True)
for record in batch_data:
doc = Document()
doc.LoadFromFile("template.docx")
fieldValues = [record[name] for name in fieldNames]
doc.MailMerge.Execute(fieldNames, fieldValues)
doc.IsUpdateFields = True
doc.SaveToFile(f"batch_output/{record['OrderNumber']}.docx", FileFormat.Docx)
doc.Close()5 条记录全部生成成功,以订单号命名。模板在每次循环中重新加载——合并操作会修改文档对象,复用同一对象会导致字段已被替换、后续合并无字段可填。
数据源不限于代码内的列表。实际应用中,数据从 Excel、CSV、数据库查询结果读入,构造为 fieldNames 和 fieldValues 两个列表即可接入同一套合并流程。
适用场景与方案选择
三种方案按复杂度递进,按需组合:
- 简单字段合并:模板字段与数据一一对应,无条件判断。适合通知书、确认函、证书——格式固定、内容全量替换。
- 条件字段:模板中用 IF 字段定义条件分支,合并时自动选择显示内容。适合报价单、合同——根据金额、客户等级、订单状态显示不同条款。
- 空区域处理:可选字段独占段落,
HideEmptyParagraphs控制是否保留空段落。适合发票、对账单——某些字段(税号、折扣码)部分客户有、部分没有。
批量生成是三种方案的共同出口:无论模板用了哪种字段类型,循环数据源、逐条合并、逐份保存的流程不变。数据源从业务系统读入,模板由业务人员维护,代码只负责把两者对接——这是邮件合并把模板和数据分离的设计意图。
以上就是Python实现邮件合并和批量生成个性化Word文档的详细内容,更多关于Python邮件合并的资料请关注脚本之家其它相关文章!
