普贤教程 › 生态包
FTP / IMAP / POP3
ftp、imap、pop3 三个明文协议客户端。它们的写法高度一致:connect → login → 若干命令 → quit,每步返 Result。三个包都不支持 TLS。
先说最大的限制:没有 TLS
三个包里 TLS 相关代码行数为 0。所以:
公网邮件请走
三个包里 TLS 相关代码行数为 0。所以:
ftps(990)、隐式 imaps(993)、pop3s(995)、
以及 STARTTLS 全部用不了。它们只适合内网、本机、或明确用明文的老设备。公网邮件请走
smtp(那个包有 TLS)或用 HTTP API;公网 FTP 现在几乎都强制 FTPS,实际也接不上。ftp
px
import ftp var c = ft_connect("127.0.0.1", 21) # 可选第三参 {"timeout_ms": 5000} print(c.is_ok(), c.err())
text
false ftp: connect 127.0.0.1:21 failed: net: 连接 127.0.0.1:21 失败 (111)
连上后(Ok({fd, host, port}))依次:
px
var c = ft_connect("host", 21, {"timeout_ms": 5000}).ok() ft_login(c, "user", "pass") # USER/PASS,返 Result ft_type(c, "I") # 二进制模式,传文件前必做 ft_pwd(c) # 当前目录 ft_cwd(c, "/upload") # 切目录 ft_list(c) # 目录列表(走 PASV 数据连接) ft_retr(c, "/path/file.txt") # 下载 → Ok(bytes) ft_stor(c, "/path/new.txt", data) # 上传,data 是 bytes ft_mkdir(c, "/upload/2026"); ft_rmdir(c, "/upload/old") ft_delete(c, "/path/gone.txt") ft_quit(c)
底层还暴露了 ft_send / ft_read_reply / ft_expect / ft_pasv_open,遇到包没封装的命令(SITE、MLSD)可以 ft_cmd(c, "SITE CHMOD 644 x", [200, 250]) 自己发。
pop3
px
import pop3 var c = po_connect("127.0.0.1", 110) # 可选 {"timeout_ms": …} print(c.is_ok(), c.err())
text
false pop3: connect 127.0.0.1:110 failed: net: 连接 127.0.0.1:110 失败 (111)
连上后:
px
var c = po_connect("host", 110, {"timeout_ms": 5000}).ok() po_login(c, "user", "pass") # USER/PASS po_stat(c) # Ok({count, size}) po_list(c) # 每封的大小 po_retr(c, 1) # 整封原文(含头与体)→ 再丢给 mailparse 解析 po_top(c, 1, 10) # 只要头部 + 前 10 行正文 po_uidl(c) # 唯一 ID,做增量收信靠它 po_dele(c, 1) # 标记删除(QUIT 时才真正生效) po_rset(c) # 撤销所有删除标记 po_noop(c); po_capa(c); po_quit(c)
POP3 的删除是「提交式」的
po_dele 只打标记,po_quit(c) 正常退出才落地;中途断线或 po_rset 就全部回滚。这跟直觉相反,但正是协议本身的设计。imap
px
import imap var c = imap_connect("127.0.0.1", 143, 1000) # 第三个参数是超时毫秒,必填 print(c.is_ok(), c.err())
text
false imap: 连接失败 127.0.0.1:143 net: 连接 127.0.0.1:143 失败 (111)
IMAP 是「选邮箱再取信」的模型:
px
var c = imap_connect("host", 143, 5000).ok() imap_login(c, "user", "pass") print(str(imap_list(c))) # 邮箱列表 imap_select(c, "INBOX") # 只读用 imap_examine print(str(imap_search(c, "UNSEEN"))) # 未读邮件序号 print(str(imap_fetch(c, "1", "(BODY[])"))) imap_store(c, "1", "+FLAGS (\\Seen)") # 标已读 imap_create(c, "Archive"); imap_copy(c, "1", "Archive") imap_close(c); imap_logout(c)
返回形态不一致
imap_connect 返 Ok(conn);imap_search / imap_fetch / imap_list 返
Ok(...);但 imap_login / imap_select / imap_store 等命令类只返
Ok(true)。写代码时别假设都能拿到数据。这三个包本轮的验证边界
诚实交代:本机没有任何 FTP / IMAP / POP3 服务,我只验证了「连不上时的行为」——三者都干净地返回 Err
(含协议名、主机、端口、系统 errno 111),没有崩、没有半开连接残留。成功路径(登录、列目录、取信)我没有跑过,
所以本页示例里的命令顺序来自源码与协议规范,不是实测输出。
要自己验:本机起一个 vsftpd(或 pyftpdlib 之类)就能把 ftp 全链路走通;IMAP/POP3 可以用
Dovecot 起一个本地实例。别拿生产邮箱当练习场——po_dele 是真删。