curl 邮件协议实战:SMTP、POP3、IMAP 几分钟完整上手
【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl
不用装邮件客户端。curl 邮件协议支持让你直接在命令行或 C 代码里发、收、管理邮件——你平时下载文件用的那个 curl,换一行参数就是邮件工具。
2 分钟跑通:用 curl 命令行邮件发出第一封
先写个带完整头部的消息文件message.txt:
To: friend@example.com From: sender@example.com Subject: Hello from curl 这封邮件由 curl 发出。然后一条命令:
curl smtp://smtp.example.com:25 \ --mail-from "sender@example.com" \ --mail-rcpt "friend@example.com" \ --upload-file message.txt预期结果:没有任何输出,echo $?是 0,就说明邮件已经在路上了。加-v能看到353握手和250 2.0.0 OK应答。✉️ 两分钟,第一封邮件发出去了。
一张表选对协议:SMTP、POP3、IMAP
| 协议 | 默认端口 | 安全端口 | 用途 | 一句话选型 |
|---|---|---|---|---|
| SMTP | 25 | 587(STARTTLS)/ 465(隐式) | 只负责发 | 只需发信 → SMTP |
| POP3 | 110 | 995 | 拉下来、服务端可删 | 一次性归档、老邮件箱清空 → POP3 |
| IMAP | 143 | 993 | 服务器端管理、多端同步 | 要文件夹/已读状态跨设备同步 → IMAP |
拿不准时按这个走:
分场景实战
场景 A:用 curl SMTP 命令行发邮件
目标:从 587 端口走 STARTTLS,带认证发一封正式邮件。
命令:
curl smtp://smtp.example.com:587 --ssl \ --user "sender@example.com:pass" \ --mail-from "sender@example.com" \ --mail-rcpt "friend@example.com" \ --upload-file message.txt结果:250 2.0.0 OK: queued之后退出码 0。message.txt必须自带 To/From/Subject 头部和空行,因为 curl 原样上传,不做任何包装。
易踩坑:正文行结尾必须是\r\n,Linux 上写个纯\n的文件会被不少服务器拒收;--mail-from建议与认证账号一致,避免触发反垃圾的 553 拒信。
在 C 代码里做同样的事,核心就 10 行(完整版本见 docs/examples/smtp-mail.c):
CURL *curl = curl_easy_init(); if (curl) { struct curl_slist *rcpt = curl_slist_append(NULL, "friend@example.com"); curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.example.com:587"); curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY); curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "sender@example.com"); curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); FILE *fh = fopen("message.txt", "rb"); curl_easy_setopt(curl, CURLOPT_READDATA, fh); curl_easy_setopt(curl, CURLOPT_USERNAME, "sender@example.com"); curl_easy_setopt(curl, CURLOPT_PASSWORD, getenv("SMTP_PASS")); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) fprintf(stderr, "%s\n", curl_easy_strerror(res)); curl_slist_free_all(rcpt); curl_easy_cleanup(curl); fclose(fh); }场景 B:用 curl POP3 拉取整个邮箱
目标:把整个 POP3 邮箱一次性搬到本地归档。
命令:
curl pop3s://pop.example.com:995 \ --user "you@example.com:pass" \ -o inbox.mbox结果:所有邮件按编号依次 RETR,拼接写入inbox.mbox。想先确认数量,加-I触发 STAT,会看到类似+OK 42 messages 112772 octets的统计行;只取第 1 封则把 URL 写成pop3s://pop.example.com/1。
易踩坑:POP3 是无状态的"一次性买卖"——RETR 之后很多服务器按配置自动 DELE,拉完就没了,没有文件夹、没有已读标志。这也是它和 IMAP 的本质差异:IMAP 把邮箱留在服务器上随时可查,POP3 是把邮件从服务器上"取走"。批量归档前先在测试账号上验证服务器行为。
场景 C:用 curl IMAP 管理多端同步邮箱
目标:不写代码,用-X直接发原始 IMAP 命令(lib/imap.c 里 custom request 原样透传),完成 LIST / SEARCH / FETCH 三件事。
命令:
# 1. 列出所有邮箱 curl imaps://imap.example.com:993 \ --user "you@example.com:pass" -X 'LIST "" *' # 2. 在 INBOX 里搜索未读邮件 curl "imaps://imap.example.com:993/INBOX" \ --user "you@example.com:pass" -X "SEARCH UNSEEN" # 3. 抓取第 3 封邮件的头部 curl "imaps://imap.example.com:993/INBOX" \ --user "you@example.com:pass" -X "FETCH 3 (BODY[HEADER])"结果:LIST 返回每行一个邮箱名及标志位(\HasNoChildren之类);SEARCH 返回未读邮件的序列号列表,如* SEARCH 3 7 12;FETCH 直接吐出 RFC822 头部。
易踩坑:curl 每次执行都是一个独立会话,前一条命令 SELECT 的邮箱不会带到下一条——所以把邮箱写进 URL(/INBOX),让 curl 每次自动 SELECT;FETCH 的参数含括号和方括号,务必整体加引号,否则 shell 先把它吃掉。
排坑手册:6 个最常见的报错
| 现象(报错/退出码) | 原因 | 一句话解决 |
|---|---|---|
535 Authentication failed | 密码错或服务器要求应用专用密码 | 换应用专用密码,别用主密码 |
| 退出码 6(CURLE_COULDNT_RESOLVE_HOST) | 主机名写错或 DNS 不通 | 先用ping确认主机名解析正常 |
| 退出码 7,连 25 端口超时 | 运营商普遍封禁 25 端口 | 改用 587 +--ssl或 465 隐式 TLS |
553 5.7.1(MAIL FROM 被拒) | --mail-from与认证账号不符 | --mail-from填认证账号本身 |
| 退出码 60(CURLE_SSL_CERTPROBLEM) | 缺失 CA 或服务器用自签证书 | --cacert /path/ca.pem指定 CA 包 |
| POP3 下载出空文件、IMAP 无数据 | 邮箱为空,或 IMAP URL 没带/INBOX | 先-I看 STAT 数量;IMAP 把邮箱写进 URL |
安全加固:TLS 三种连接方式怎么选
| 连接方式 | URL 写法 | curl 参数 | 说明 |
|---|---|---|---|
| 明文 | smtp://host:25 | 无 | 账号密码裸奔,仅限可信内网 |
| STARTTLS | smtp://host:587 | --ssl | 先明文握手再升级为 TLS,现代主流 |
| 隐式 TLS | smtps://host:465、pop3s://、imaps:// | 由 scheme 决定 | 第一个字节起就是 TLS,最稳 |
加固 ✅ 清单:
- ✅ 加
--ssl-reqd:TLS 协商失败就报错退出,而不是静默降级明文 - ✅ 保持证书校验默认开启;CA 不完整时用
--cacert指定,而不是关校验 - ✅
--connect-timeout 10 --max-time 30:10 秒连不上、30 秒总超时,防止脚本挂死 - ✅ 密码走环境变量:
--user "you@example.com:$MAIL_PASS",别硬编码进脚本 - ✅
-k(跳过证书校验)只在排障时用,用完即删
收尾
curl 邮件协议本质就是终端里说 RFC 5321、1939、3501 的瑞士军刀。上面三条命令跑通,日常收发和运维场景就覆盖了九成。想继续深挖,翻一遍 docs/examples/ 里imap-*.c、pop3-*.c、smtp-*.c的官方示例源码,docs/cmdline-opts/mail-from.md 等选项文档也值得一读。
⚡ 进阶技巧:
- 连接复用:libcurl 下
curl_easy_perform()返回后先别cleanup,改完MAIL_FROM/MAIL_RCPT再次 perform 即可复用同一条连接,QUIT只在 cleanup 时发出(见 docs/examples/smtp-mail.c 尾部注释)——连续发 100 封比每次重连快一个量级。 - 并发批量:拉 IMAP 时
for i in $(seq 1 50); do curl "imaps://imap.example.com/INBOX" -X "FETCH $i (RFC822)" -o "msg_$i.eml" & done; wait,或用xargs -P 8开 8 路并发,几十秒拉完全箱。
【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考