如何用 curl 收发邮件:SMTP、POP3、IMAP 完整实战指南

发布时间:2026/9/7 4:27:27
如何用 curl 收发邮件:SMTP、POP3、IMAP 完整实战指南 如何用 curl 收发邮件SMTP、POP3、IMAP 完整实战指南【免费下载链接】Awesome-Chinese-LLM整理开源的中文大语言模型以规模较小、可私有化部署、训练成本较低的模型为主包括底座模型垂直领域微调及应用数据集与教程等。项目地址: https://gitcode.com/GitHub_Trending/aw/Awesome-Chinese-LLM不用装邮件库、不用手拼协议字节curl 原生支持 SMTP、POP3、IMAP 三个邮件协议命令行里能发信、能取信C 程序里通过 libcurl 也能干同一件事。本文按三个真实任务展开——CI 构建告警要发出去、退役邮箱要整箱搬回本地、多设备要远程管理收件箱——每个任务回答三个问题选哪个协议、命令怎么写、怎么算成功。文末统一交代 TLS 加密的两种姿势和常见错误码的排查顺序。先把能力边界划清楚curl 只负责协议层——建连、认证、收发、透传部分原生命令。它不解析邮件内容、不存本地数据库、不会自动删 POP3 邮件也不会替你补邮件头里的 Subject。超出这个边界的事得在 curl 外面自己处理。先选协议三个问题定下 SMTP、POP3、IMAP动手写命令之前先回答三个问题答案基本就定了邮件往哪边流推给对方服务器还是拉到本地拉回来之后服务器上的原件还要不要要不要搜索、打标记、多设备同步这类远程操作协议职责明文端口加密端口服务器上的原件SMTP投递把信推到对方服务器25465隐式 TLS/ 587STARTTLS不涉及只发不收POP3拉取把邮件搬回本地110995原样保留curl 不删IMAP管理远程查、搜、改标记143993原样保留状态可同步对应关系很直白只发选 SMTP要整箱搬走备份选 POP3要查、搜、改标记选 IMAP。POP3 在三者里功能最少可以理解成一台单向搬运机。发第一封邮件一条命令跑通 SMTP任务是 CI 里构建失败把告警推给运维邮箱。SMTP 发信成功与否看应答码流程最后一条250代表全部收件人接收成功。最小可运行命令把mail.txt完整邮件文本投递出去curl smtps://mail.example.com:465 \ --user username:password \ --mail-from senderexample.com \ --mail-rcpt readerexample.com \ --upload-file mail.txt跑完退出码为 0、终端末行出现250 2.0.0 Ok一类应答即算成功。想看过程就加-vEHLO、MAIL FROM、RCPT TO、DATA的协商会逐行打印每行开头都是三位应答码。参数逐个拆--mail-from声明发件人建议带尖括号写成addr。--mail-rcpt收件人可重复传入一封发给多人curl smtps://mail.example.com:465 \ --user username:password \ --mail-from senderexample.com \ --mail-rcpt aexample.com \ --mail-rcpt bexample.com \ --upload-file mail.txt--upload-file正文文件。注意它必须是完整的 RFC 5322 文本——头部、一个空行、正文缺一不可curl 不会自动补 Subject文件里没写就没有主题行。libcurl 版收件人列表与正文回调C 程序里收件人挂在curl_slist上正文由读回调按块吐出#include stdio.h #include string.h #include curl/curl.h static const char *payload To: readerexample.com\r\n From: Sender senderexample.com\r\n Subject: build alert\r\n \r\n /* 空行分隔头部与正文RFC 5322 */ Pipeline #2048 failed.\r\n; static size_t read_cb(char *buf, size_t size, size_t nmemb, void *userp) { size_t *off userp; size_t room size * nmemb; size_t len strlen(payload *off); if (len room) len room; memcpy(buf, payload *off, len); *off len; return len; } int main(void) { size_t off 0; struct curl_slist *rcpt NULL; CURL *curl curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, smtp://mail.example.com:587); curl_easy_setopt(curl, CURLOPT_USERNAME, username); curl_easy_setopt(curl, CURLOPT_PASSWORD, password); curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY); /* 支持 STARTTLS 升级 */ curl_easy_setopt(curl, CURLOPT_MAIL_FROM, senderexample.com); /* 发件人 */ rcpt curl_slist_append(rcpt, readerexample.com); curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt); /* 收件人列表可继续 append */ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_cb); /* 正文经回调提供 */ curl_easy_setopt(curl, CURLOPT_READDATA, off); curl_easy_perform(curl); curl_slist_free_all(rcpt); curl_easy_cleanup(curl); /* QUIT 在 cleanup 时才发出 */ return 0; }两个实操细节循环连发多封可以复用同一句柄只需反复curl_easy_performQUIT到curl_easy_cleanup()才真正发出。注意闲置几分钟服务器会主动断连届时重建句柄即可。脚本触发自动回复的场景发件人可以传空字符串避免你发→对方回→你再发的死循环。整箱邮件拉到本地POP3 归档最简做法任务是退役旧邮箱前把存量邮件全部搬回本地存档。POP3 的寻址规则只有一条URL 里的/N表示第 N 封不带路径就整箱拉。C 版最短先跑通它#include stdio.h #include curl/curl.h int main(void) { CURL *curl curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, pop3s://pop.example.com/7); /* /7 RETR 7 */ curl_easy_setopt(curl, CURLOPT_USERNAME, username); curl_easy_setopt(curl, CURLOPT_PASSWORD, password); curl_easy_perform(curl); /* 邮件内容经写回调输出到 stdout */ curl_easy_cleanup(curl); return 0; }命令行等价操作# 整箱拉取写入归档文件 curl pop3s://pop.example.com --user username:password -o inbox.mbox # 只要第 7 封 curl pop3s://pop.example.com/7 --user username:password -o msg7.eml搬之前先数一遍数量-I只发状态查询响应头就是OK行curl -sI pop3s://pop.example.com --user username:password # 输出形如OK 25 messages 4418813 octetsC 里用自定义请求发STAT命令效果相同curl_easy_setopt(curl, CURLOPT_URL, pop3s://pop.example.com); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, STAT); /* 透传 STAT 命令 */ curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); /* 只取状态不取正文 */一个必须记住的行为curl 取信走 RETR默认只取不删不会替你发 DELE。归档完成后服务器上的原件依然原样躺着要删得另发命令处理。远程管理收件箱curl IMAP 的 -X 透传套路IMAP 和前两者的差别在管邮件留在服务器你远程查、搜、改标记。curl 处理 IMAP 的核心套路是——URL 路径写目标邮箱/选择器其余操作一律用-X透传原生命令。掌握这一条LIST、STATUS、SEARCH、FETCH 全能拼出来。列邮箱、查状态# 列出服务器上所有邮箱 curl -s imaps://imap.example.com --user username:password -X LIST * # 看 INBOX 总量与未读数 curl -s imaps://imap.example.com/INBOX --user username:password \ -X STATUS INBOX (MESSAGES UNSEEN)搜未读、抓正文# 搜出未读邮件返回一串序号 curl -s imaps://imap.example.com/INBOX --user username:password -X SEARCH UNSEEN # 取 INBOX 第 3 封全文 curl imaps://imap.example.com/INBOX/3 --user username:password -o msg3.eml # 只抓头部不落盘 curl -s imaps://imap.example.com/INBOX --user username:password \ -X FETCH 3 BODY[HEADER]C 版透传一条 SEARCHcurl_easy_setopt(curl, CURLOPT_URL, imaps://imap.example.com/INBOX); curl_easy_setopt(curl, CURLOPT_USERNAME, username); curl_easy_setopt(curl, CURLOPT_PASSWORD, password); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, SEARCH UNSEEN); /* 只搜未读 */ curl_easy_perform(curl);按 UID 稳定取信头部正文经写回调输出curl_easy_setopt(curl, CURLOPT_URL, imaps://imap.example.com/INBOX/;UID1); curl_easy_perform(curl); /* UID1 那封输出到 stdout */UID 和序号的区别FETCH 默认按序列号取信就是当前会话里第几封。序号的问题是会漂移新邮件一进 INBOX原来的第 3 封变第 4 封跨会话的批量脚本就会抓错信。UID 是服务器给每封邮件发的稳定编号不随新邮件插入而变化。规则一句话会话内临时操作用序号无所谓批量归档、同步进度这类跨会话操作优先 UID。加密通道隐式 TLS 与 STARTTLS 怎么分两种加密方式的差别只有一条线加密从哪一刻开始。通道写法行为常见端口隐式 TLSsmtps:///pop3s:///imaps://TCP 一连上就进 TLS 握手465 / 995 / 993STARTTLSsmtp://等明文端口 --ssl先明文握手发 STARTTLS 后升级587 / 110 / 143强制升级明文端口 --ssl-reqd必须升级成功否则直接失败同上一次完整会话的走向大致是TCP 建连 →隐式 TLS 直接握手或 STARTTLS 协商后升级→ SASL 认证PLAIN、LOGIN235为通过→ 业务命令MAIL FROM / RETR / SEARCH / FETCH→ QUIT 或 LOGOUT 收尾。命令行上--ssl的态度是能升就升升不了照发--ssl-reqd是升不了就失败。口令认证至少保证走到--ssl否则用户名口令全程可读--insecure直接禁用——它会把证书错误一并放过等于把门焊死。libcurl 侧对应CURLOPT_USE_SSLCURLUSESSL_TRY对应--sslCURLUSESSL_ALL对应--ssl-reqd。证书校验默认开着CURLOPT_SSL_VERIFYPEER加主机名校验企业内网自签 CA 时用CURLOPT_CAINFO指向自己的 bundle。出错时的排查顺序五个高频错误码按这个顺序过一遍多数问题能在前两步定位退出码错误名第一步备选7CURLE_COULDNT_CONNECT用nc或telnet验端口通不通换 465/587、995、993 逐个试确认端口与加密模式匹配隐式/STARTTLS 不混用67CURLE_LOGIN_DENIED核对用户名、口令查是否要求应用专用密码或账号被禁登35CURLE_SSL_CONNECT_ERROR-v看握手卡在哪协议版本、ALPN换隐式 TLS 端口或升级 curl60CURLE_SSL_CACERT服务器证书链缺 CA--cacert/CURLOPT_CAINFO指定企业 CA bundle28CURLE_OPERATION_TIMEDOUT区分连接超时与整体超时CURLOPT_CONNECTTIMEOUT与CURLOPT_TIMEOUT分开设调试手段命令行加-vC 程序设CURLOPT_VERBOSE, 1L得到同等输出要按行分流的话挂CURLOPT_DEBUGFUNCTION在回调里按CURLINFO_HEADER_IN/CURLINFO_DATA_IN把协议应答和邮件数据分开。上线前检查清单正文文件是完整 MIME 文本头部 空行 正文不是只有正文。认证流量确认走了 TLS隐式端口smtps://等或--ssl-reqd至少占其一。发件人地址带尖括号addr自动回复场景用空发件人防止回信循环。IMAP 批量操作一律用 UID别用会漂移的序列号。POP3 拉完不等于删了要清理服务器原件另行发命令。curl 版本 ≥ 7.21三个协议支持的起点curl --version输出里能看到SMTP POP3 IMAP字样即具备对应能力。复用句柄连发多封时QUIT在curl_easy_cleanup()才发出闲置断连后记得重建句柄。【免费下载链接】Awesome-Chinese-LLM整理开源的中文大语言模型以规模较小、可私有化部署、训练成本较低的模型为主包括底座模型垂直领域微调及应用数据集与教程等。项目地址: https://gitcode.com/GitHub_Trending/aw/Awesome-Chinese-LLM创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考