Go to file
FrRay 1076f52836 fix: use RFC 2047 Chinese attachment name that is compatible with the old mailbox client instead 2026-07-24 13:44:12 +08:00
assets init 2026-07-21 15:04:22 +08:00
.gitignore update: readme.md and start_gui.command 2026-07-23 14:27:32 +08:00
README.md feat: support drawing table fields as personalized invitation attachment according to invitation basemap and JSON configuration 2026-07-24 10:55:37 +08:00
bulk_invite_mailer.py fix: use RFC 2047 Chinese attachment name that is compatible with the old mailbox client instead 2026-07-24 13:44:12 +08:00
requirements.txt feat: support drawing table fields as personalized invitation attachment according to invitation basemap and JSON configuration 2026-07-24 10:55:37 +08:00
run_tool.bat init 2026-07-21 15:04:22 +08:00
start_gui.command update: readme.md and start_gui.command 2026-07-23 14:27:32 +08:00
start_gui.vbs init 2026-07-21 15:04:22 +08:00
tests_mailer.py fix: use RFC 2047 Chinese attachment name that is compatible with the old mailbox client instead 2026-07-24 13:44:12 +08:00

README.md

Bulk Invitation Mailer

批量发送个性化邮件工具。从 Excel 或 CSV 读取收件人信息为每位收件人单独生成邮件支持发件人配置、变量替换、HTML 正文、附件、演练预览、发送日志和断点续发。

如果以演练模式运行,不会连接 SMTP 服务器发送真实邮件。

功能

  • 支持 .xlsx.xlsm 和 UTF-8 CSV 收件人文件。
  • 自动识别姓名、邮箱列;其他列可直接用于模板变量。
  • 按收件人分别生成标题、正文和附件路径,例如 {{姓名}}{{公司}}
  • 支持根据邀请函底图和 JSON 配置,将表格字段绘制为个性化邀请函附件。
  • 支持纯文本和 HTML 正文;检测到 HTML 标签时会自动按 HTML 邮件生成。
  • 支持多个 SMTP 发件人配置,以及 SSL、STARTTLS 和无加密连接。
  • 演练模式为每位收件人生成 .eml 预览文件,不发送邮件。
  • 自动跳过重复邮箱、已完成记录;发送过程可暂停、继续或停止。
  • 记录每次任务的发送日志、状态表、预览文件和重试信息。

环境与安装

需要 Python 3.9 或更高版本。Excel 读取依赖 openpyxl;图形界面使用 Python 自带的 Tkinter。

pip install -r requirements.txt

Windows PowerShell 可使用:

pip install -r requirements.txt

启动图形界面

Windows 下可双击 start_gui.vbs;需要看到命令行输出时运行:

python bulk_invite_mailer.py --gui

macOS 下首次使用时,在项目目录执行:

chmod +x start_gui.command

之后可双击 start_gui.command 启动。

不带命令行参数直接运行 python bulk_invite_mailer.py 也会打开图形界面。

图形界面使用流程

  1. 选择收件人表格,点击“读取并预览”。
  2. 确认姓名列和邮箱列;程序会标记重复邮箱和可能无效的邮箱格式。
  3. 选择已有发件人配置,或填写 SMTP 信息后保存为新配置。
  4. 填写标题、正文、HTML 选项、附件路径和发送间隔。
  5. 先保持“演练模式”生成预览;确认无误后关闭演练模式,再开始真实发送。

开始前会显示发送模式、发件人、收件人数、标题模板和首封邮件标题的确认窗口。可在界面中生成当前收件人的 HTML 与 .eml 预览,或在任务结束后直接打开日志和输出目录。

收件人表格

首行必须是列名。邮箱列会从以下名称中自动识别:邮箱电子邮箱邮件收件邮箱邮箱地址emaile-mailmail。姓名列也会自动识别 姓名名字收件人客户姓名嘉宾姓名name

姓名,邮箱,公司,场次
张三,zhangsan@example.com,示例公司,上海场
李四,lisi@example.com,示例公司,北京场

正文、标题和附件路径都能引用任意列:

{{姓名}},您好:

诚邀您参加 {{公司}} 的 {{场次}} 活动。

附件支持多个路径,以英文分号分隔:

attachments/{{姓名}}.pdf;attachments/活动说明.pdf

附件路径不存在时,当前收件人会暂停等待处理,不会静默跳过。

个性化邀请函附件

勾选“附加个性化邀请函”,选择 JSON 配置文件后,程序会在开始任务前为每位收件人生成邀请函,并作为普通附件附加到邮件。生成过程在连接 SMTP 前完成;姓名、字体、底图或像素尺寸不符合配置时,任务不会开始发送。

配置文件可放在收件人表格同目录。当前示例位于 app_data/recipients/06-发邀请函/邀请函配置.json

{
  "template_image": "邀请函底图.jpg",
  "expected_image_size": [2568, 5511],
  "output": {
    "format": "pdf",
    "file_name_template": "{{真实姓名}}邀请函"
  },
  "layers": [
    {
      "text_template": "{{真实姓名}}",
      "position": { "x": 510, "y": 3030 },
      "anchor": "mm",
      "max_width": 450,
      "font": {
        "path": "%WINDIR%/Fonts/msyh.ttc",
        "size": 92,
        "min_size": 48
      },
      "color": "#382066"
    }
  ]
}

position 使用底图原始像素坐标;anchor: "mm" 表示文字中心对准坐标。max_width 限制文字宽度,姓名过长时会在 sizemin_size 之间自动缩小。每次任务会在输出目录生成 invitations/ 和所用的 invitation_config.json 副本。

发件人配置与隐私

发件人配置保存在 app_data/config/senders.csv,包含 SMTP 地址、端口、安全方式、发件人信息和授权码或密码。授权凭据以明文保存在本机,请妥善保护该目录。

界面设置保存在 app_data/config/mailer_config.json。默认运行数据目录如下:

app_data/
  config/
    mailer_config.json
    senders.csv
  recipients/
  previews/
    current_email_preview.html
    current_email_preview.eml
  outputs/
    20260723_100000/
      send_log.csv
      send_status.csv
      previews/

app_data/ 已被 Git 忽略。不要强制加入、压缩或上传其中的配置、收件人表格、预览和日志。

发送行为与日志

  • 演练模式:为每位收件人生成 .eml 文件,状态记为 PREVIEWED
  • 真实发送:邮件成功提交给 SMTP 服务器后,状态记为 DONE
  • 同一次任务中,忽略大小写和首尾空白后相同的邮箱只处理首次出现的记录,后续记录标为 SKIPPED_DUPLICATE
  • 使用同一个输出目录再次运行时,已完成的记录会被跳过;可通过 --output-dir 指定该目录以继续未完成任务。
  • GUI 支持暂停、继续和停止。SMTP 临时错误可选择自动重试;其他发送错误会暂停在当前收件人处等待继续。
  • 每次任务会写入 send_log.csvsend_status.csv;演练模式还会在 previews/ 生成邮件文件。

日志记录收件人邮箱和发送状态,输出目录同样属于敏感数据。

命令行

列出已保存的发件人配置:

python3 bulk_invite_mailer.py --list-senders

保存发件人配置。推荐从环境变量读取授权码,避免把密码写入终端历史:

export SMTP_PASSWORD='授权码'
python3 bulk_invite_mailer.py \
  --smtp-host smtp.example.com \
  --smtp-port 465 \
  --security ssl \
  --sender sender@example.com \
  --sender-name '活动组' \
  --password-env SMTP_PASSWORD \
  --save-sender-profile '默认发件人'

演练模式(默认,不会发送):

python3 bulk_invite_mailer.py \
  --excel recipients.xlsx \
  --sender-profile '默认发件人' \
  --subject '{{姓名}},活动邀请' \
  --body-file invite.html \
  --html

真实发送:

python3 bulk_invite_mailer.py \
  --excel recipients.xlsx \
  --sender-profile '默认发件人' \
  --subject '{{姓名}},活动邀请' \
  --body-file invite.html \
  --html \
  --attachments 'attachments/{{姓名}}.pdf' \
  --send

常用参数:

参数 用途
--sheet 指定 Excel 工作表;默认读取活动工作表。
--name-column--email-column 手动指定姓名列、邮箱列。
--data-dir 指定配置、收件人和默认输出目录;默认 ./app_data
--senders-csv 指定发件人配置 CSV。
--password-env 授权码所在环境变量;默认 SMTP_PASSWORD
--output-dir 指定日志、状态表和演练预览目录。
--delay 真实发送时两封邮件之间的等待秒数;默认 1.0
--auto-retry-seconds 命令行发生错误后的重试等待秒数;默认 180
--send 开启真实发送;省略时始终为演练模式。

查看全部参数:

python3 bulk_invite_mailer.py --help

测试

python3 -m unittest tests_mailer.py