如何利用 curl 通过 SMTP 发送邮件

在自动化运维或脚本编写中,直接使用 Linux 系统自带的 curl 即可通过 SMTP 协议发送告警或通知邮件。

🛠️ 发信前的准备工作(以 Gmail 为例)

  1. 前往 security,确认两步验证已开启。
  2. 访问 App Password,创建一个应用专用密码(生成的 16 位随机字母即为 curl 命令中的密码)。

📄 第一步:编写邮件内容文件 (mail.txt)

邮件本质上是一个符合 MIME 规范的文本文件(邮件头与正文之间必须保留一个空行):

From: Jiacai Liu <[email protected]>
To: Joe Smith <[email protected]>
Subject: 命令行 curl 发信测试
Date: Fri, 7 Aug 2026 19:19:00 -0700

Dear Joe,
这是一封通过 curl 直接发送的测试邮件。

💻 第二步:运行 curl 命令发送

curl smtps://smtp.gmail.com \
  --user "[email protected]:您的16位应用专用密码" \
  --mail-from "[email protected]" \
  --mail-rcpt "[email protected]" \
  --upload-file mail.txt

💡 核心概念:MIME Header vs SMTP Envelope

在电子邮件传输中,邮件内容(Header)信封传输(Envelope) 是完全独立的:

维度MIME Header (邮件文本头部)SMTP Envelope (SMTP 传输指令)
生效位置写入 mail.txt 文件中 (From:, To:)传给 curl 的命令行参数 (--mail-from, --mail-rcpt)
主要作用邮件客户端(Gmail / Outlook)展示给收件人看SMTP 服务器握手路由,决定信件实际投递给谁
格式要求支持 Display Name,如 Display Name <[email protected]>必须为纯 Email 地址(如 [email protected]),不能包含 Display Name
多收件人逗号分隔,如 To: [email protected], [email protected]必须重复传参,如 --mail-rcpt "[email protected]" --mail-rcpt "[email protected]"

⚠️ 踩坑提示 1:如果直接把包含 Display Name 的字符串 Name <[email protected]> 传给 curl --mail-rcptcurl 会在最外层包裹角括号变成 RCPT TO:<Name <[email protected]>,导致 SMTP 服务器抛出 555 Syntax error。在脚本中给 curl 传参前必须提取出纯邮箱地址。

⚠️ 踩坑提示 2:非 ASCII 字符(中文)导致对方显示 no subject(RFC 2047) SMTP 规范(RFC 5322)要求邮件头(Subject:, From: 中的 Display Name 等)必须仅包含 7-bit ASCII 字符。如果在 Subject 中直接写入中文而未经编码,在经过 Gmail / Google Groups / Outlook 等邮件服务解析 Header 时会失败,接收方将显示为 (no subject) / 无主题

解决方法:按照 RFC 2047 规范,将包含中文的 Header 包装为 UTF-8 Base64 编码格式:=?UTF-8?B?<base64>?=

可以在 Bash 脚本中自动处理:

# Encode header using RFC 2047 UTF-8 Base64 format
SUBJECT_ENCODED="=?UTF-8?B?$(printf "%s" "$SUBJECT" | base64 | tr -d '\r\n')?="

写入 mail.txt 时输出:

Subject: =?UTF-8?B?44CQWmlnIMpelp报44CR6aG555uu5YiG5Lqr...=?=

💡 进阶小贴士

  • GitHub Actions 集成:如果需要在 GitHub Workflows 中自动化发送邮件,推荐使用基于本文踩坑经验封装的 Composite Action:jiacai2050/sendmail-action。该 Action 内置了纯邮箱地址自动提取、RFC 2047 中文 Header 自动编码及 Multipart HTML 等特性,开箱即用。
  • 密送 (BCC):只需在 curl 中并列增加 --mail-rcpt,但不要在 mail.txtTo:Cc: 头部写入该邮箱。
  • 防止误判垃圾邮件:建议显式在 mail.txt 中包含格式规范的 Date: 字段。

参考