分类网络协议标签IMAPPOP3邮件协议邮箱开发网络协议一句话总结POP3是把信从邮局取回家IMAP是把信存在邮局随时看。一个是下载即拥有一个是云端同步流。选错了你的邮件可能在一台设备上读完另一台设备上却显示未读——这就是协议选择的艺术。一、开篇两种收信哲学的对决想象一下这个场景你刚在办公室的电脑上读完一封重要邮件标记为已读。下班回到家打开手机邮箱——咦怎么还是未读状态别急着骂邮箱App问题可能出在你的邮件接收协议选择上。邮件协议的世界里有两位老大哥POP3Post Office Protocol v3和IMAPInternet Message Access Protocol。它们就像两个性格迥异的邮递员 POP3传统邮递员您的信我放门口了取走就是你的我这儿不留底。POP3的哲学很简单把邮件从服务器下载到本地下载完服务器上的副本可以选择删除或保留。就像把信从邮局取回家看完随手扔抽屉里或者丢掉。️ IMAP现代邮局管理员您的信我帮您保管在邮局保险柜里您在任何地方都能看到同样的信。标记已读、整理分类所有操作都会同步。IMAP的哲学是云端优先邮件始终保存在服务器上客户端只是查看和操作这些邮件。你在手机上标记已读电脑上也会同步显示已读。这两种协议诞生于不同的时代解决不同的问题有着完全不同的设计哲学。接下来让我们深入它们的内心世界。二、POP3协议详解老派但可靠的下载模式2.1 POP3的工作流程POP3协议诞生于1984年RFC 918在1988年定型为POP3RFC 1081最后一次更新是1996年的RFC 1939。它设计于拨号上网时代那时候网络连接昂贵且不稳定下载后离线阅读是最合理的选择。┌─────────────────────────────────────────────────────────────┐ │ POP3 工作流程示意图 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────┐ ┌──────────────┐ │ │ │ 客户端 │ │ 邮件服务器 │ │ │ │ (Outlook)│◄────── TCP 110 ───►│ (POP3) │ │ │ └────┬─────┘ └──────┬───────┘ │ │ │ │ │ │ │ 1. USER username │ │ │ │────────────────────────────────►│ │ │ │ 2. OK │ │ │ │◄────────────────────────────────│ │ │ │ 3. PASS password │ │ │ │────────────────────────────────►│ │ │ │ 4. OK 登录成功 │ │ │ │◄────────────────────────────────│ │ │ │ 5. STAT │ │ │ │────────────────────────────────►│ │ │ │ 6. OK 3 15234 (3封邮件共15KB)│ │ │ │◄────────────────────────────────│ │ │ │ 7. RETR 1 │ │ │ │────────────────────────────────►│ │ │ │ 8. OK 邮件内容... │ │ │ │◄────────────────────────────────│ │ │ │ 9. DELE 1 (标记删除) │ │ │ │────────────────────────────────►│ │ │ │ 10. OK │ │ │ │◄────────────────────────────────│ │ │ │ 11. QUIT │ │ │ │────────────────────────────────►│ │ │ │ 12. OK 再见 (执行删除) │ │ │ │◄────────────────────────────────│ │ │ ▼ ▼ │ │ [邮件已下载到本地] [服务器邮件已删除] │ │ │ └─────────────────────────────────────────────────────────────┘2.2 核心命令解析POP3协议非常简单只有十几个命令。它的设计理念是最小可用每个命令都直截了当命令作用示例响应USER提交用户名OK或-ERRPASS提交密码OK登录成功STAT查询邮件统计OK 3 15234(3封15KB)LIST列出邮件大小OK 1 5024(第1封5KB)RETR获取邮件内容OK 邮件全文DELE标记删除OK(QUIT后生效)NOOP无操作保活OKRSET重置删除标记OKQUIT结束会话OK(执行删除)2.3 UIDL命令POP3的身份证系统这里有个关键问题如果邮件被删除后新邮件进来编号会变化吗答案是会。POP3的邮件编号是动态的第1封删了原来的第2封就变成第1封。这对于客户端来说是个噩梦——怎么知道哪些邮件已经下载过了POP3的解决方案是UIDL命令Unique ID ListC: UIDL S: OK S: 1 abc123def456 S: 2 xyz789uvw012 S: 3 mno345pqr678 S: .每一封邮件都有一个唯一的UID通常是哈希值即使邮件编号变了UID也不变。客户端可以维护一个已下载UID列表避免重复下载。开发提示实现POP3客户端时务必使用UIDL来跟踪已下载邮件否则用户会看到重复邮件体验极差。2.4 删除策略延迟删除的巧妙设计POP3的删除机制有个有趣的设计DELE命令并不会立即删除邮件而是标记为待删除。真正的删除发生在QUIT命令之后。为什么要这样设计1.容错性如果下载过程中断网邮件不会被误删2.可撤销用户可以用RSET命令取消所有删除标记3.事务性整个会话要么全部成功要么全部回滚这就像你去超市购物把商品放进购物车不代表你买了直到结账离开才真正成交。三、IMAP协议详解云时代的同步大师3.1 IMAP的设计哲学IMAP诞生于1986年RFC 1064当前版本是IMAP4rev1RFC 35012003年更新。与POP3不同IMAP设计之初就考虑了多设备、永久在线的场景。IMAP的核心设计原则•服务器是权威数据源邮件始终保存在服务器•状态同步已读/未读、标记、文件夹结构全部同步•按需获取可以只下载邮件头不下载正文•多客户端并发支持多个客户端同时操作3.2 IMAP的文件夹同步机制IMAP引入了邮箱Mailbox的概念对应我们熟悉的文件夹┌─────────────────────────────────────────────────────────────┐ │ IMAP 邮箱结构示意图 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ INBOX ← 收件箱所有新邮件默认进来 │ │ ├── 邮件1 (未读) │ │ ├── 邮件2 (已读) │ │ └── 邮件3 (已标记⭐) │ │ │ │ Sent ← 已发送 │ │ Drafts ← 草稿箱 │ │ Trash ← 垃圾箱 │ │ Spam ← 垃圾邮件 │ │ Work/ ← 自定义文件夹 │ │ ├── Projects/ │ │ └── Reports/ │ │ │ │ Archive/2025/ ← 归档文件夹IMAP支持层级结构 │ │ │ └─────────────────────────────────────────────────────────────┘IMAP使用LIST和LSUB命令来获取文件夹列表使用SELECT或EXAMINE来选择文件夹进行操作C: A1 LIST * S: * LIST (\HasNoChildren) / INBOX S: * LIST (\HasNoChildren) / Sent S: * LIST (\HasChildren) / Work S: * LIST (\HasNoChildren) / Work/Projects S: A1 OK LIST completed3.3 UID机制比POP3更强大的唯一标识IMAP也有UID但比POP3的UIDL强大得多•32位无符号整数范围1到2^32-1•单调递增新邮件的UID一定比旧邮件大•唯一性保证在一个邮箱内绝对唯一•持久性除非邮件被删除否则UID不变IMAP的UID命令允许你使用UID而非序号来操作邮件C: A2 UID FETCH 12345 (FLAGS BODY[HEADER]) S: * 7 FETCH (UID 12345 FLAGS (\Seen) BODY[HEADER] {1024} S: ...邮件头内容... S: ) S: A2 OK UID FETCH completed3.4 FLAGS标记邮件的状态标签这是IMAP最酷的功能之一。每封邮件可以有一组FLAGS标记常用的有标记含义说明\Seen已读用户已阅读\Answered已回复已发送回复邮件\Flagged已标记星标/红旗标记\Deleted已删除标记为删除类似POP3\Draft草稿未完成的邮件\Recent新邮件本次会话首次看到只读客户端可以用STORE命令修改标记C: A3 STORE 7 FLAGS (\Seen \Flagged) S: * 7 FETCH (FLAGS (\Seen \Flagged)) S: A3 OK STORE completed这意味着你在手机上标记一封邮件为星标打开电脑后它也会显示星标。这就是IMAP的魔力。四、IMAP的部分获取优化BODYSTRUCTURE与BODY.PEEK4.1 为什么需要部分获取想象一下你的收件箱有1000封邮件每封带附件平均5MB。如果用POP3全部下载需要5GB流量IMAP的解决方案是按需获取。你可以只获取邮件头不获取正文只获取文本部分不获取附件甚至只获取前100行预览。4.2 BODYSTRUCTURE邮件的解剖图BODYSTRUCTURE是IMAP最强大的功能之一。它返回邮件的MIME结构告诉你邮件由哪些部分组成C: A4 FETCH 1 (BODYSTRUCTURE) S: * 1 FETCH (BODYSTRUCTURE ( S: (TEXT PLAIN (CHARSET UTF-8) NIL NIL QUOTED-PRINTABLE 1523 45) S: (TEXT HTML (CHARSET UTF-8) NIL NIL QUOTED-PRINTABLE 2847 62) S: (APPLICATION PDF (NAME report.pdf) NIL NIL BASE64 1048576) S: MIXED (BOUNDARY ----_Part_123_456) NIL NIL S: )) S: A4 OK FETCH completed这告诉我们• 第1部分纯文本UTF-8编码1523字节45行• 第2部分HTML版本2847字节62行• 第3部分PDF附件BASE64编码约1MB客户端可以据此决定我只下载文本部分附件等用户点击再下载。4.3 BODY.PEEK静默查看有个细节问题当你用FETCH获取邮件时服务器会自动标记为\Seen已读。但有时候你只是预览一下不想标记已读。BODY.PEEK就是为此设计的C: A5 FETCH 1 (BODY.PEEK[HEADER] BODY.PEEK[TEXT]) S: ...返回邮件内容但不标记已读...这就像是你在书店翻书店员不会因为你翻了就强迫你买下。4.4 部分获取的实战技巧常见的部分获取场景# 只获取邮件头用于列表展示 FETCH 1:10 (FLAGS RFC822.SIZE ENVELOPE) # 获取前1000字节的预览 FETCH 1 (BODY.PEEK[]0.1000) # 只获取纯文本部分跳过HTML和附件 FETCH 1 (BODY.PEEK[1]) # 获取特定附件 FETCH 1 (BODY.PEEK[3])性能优化邮件客户端通常采用先拉列表按需拉详情的策略。先用轻量查询获取邮件列表用户点击某封邮件时再获取完整内容。五、协议性能对比数据说话5.1 核心特性对比表特性POP3IMAP默认端口110TLS: 995143TLS: 993邮件存储位置主要在本地下载后删除永久保存在服务器多设备同步❌ 不支持✅ 完整支持文件夹支持❌ 无✅ 层级文件夹状态同步❌ 已读状态不同步✅ 已读/标记全同步部分获取❌ 只能全下载✅ 支持按需获取服务器搜索❌ 不支持✅ 支持服务器端搜索离线阅读✅ 天然支持⚠️ 需客户端缓存带宽消耗高全量下载低按需获取服务器存储低下载后可删高永久保存协议复杂度简单~10个命令复杂~30个命令5.2 性能实测数据假设一个典型场景收件箱有500封邮件平均每封50KB含小附件┌─────────────────────────────────────────────────────────────┐ │ 性能对比实测数据 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 首次同步新设备 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ POP3: 下载全部 500 × 50KB 25MB │ │ │ │ IMAP: 下载邮件头 500 × 2KB 1MB │ │ │ │ ▓▓▓▓ │ │ │ │ POP3 ████████████████████████████████████████████ │ │ │ │ IMAP ██ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 日常检查新邮件10封新邮件 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ POP3: 需对比UIDL下载10封 500KB │ │ │ │ IMAP: 查询新邮件UID下载头 20KB │ │ │ │ ▓▓▓▓ │ │ │ │ POP3 ████████████████████████████████████████████ │ │ │ │ IMAP █ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ │ 多设备切换已读100封邮件 │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ POP3: 设备A已读设备B显示未读 ❌ │ │ │ │ IMAP: 状态同步所有设备一致 ✅ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘5.3 适用场景分析选择POP3的场景• 只在单一设备上查收邮件• 服务器邮箱容量非常有限如只有几十MB• 需要完全离线访问所有历史邮件• 对隐私极度敏感不信任云端存储• 使用的是非常老的邮件客户端选择IMAP的场景• 在多设备手机电脑平板上使用邮箱• 需要状态同步已读/未读/标记• 使用文件夹分类管理邮件• 服务器邮箱容量充足• 希望节省流量按需获取内容• 需要在Web端和客户端保持一致体验现实情况2025年了除非你有特殊需求否则一律选IMAP。Gmail、Outlook、QQ邮箱、163邮箱的默认推荐都是IMAP。六、Wireshark抓包分析看协议如何对话纸上得来终觉浅让我们用Wireshark抓包看看真实的协议交互是什么样的。6.1 POP3抓包实录 Wireshark过滤表达式tcp.port 110Frame 1: 客户端 → 服务器 USER kazikexample.com Frame 2: 服务器 → 客户端 OK Welcome to POP3 server Frame 3: 客户端 → 服务器 PASS mySecretPassword Frame 4: 服务器 → 客户端 OK Logged in. 3 messages (15234 bytes) Frame 5: 客户端 → 服务器 STAT Frame 6: 服务器 → 客户端 OK 3 15234 Frame 7: 客户端 → 服务器 RETR 1 Frame 8: 服务器 → 客户端 OK 5024 octets Received: from mail.example.com... From: bosscompany.com Subject: 周报 reminder ...邮件正文... .⚠️安全警告上面的抓包显示POP3使用明文传输密码这就是为什么现在强制使用POP3SSSL/TLS加密端口995。生产环境绝不能用明文POP3。6.2 IMAP抓包实录 Wireshark过滤表达式tcp.port 143 || tcp.port 993Frame 1: 服务器 → 客户端Capability响应 * OK [CAPABILITY IMAP4rev1 LITERAL SASL-IR ...] Server ready Frame 2: 客户端 → 服务器 A1 LOGIN kazikexample.com mySecretPassword Frame 3: 服务器 → 客户端 A1 OK [CAPABILITY IMAP4rev1 ...] Logged in Frame 4: 客户端 → 服务器 A2 SELECT INBOX Frame 5: 服务器 → 客户端 * 3 EXISTS * 0 RECENT * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) * OK [PERMANENTFLAGS (\*)] Flags permitted * OK [UIDVALIDITY 1623456789] UIDs valid * OK [UIDNEXT 4] Predicted next UID A2 OK [READ-WRITE] SELECT completed Frame 6: 客户端 → 服务器 A3 FETCH 1:3 (FLAGS RFC822.SIZE ENVELOPE) Frame 7: 服务器 → 客户端 * 1 FETCH (FLAGS (\Seen) RFC822.SIZE 5024 ENVELOPE (...)) * 2 FETCH (FLAGS (\Flagged) RFC822.SIZE 8192 ENVELOPE (...)) * 3 FETCH (FLAGS () RFC822.SIZE 2048 ENVELOPE (...)) A3 OK FETCH completed Frame 8: 客户端 → 服务器 A4 STORE 3 FLAGS (\Seen) Frame 9: 服务器 → 客户端 * 3 FETCH (FLAGS (\Seen)) A4 OK STORE completed注意到IMAP的标签机制了吗每个命令前面都有A1、A2这样的标签服务器响应也会带上相同的标签。这允许客户端流水线发送多个命令而不必等待每个响应。6.3 TLS加密后的抓包使用IMAPS端口993或STARTTLS后Wireshark看到的是加密流量Frame 1-3: TLS握手 Client Hello → Server Hello → Certificate → ... Frame 4: 加密应用数据 TLSv1.3 Record Layer: Application Data Content Type: Application Data (23) Version: TLS 1.3 (0x0304) Length: 256 Encrypted Application Data: 00000000000000017f8a2b3c... [Application Data Protocol: imap]想看明文你需要配置Wireshark的SSL密钥日志或者使用服务器的私钥解密仅用于调试。七、Python实战imaplib与poplib理论讲完了让我们写点能跑的代码。Python标准库自带imaplib和poplib无需额外安装。7.1 POP3客户端实战import poplib from email.parser import Parser from email.header import decode_header import getpass def decode_str(s): 解码邮件头中的编码字符串 value, charset decode_header(s)[0] if charset: value value.decode(charset) return value def get_email_content(msg): 递归获取邮件正文 if msg.is_multipart(): parts msg.get_payload() for part in parts: content get_email_content(part) if content: return content else: content_type msg.get_content_type() if content_type text/plain or content_type text/html: content msg.get_payload(decodeTrue) charset msg.get_charset() if charset is None: content_type msg.get(Content-Type, ).lower() pos content_type.find(charset) if pos 0: charset content_type[pos 8:].strip() if charset: content content.decode(charset) return content return None def fetch_pop3_emails(server, port, username, password, use_sslTrue): 使用POP3获取邮件 Args: server: POP3服务器地址 port: 端口SSL默认995非SSL默认110 username: 邮箱账号 password: 邮箱密码/授权码 use_ssl: 是否使用SSL加密 try: # 连接服务器 if use_ssl: pop_conn poplib.POP3_SSL(server, port) else: pop_conn poplib.POP3(server, port) pop_conn.set_debuglevel(1) # 开启调试输出 print(f服务器响应: {pop_conn.getwelcome().decode(utf-8)}) # 登录 pop_conn.user(username) pop_conn.pass_(password) # 获取邮件统计 num_messages, total_size pop_conn.stat() print(f\n 邮箱统计: {num_messages} 封邮件共 {total_size} 字节) # 获取UIDL列表用于去重 print(\n UIDL列表:) response, uidl_list, octets pop_conn.uidl() for uidl in uidl_list: print(f {uidl.decode(utf-8)}) # 下载最近3封邮件 if num_messages 0: print(f\n 下载最近3封邮件:) for i in range(max(1, num_messages - 2), num_messages 1): print(f\n--- 邮件 {i} ---) # 获取邮件内容 response, lines, octets pop_conn.retr(i) msg_content b\r\n.join(lines).decode(utf-8) # 解析邮件 msg Parser().parsestr(msg_content) # 获取邮件头信息 subject decode_str(msg[Subject]) if msg[Subject] else 无主题 from_addr decode_str(msg[From]) if msg[From] else 未知发件人 date msg[Date] or 未知日期 print(f主题: {subject}) print(f发件人: {from_addr}) print(f日期: {date}) # 获取正文预览 content get_email_content(msg) if content: preview content[:200].replace(\n, ) print(f预览: {preview}...) # 标记删除可选 # pop_conn.dele(i) # print([已标记删除]) # 退出执行删除 pop_conn.quit() print(\n✅ POP3会话结束) except Exception as e: print(f❌ 错误: {e}) # 使用示例 if __name__ __main__: # 请替换为你的邮箱信息 # 注意大多数邮箱需要使用授权码而非登录密码 SERVER pop.qq.com # QQ邮箱POP3服务器 PORT 995 USERNAME your_qqqq.com PASSWORD getpass.getpass(请输入邮箱授权码: ) fetch_pop3_emails(SERVER, PORT, USERNAME, PASSWORD)7.2 IMAP客户端实战import imaplib import email from email.parser import Parser from email.header import decode_header import getpass def decode_str(s): 解码邮件头中的编码字符串 if not s: return value, charset decode_header(s)[0] if isinstance(value, bytes): if charset: value value.decode(charset) else: value value.decode(utf-8) return value def get_body(msg): 获取邮件正文优先纯文本 if msg.is_multipart(): for part in msg.walk(): content_type part.get_content_type() content_disposition str(part.get(Content-Disposition)) # 跳过附件 if attachment in content_disposition: continue if content_type text/plain: try: return part.get_payload(decodeTrue).decode(utf-8) except: pass elif content_type text/html: try: return part.get_payload(decodeTrue).decode(utf-8) except: pass else: try: return msg.get_payload(decodeTrue).decode(utf-8) except: pass return def fetch_imap_emails(server, username, password, mailboxINBOX, limit5): 使用IMAP获取邮件 Args: server: IMAP服务器地址 username: 邮箱账号 password: 邮箱密码/授权码 mailbox: 邮箱文件夹默认INBOX limit: 获取最近几封邮件 try: # 使用SSL连接端口993 mail imaplib.IMAP4_SSL(server) # 登录 mail.login(username, password) print(f✅ 登录成功: {username}) # 列出所有邮箱文件夹 print(\n 邮箱文件夹列表:) status, folders mail.list() for folder in folders[:5]: # 只显示前5个 print(f {folder.decode(utf-8)}) if len(folders) 5: print(f ... 还有 {len(folders) - 5} 个文件夹) # 选择邮箱 status, messages mail.select(mailbox) if status ! OK: print(f❌ 无法选择邮箱: {mailbox}) return num_messages int(messages[0]) print(f\n {mailbox} 中有 {num_messages} 封邮件) if num_messages 0: print(邮箱为空) mail.logout() return # 搜索所有邮件 status, data mail.search(None, ALL) if status ! OK: print(搜索邮件失败) return mail_ids data[0].split() # 获取最近的N封邮件 recent_ids mail_ids[-limit:] print(f\n 获取最近 {len(recent_ids)} 封邮件:\n) for i, mail_id in enumerate(reversed(recent_ids), 1): # 获取邮件头信息使用BODY.PEEK避免标记已读 status, data mail.fetch(mail_id, (BODY.PEEK[HEADER])) if status ! OK: continue # 解析邮件头 raw_header data[0][1] msg email.message_from_bytes(raw_header) subject decode_str(msg[Subject]) from_addr decode_str(msg[From]) date msg[Date] print(f--- 邮件 {i} (ID: {mail_id.decode()}) ---) print(f主题: {subject}) print(f发件人: {from_addr}) print(f日期: {date}) # 获取FLAGS查看当前状态 status, flag_data mail.fetch(mail_id, (FLAGS)) if status OK: flags flag_data[0].decode(utf-8) print(f标记: {flags}) # 获取完整邮件内容 status, data mail.fetch(mail_id, (RFC822)) if status OK: raw_email data[0][1] msg email.message_from_bytes(raw_email) body get_body(msg) # 显示正文预览 if body: preview body[:150].replace(\n, ).replace(\r, ) print(f预览: {preview}...) # 检查是否有附件 has_attachment False for part in msg.walk(): if part.get_content_disposition() attachment: has_attachment True filename decode_str(part.get_filename()) print(f 附件: {filename}) if not has_attachment: print( 无附件) print() # 演示标记第一封为已读 if recent_ids: first_id recent_ids[-1] print(f 标记邮件 {first_id.decode()} 为已读...) mail.store(first_id, FLAGS, \\Seen) print(✅ 已标记) # 演示搜索未读邮件 print(\n 搜索未读邮件...) status, data mail.search(None, UNSEEN) if status OK: unseen_ids data[0].split() print(f找到 {len(unseen_ids)} 封未读邮件) # 关闭连接 mail.close() mail.logout() print(\n✅ IMAP会话结束) except Exception as e: print(f❌ 错误: {e}) import traceback traceback.print_exc() def demonstrate_imap_features(): 演示IMAP的高级特性 print( * 50) print(IMAP高级特性演示) print( * 50) server imap.qq.com # QQ邮箱IMAP服务器 username input(请输入邮箱地址: ) password getpass.getpass(请输入邮箱授权码: ) fetch_imap_emails(server, username, password) # 使用示例 if __name__ __main__: demonstrate_imap_features()7.3 高级IMAP操作部分获取实战import imaplib import email def advanced_imap_demo(server, username, password): 演示IMAP的部分获取和高级功能 mail imaplib.IMAP4_SSL(server) mail.login(username, password) mail.select(INBOX) # 1. 只获取邮件头用于快速列表 print( 1. 轻量获取邮件列表 ) status, data mail.search(None, ALL) mail_ids data[0].split()[-5:] # 最近5封 for mail_id in mail_ids: # 只获取信封信息From, To, Subject, Date status, data mail.fetch(mail_id, (ENVELOPE FLAGS RFC822.SIZE)) if status OK: print(f邮件 {mail_id.decode()}: {data[0][1][:100]}...) # 2. 使用BODYSTRUCTURE分析邮件结构 print(\n 2. 分析邮件结构 (BODYSTRUCTURE) ) if mail_ids: status, data mail.fetch(mail_ids[-1], (BODYSTRUCTURE)) if status OK: print(f结构: {data[0][1][:500]}...) # 3. 只获取纯文本部分跳过HTML和附件 print(\n 3. 只获取纯文本部分 ) if mail_ids: # BODY[1] 通常指第一个MIME部分 status, data mail.fetch(mail_ids[-1], (BODY.PEEK[1])) if status OK: content data[0][1] print(f纯文本内容: {content[:200]}...) # 4. 获取前1000字节预览 print(\n 4. 部分获取预览 ) if mail_ids: # 0.1000 表示从0字节开始获取1000字节 status, data mail.fetch(mail_ids[-1], (BODY.PEEK[]0.1000)) if status OK: preview data[0][1] print(f前1000字节: {preview}...) # 5. 服务器端搜索 print(\n 5. 服务器端搜索 ) # 搜索来自特定发件人的邮件 status, data mail.search(None, FROM, noreplygithub.com) if status OK: print(f来自GitHub的邮件: {len(data[0].split())} 封) # 搜索主题包含特定关键词的邮件 status, data mail.search(None, SUBJECT, 发票) if status OK: print(f主题含发票的邮件: {len(data[0].split())} 封) # 搜索特定日期之后的邮件 status, data mail.search(None, SINCE, 01-May-2025) if status OK: print(f5月1日之后的邮件: {len(data[0].split())} 封) # 搜索未读邮件 status, data mail.search(None, UNSEEN) if status OK: print(f未读邮件: {len(data[0].split())} 封) # 6. UID操作更可靠 print(\n 6. UID操作 ) status, data mail.uid(SEARCH, None, ALL) if status OK: uids data[0].split() print(fUID列表前5个: {uids[:5]}) if uids: # 使用UID获取邮件 status, data mail.uid(FETCH, uids[-1], (FLAGS)) if status OK: print(fUID {uids[-1].decode()} 的标记: {data[0][1]}) mail.close() mail.logout() print(\n✅ 高级演示完成) # 运行示例 if __name__ __main__: import getpass SERVER imap.qq.com USERNAME input(邮箱地址: ) PASSWORD getpass.getpass(授权码: ) advanced_imap_demo(SERVER, USERNAME, PASSWORD)开发提示• QQ邮箱、163邮箱等需要使用授权码而非登录密码• 生产环境务必使用SSL/TLS加密IMAPS/POP3S• 频繁操作建议使用连接池避免反复登录• 大量邮件处理考虑使用分页避免内存溢出八、总结如何选择你的邮件协议让我们用一张图总结今天的全部内容┌─────────────────────────────────────────────────────────────┐ │ 邮件协议选择决策树 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 开始选择邮件协议 │ │ │ │ │ ┌───────────┴───────────┐ │ │ ▼ ▼ │ │ 你有多台设备吗 只有一台设备 │ │ │ │ │ │ ┌───────┴───────┐ ▼ │ │ ▼ ▼ 服务器容量小 │ │ 是 否 │ │ │ │ │ ┌─────┴─────┐ │ │ ▼ ▼ ▼ ▼ │ │ 选 IMAP 选 POP3 是 否 │ │ ✅ 状态同步 ✅ 简单 │ │ │ │ ✅ 多设备 ✅ 离线 ▼ ▼ │ │ ✅ 省流量 ✅ 省空间 POP3 还是IMAP │ │ ✅ ✅ 云端备份 │ │ │ │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ │ │ │ │ 2025年推荐默认选择IMAP │ │ 除非你有特殊需求否则不要选POP3 │ │ │ └─────────────────────────────────────────────────────────────┘核心要点回顾1.POP3是下载模式邮件下载到本地服务器可选删除。适合单设备、离线场景但多设备体验差。2.IMAP是同步模式邮件保存在服务器所有设备看到一致的状态。适合现代多设备场景。3.UIDL vs UIDPOP3用UIDL避免重复下载IMAP用UID实现精确操作。IMAP的UID更强大单调递增、32位范围。4.FLAGS机制IMAP的\Seen、\Flagged等标记让状态同步成为可能这是POP3无法做到的。5.部分获取IMAP的BODYSTRUCTURE和BODY.PEEK让按需加载成为现实大幅节省流量。6.安全优先生产环境必须使用SSL/TLS加密POP3S/IMAPS明文传输是安全隐患。 源码获取本文所有代码示例已整理到GitHub仓库仓库地址https://github.com/kazik/email-protocol-demos包含内容• pop3_client.py - 完整的POP3客户端示例• imap_client.py - 完整的IMAP客户端示例• imap_advanced.py - IMAP高级特性演示• wireshark_filters.txt - 抓包过滤表达式合集• requirements.txt - 依赖列表欢迎Star和Fork如有问题请提Issue。 思考题1. 如果你正在开发一个邮件客户端如何设计离线模式是像POP3那样全量下载还是像IMAP那样按需缓存2. IMAP的UIDVALIDITY有什么作用什么情况下它会改变客户端应该如何处理3. 为什么IMAP的\Recent标记是会话级的设计这样一只读标记的目的是什么4. 在移动网络环境下如何优化IMAP客户端以减少流量消耗提示考虑BODYSTRUCTURE和选择性同步5. POP3的TOP命令获取邮件头和前N行在某些服务器上支持不佳为什么 系列文章预告《网络协议深度解析》系列持续更新中• 已发布• 01_TCP三次握手与四次挥手• 05_HTTP/1.1 vs HTTP/2 vs HTTP/3• 10_DNS解析全流程• 12_TLS/SSL握手详解• 即将发布• 17_SMTP协议——邮件发送的艺术• 18_WebSocket实时通信原理• 20_gRPC与Protobuf实战• 25_QUIC协议深度剖析点击关注不错过每一篇硬核技术文章如果觉得本文对你有帮助欢迎• 点赞支持 - 让更多人看到这篇文章• ⭐ 收藏备用 - 开发时随时查阅• 评论交流 - 有问题或建议请留言• 关注作者 - 获取更多网络协议干货—— 全文完 ——标签IMAPPOP3邮件协议邮箱开发网络协议