资讯详情

电子邮件系统实战指南:从SMTP协议到送达率优化的避坑手册

📅 2026/10/17 5:15:01 | 华诺云谱 👁 阅读
电子邮件系统实战指南:从SMTP协议到送达率优化的避坑手册
电子邮件这套东西很多人觉得它老掉牙甚至觉得是上个世纪的产物。但只要你还在互联网行业混哪怕只是做前端、搞运维、写脚本迟早都得跟它打交道。发验证码、发告警通知、发营销邮件、做自动化报表推送哪一样都绕不开它。我见过不少新手一听说要发邮件第一反应就是“找个库调一下不就行了”结果真上手了才发现邮件进了垃圾箱、附件变成乱码、发信频率一高就被封各种幺蛾子层出不穷。这篇文章不打算给你背教科书而是从实际干活的角度把电子邮件这套体系拆开揉碎讲清楚它到底怎么运转、哪些环节容易翻车、怎么配置才能稳。不管你是刚接触网络编程的学生还是需要给系统加告警通知的运维或者是想搞明白“为什么我发的邮件别人收不到”的开发者下面这些内容都能直接拿去用。1. 电子邮件系统的整体架构与核心角色拆解1.1 为什么电子邮件不是“一个服务器”的事很多人脑子里对电子邮件的印象就是“我写好内容点发送对方就收到了”跟发微信差不多。但电子邮件的底层逻辑完全不是即时通信那一套它更像是一套接力跑的邮政系统。你写的邮件不是直接从你电脑飞到对方电脑上中间要经过好几个角色转手每个角色各干各的活任何一个环节出问题邮件就到不了。这套系统里最核心的几个角色分别是用户代理UA、邮件服务器、SMTP协议、POP3/IMAP协议。用户代理就是你平时用的Outlook、Foxmail、网页版邮箱界面它负责让你写邮件、看邮件。邮件服务器才是真正干活的它分成发送方服务器和接收方服务器两边可能完全不是一个厂商、不是一个系统。SMTP负责把邮件从你手里推到服务器再从你的服务器推到对方的服务器。POP3和IMAP则是负责把邮件从服务器拉到你的设备上。我刚开始学的时候特别困惑为什么不能像HTTP那样直接请求一下就完事后来想明白了电子邮件的设计目标是“异步可靠投递”不是“实时交互”。你发邮件的时候对方可能根本没开机甚至可能几天不上线所以必须有一个中间人帮你存着等对方来了再给。这个中间人就是邮件服务器它得24小时在线得有大容量存储还得能跟全世界其他邮件服务器互相通信。1.2 SMTP、POP3、IMAP三兄弟的分工与区别这三个协议是电子邮件体系里的顶梁柱但很多人分不清谁是谁。我用一个特别土的类比来解释SMTP是“寄信”POP3是“把信箱里的信全部拿回家”IMAP是“信箱留在邮局你随时去看”。SMTP全称是简单邮件传输协议它只管一件事把邮件从A点推到B点。注意是“推”不是“拉”。你点发送的时候你的客户端用SMTP把邮件推给你的发送方服务器你的发送方服务器再用SMTP把邮件推到对方的接收方服务器。SMTP有个特点它不负责存储推完就完事如果对方服务器没响应它会排队重试但重试几次还不行就会退信。POP3全称是邮局协议第三版它的工作模式是“下载并删除”当然也可以配置成下载不删除。你配置POP3的时候客户端会把服务器上所有邮件拉到本地然后默认把服务器上的删掉。这种模式适合只有一台设备收邮件的场景比如你只用办公室电脑收公司邮件。但如果你手机也要收、家里电脑也要收POP3就会让你崩溃因为每台设备看到的邮件都不一样。IMAP全称是互联网消息访问协议它跟POP3最大的区别是“服务器端管理”。你的邮件始终存在服务器上客户端只是显示一个镜像。你在手机上读了一封邮件标记为已读回到电脑上打开它也是已读状态。你在电脑上删了一封手机上也没了。IMAP适合多设备场景现在基本是主流了。协议方向默认端口核心职责适用场景SMTP推送25/587/465发送和中转邮件所有发信场景POP3拉取110/995下载邮件到本地单设备收信IMAP拉取143/993服务器端管理邮件多设备收信注意25端口是传统SMTP端口但现在很多云服务商默认封禁25端口防止垃圾邮件。发信建议用587STARTTLS或465SSL/TLS。1.3 一封邮件从点击发送到对方收件箱的完整路径我拿一个实际场景来串一遍。假设你用某个邮件客户端给朋友发一封带附件的邮件整个过程大概是这样你在客户端写好邮件填好收件人地址点发送。客户端通过SMTP协议连接你的发送方服务器比如你公司自己的邮件服务器或者某个企业邮箱服务把邮件内容推过去。这一步需要认证通常要用户名和密码或者授权码。发送方服务器收到邮件后先检查收件人域名。比如收件人是friendexample.com它就去找example.com的MX记录。MX记录是DNS里专门给邮件用的告诉发送方服务器“这个域名的邮件该投给哪台服务器”。发送方服务器通过SMTP连接接收方服务器把邮件推过去。如果接收方服务器暂时不可达发送方服务器会把邮件放进队列过一段时间重试。接收方服务器收到邮件后先做一堆检查发件人是不是黑名单、邮件内容有没有病毒、是不是垃圾邮件、收件人是否存在。检查通过后把邮件放进收件人的邮箱存储。你朋友打开客户端通过IMAP或POP3连接接收方服务器把邮件拉下来看。这条链路里第3步的MX记录查询和第5步的反垃圾检查是最容易出问题的。很多人发邮件失败不是自己代码写错了而是DNS没配好或者被对方服务器判定为垃圾邮件。2. 邮件地址、邮件格式与编码的细节陷阱2.1 邮件地址的组成与常见书写错误邮件地址看起来简单就是“用户名域名”但实际用起来坑特别多。标准格式是local-partdomainlocal-part可以包含字母、数字、点、下划线、加号等但有一些限制。比如点不能出现在开头或结尾不能连续出现两个点。域名部分必须是有效的DNS域名不能是IP地址虽然技术上某些场景可以但实际会被拒。我见过最常见的错误是大小写问题。理论上local-part是区分大小写的但实际几乎所有邮件服务器都当成不区分大小写处理。所以你把张三写成ZhangSanexample.com还是zhangsanexample.com通常都能收到。但域名部分绝对不区分大小写这个没商量。另一个高频错误是多余的空格。有时候从网页复制邮件地址前后会带空格或者中间混入不可见字符。这种地址发出去服务器直接拒收而且报错信息往往很模糊让你查半天。我的习惯是拿到邮件地址后先用正则过一遍把首尾空格去掉再检查有没有连续点、有没有符号缺失。还有一个坑是“加号别名”。很多邮件服务支持usertagexample.com这种格式加号后面的内容会被忽略邮件还是投到userexample.com。这个特性特别适合做邮件分类或者追踪来源。比如你注册某个网站时用userwebsiteexample.com如果以后收到垃圾邮件你就知道是哪个网站泄露了你的地址。2.2 邮件头部的关键字段及其作用邮件内容其实分成两大部分邮件头Header和邮件体Body。邮件头里有一堆字段每个字段都有特定用途不是随便写的。我挑几个最关键的讲。From字段是显示给收件人看的发件人地址。但注意From字段是可以伪造的SMTP协议本身不验证这个。所以你会收到很多冒充银行的诈骗邮件From显示的是bankxxx.com实际发件人完全不是。这也是为什么后来出现了SPF、DKIM、DMARC这些验证机制。To字段是收件人地址Cc是抄送Bcc是密送。Bcc比较特殊它在邮件头里不会出现收件人看不到密送给了谁。这个特性有时候被用来做批量发信但容易被判定为垃圾邮件。Subject字段是邮件主题这个字段如果包含非ASCII字符比如中文必须进行编码。标准做法是用MIME编码格式是?字符集?编码方式?编码后的内容?。比如“?UTF-8?B?5L2g5aW9?”解码后就是“你好”。很多邮件库会自动处理这个但如果你手动拼邮件内容忘了编码收件人看到的主题就是一串乱码。Date字段是邮件发送时间格式有严格要求必须是RFC 2822规定的格式比如“Tue, 15 Nov 2024 10:30:00 0800”。这个字段如果格式不对有些邮件客户端会显示异常甚至把邮件判定为可疑。Message-ID是邮件的唯一标识由发送方服务器生成。这个字段用于邮件追踪和去重格式类似“ randomdomain ”。如果你自己写邮件发送程序最好让库自动生成不要手动编。2.3 MIME编码为什么附件会变成乱码MIME多用途互联网邮件扩展是解决邮件只能发纯文本这个限制的关键技术。没有MIME之前邮件只能传ASCII字符中文、图片、附件统统发不了。MIME通过定义各种编码方式让邮件可以携带任意类型的数据。最常用的两种编码是Base64和Quoted-Printable。Base64把二进制数据转成64个可打印字符适合图片、附件这种二进制内容。Quoted-Printable则适合主要是ASCII但夹杂少量非ASCII的文本它把非ASCII字符转成XX的形式可读性比Base64好。我踩过最大的坑是附件文件名编码。早期邮件协议规定附件文件名只能用ASCII中文文件名必须编码。但不同邮件客户端对编码的支持程度不一样有的用RFC 2047有的用RFC 2231导致中文附件名在不同客户端显示效果千奇百怪。有的显示正常有的显示一串?UTF-8?B?...?有的直接乱码。后来我学乖了给用户发附件时文件名尽量用英文加数字实在要用中文就在邮件正文里也说明一下附件名称。还有一个坑是邮件体编码和传输编码的混淆。Content-Type里的charset指定的是字符集比如UTF-8Content-Transfer-Encoding指定的是传输编码比如Base64。这两个是不同层面的东西但经常被搞混。如果你把charset设成UTF-8但传输编码用了7bit中文就会出问题。# 一个典型的MIME邮件构造示例Python from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.application import MIMEApplication from email.header import Header msg MIMEMultipart() msg[From] Header(发件人名称, utf-8) msg[To] Header(收件人名称, utf-8) msg[Subject] Header(邮件主题, utf-8) # 正文 body MIMEText(这是邮件正文内容, plain, utf-8) msg.attach(body) # 附件 with open(report.pdf, rb) as f: att MIMEApplication(f.read()) att.add_header(Content-Disposition, attachment, filename(utf-8, , 报告.pdf)) msg.attach(att)提示用Python的email库构造邮件时Header对象会自动处理中文编码比手动拼字符串靠谱得多。3. 发信实操从零搭建一个稳定的邮件发送流程3.1 选择发信方式自建服务器还是用第三方服务这是每个要做邮件发送的人面临的第一个决策。我两种方式都用过各有各的适用场景。自建邮件服务器意味着你要自己装Postfix、Exim或者Sendmail自己配DNS记录自己维护IP信誉。好处是可控性高发信量大的时候成本低。坏处是门槛高IP信誉需要时间积累新IP直接发信基本都进垃圾箱。而且很多云服务商默认封25端口你得申请解封还不一定批。第三方邮件服务则是把发信这件事外包出去你调API就行。好处是省心对方帮你处理IP信誉、退信、统计。坏处是要花钱免费额度通常很少而且有些服务对发信内容有审核。我的建议是如果你只是偶尔发几封通知邮件用个人邮箱的SMTP就行比如企业邮箱或者某个免费邮箱的授权码。如果你要发大量邮件比如用户注册验证、订单通知那就用第三方服务别自己折腾。自建服务器只适合有专门运维团队、发信量极大、对成本极度敏感的场景。对比项自建邮件服务器第三方邮件服务初始成本高需要服务器和运维低按量付费维护成本高IP信誉、反垃圾低服务商负责可控性高中送达率取决于IP信誉通常较高适合场景大型企业、特殊需求中小规模、快速上线3.2 SMTP认证与授权码的正确使用姿势不管你用哪种方式发信SMTP认证都是绕不开的。认证方式主要有三种LOGIN、PLAIN、CRAM-MD5。现在最常见的是LOGIN和PLAINCRAM-MD5因为安全性问题已经很少用了。这里有个特别容易搞混的点很多邮箱服务不支持直接用登录密码做SMTP认证而是要求你生成一个“授权码”或“应用专用密码”。比如某个邮箱你开启SMTP服务后它会给你一串随机字符你用这串字符代替密码。这样做的好处是即使授权码泄露也不会影响你邮箱的登录密码。我见过太多人在这上面翻车代码里填的是邮箱登录密码结果一直报认证失败查了半天以为是代码问题其实是没生成授权码。所以第一步永远是去邮箱设置里找“SMTP服务”或“客户端授权”相关的选项开启它拿到授权码。认证过程本身不复杂就是客户端把用户名和密码或授权码用Base64编码后发给服务器。但注意Base64不是加密只是编码所以SMTP认证必须配合TLS加密使用否则密码等于裸奔。现在主流做法是先连25端口发STARTTLS命令升级到加密连接然后再认证。或者直接连465端口从一开始就是SSL/TLS加密。# 用openssl测试SMTP认证示例 openssl s_client -connect smtp.example.com:465 # 连接成功后输入 EHLO test AUTH LOGIN # 然后输入Base64编码的用户名和密码注意生产环境不要用明文方式在命令行里输密码这里只是演示协议交互过程。3.3 邮件内容构造纯文本、HTML和附件的混合编排一封实用的邮件通常不是纯文本而是HTML格式可能还带附件。构造这种邮件需要用MIMEMultipart把不同部分组合起来。结构上最外层是multipart/mixed表示这是一个混合内容。里面可以放一个multipart/alternative用来放纯文本和HTML两个版本的正文。为什么要有纯文本版本因为有些邮件客户端或者某些场景下不支持HTML纯文本是保底。然后附件作为独立的部分挂在multipart/mixed下面。我刚开始写的时候直接把HTML字符串塞进MIMEText结果中文乱码。后来发现必须指定字符集为utf-8而且HTML内容里也要有对应的meta标签。另外HTML邮件里不要用太复杂的CSS很多邮件客户端会过滤掉style标签和外部样式表。内联样式是最稳妥的虽然写起来麻烦但兼容性最好。附件的处理也有讲究。附件内容要先用Base64编码然后设置Content-Disposition为attachment并指定filename。filename如果包含中文要用RFC 2231编码格式是filename*utf-8%E6%8A%A5%E5%91%8A.pdf。很多邮件库会自动处理但如果你手动构造很容易漏掉。还有一个细节是附件大小。大多数邮件服务器对单封邮件大小有限制通常是10MB到25MB。超过限制会被拒收。如果你要发大文件正确做法是把文件上传到某个存储服务然后在邮件里放下载链接而不是硬塞附件。3.4 发信频率控制与退信处理发信频率是个容易被忽视但极其重要的问题。很多邮件服务商对发信频率有严格限制比如每分钟最多发多少封、每天最多发多少封。如果你短时间内发大量邮件轻则被限流重则被封号。我吃过一次亏有个告警系统某次故障导致短时间内触发了几百条告警系统疯狂发邮件结果发信账号直接被封了24小时。后来我加了限流逻辑用队列控制发信速度比如每秒最多发一封超过的排队等待。同时设置告警聚合相同类型的告警合并成一封邮件避免轰炸。退信处理也是必须考虑的。退信分两种硬退信和软退信。硬退信表示收件人地址不存在这种要立即从列表里移除不要再发。软退信表示临时问题比如对方邮箱满了、服务器暂时不可达这种可以重试几次。如果你不处理退信继续给无效地址发信你的发信信誉会迅速下降。# 简单的发信限流示例 import time from collections import deque class RateLimiter: def __init__(self, max_per_minute): self.max_per_minute max_per_minute self.timestamps deque() def wait_if_needed(self): now time.time() # 移除一分钟前的时间戳 while self.timestamps and now - self.timestamps[0] 60: self.timestamps.popleft() if len(self.timestamps) self.max_per_minute: sleep_time 60 - (now - self.timestamps[0]) if sleep_time 0: time.sleep(sleep_time) self.timestamps.append(time.time())提示退信通常不会直接返回给发信程序而是发到发件人邮箱里。你需要定期检查发件人邮箱解析退信内容更新收件人列表。4. 收信与邮件解析把邮件变成程序能用的数据4.1 IMAP与POP3的选择与连接配置收信这块我强烈建议用IMAP除非你有特殊理由必须用POP3。IMAP的优势太明显了多设备同步、服务器端搜索、部分下载。POP3那套“下载并删除”的逻辑在现在这个多设备时代基本就是给自己找麻烦。IMAP连接配置有几个关键参数服务器地址、端口、加密方式、用户名、密码。端口143是明文993是SSL/TLS。现在基本都用993。连接建立后你需要选择邮箱文件夹通常是INBOX。然后可以搜索邮件、获取邮件内容、标记已读、移动邮件。IMAP协议本身挺复杂的但用现成的库就简单多了。Python里用imaplibJava里用JavaMailNode.js里用imap模块。这些库把协议细节封装好了你只需要调方法就行。但要注意IMAP连接是有状态的你得保持连接或者定期重连。长时间不操作服务器可能会断开连接。我遇到过一个坑用IMAP拉取大量邮件时如果一次性拉太多服务器会超时或者限流。正确做法是分批拉取比如每次拉50封处理完再拉下一批。另外拉取邮件内容时如果只要邮件头可以用FETCH命令只取HEADER部分速度会快很多。4.2 邮件解析从原始文本到结构化数据从IMAP拉下来的邮件是原始文本包含邮件头和邮件体还有各种MIME边界。你需要把它解析成结构化数据才能提取发件人、主题、正文、附件。Python的email库是解析邮件的利器。用email.message_from_string()或者email.message_from_bytes()把原始文本转成Message对象然后就可以遍历各个部分。邮件的结构可能是嵌套的比如multipart/mixed里面套multipart/alternative你需要递归遍历。解析时最常见的坑是编码问题。邮件头里的中文可能是Base64编码也可能是Quoted-Printable编码还可能是未编码的原始字节。你需要用email.header.decode_header()来处理。邮件体的编码则要看Content-Transfer-Encoding字段可能是7bit、8bit、Base64、Quoted-Printable等。附件提取也是常见需求。遍历邮件各部分找到Content-Disposition为attachment的部分获取filename和payload然后解码保存。注意filename可能也是编码过的需要解码。# 邮件解析示例 import email from email.header import decode_header def parse_email(raw_email): msg email.message_from_string(raw_email) # 解析主题 subject, encoding decode_header(msg[Subject])[0] if isinstance(subject, bytes): subject subject.decode(encoding or utf-8) # 解析发件人 from_addr msg[From] # 遍历邮件部分 for part in msg.walk(): content_type part.get_content_type() if content_type text/plain: body part.get_payload(decodeTrue).decode(utf-8) elif content_type application/octet-stream: filename part.get_filename() if filename: with open(filename, wb) as f: f.write(part.get_payload(decodeTrue))注意decode_header返回的可能是多个片段需要拼接。而且encoding可能是None这时候要用默认编码。4.3 邮件搜索与过滤规则的实际应用IMAP支持服务器端搜索这个功能特别实用。你可以按发件人、主题、日期、已读状态等条件搜索邮件不用把所有邮件都拉到本地再过滤。搜索条件用IMAP的SEARCH命令语法类似SEARCH FROM someoneexample.com SINCE 01-Jan-2024。多个条件可以组合比如SEARCH UNSEEN FROM alertexample.com表示搜索来自alert的未读邮件。我在做告警邮件处理时就是先用IMAP搜索未读的告警邮件然后逐封解析提取告警内容写入数据库最后标记为已读。这样既不会重复处理也不会漏掉。过滤规则方面除了IMAP搜索还可以在本地做更复杂的过滤。比如按正则匹配主题、按关键词过滤正文、按附件类型过滤。我一般会把过滤逻辑写成配置方便调整而不是硬编码在代码里。5. 邮件安全与送达率那些没人明说但必须知道的规则5.1 SPF、DKIM、DMARC三件套到底在干什么这三个东西是邮件安全的基石但很多人只是听说过不知道具体作用。我用最直白的话解释。SPF是发件人策略框架。它在DNS里加一条TXT记录列出哪些服务器有权代表你的域名发邮件。接收方收到邮件后检查发件服务器IP在不在SPF记录里不在就判定为伪造。SPF解决的是“谁有权发”的问题。DKIM是域名密钥识别邮件。它用私钥对邮件内容签名接收方用DNS里的公钥验证签名。签名验证通过说明邮件内容没被篡改而且确实来自该域名。DKIM解决的是“内容有没有被改”的问题。DMARC是基于SPF和DKIM的策略框架。它告诉接收方如果SPF和DKIM都验证失败该怎么处理这封邮件是放行、隔离还是拒收。同时DMARC还要求一个报告地址接收方会定期把验证结果发到这个地址让你知道谁在用你的域名发邮件。DMARC解决的是“验证失败怎么办”的问题。这三个记录缺一不可。只配SPF不配DKIM邮件可能被篡改只配DKIM不配SPF伪造发件人还是防不住配了SPF和DKIM但不配DMARC接收方不知道失败后该怎么处理。我见过很多公司只配了SPF就以为万事大吉结果发信还是进垃圾箱。机制作用DNS记录类型解决什么问题SPF声明合法发信服务器TXT防止伪造发件人DKIM对邮件内容签名TXT防止内容篡改DMARC定义验证失败策略TXT统一处理策略和报告5.2 避免进垃圾箱的实操经验邮件进垃圾箱是发信方最头疼的问题。我总结了几条实操经验都是踩坑踩出来的。第一新IP或新域名不要一上来就大量发信。先从小量开始慢慢增加发信量让接收方逐渐建立信任。这个过程叫“IP预热”通常需要几周时间。第二邮件内容要规范。不要用全大写主题不要用太多感叹号不要放短链接不要用“免费”“中奖”“点击这里”这种垃圾邮件高频词。HTML邮件要有纯文本版本图片不要太多文字和图片比例要合理。第三退信率要控制。硬退信率超过5%就很危险了超过10%基本会被拉黑。所以要及时清理无效地址不要反复给退信地址发信。第四投诉率要关注。如果用户把你的邮件标记为垃圾邮件投诉率上升你的发信信誉会下降。所以邮件要有明确的退订链接而且退订要真的生效不能玩花样。第五发信频率要稳定。不要今天发10封明天发10000封这种突变会被判定为异常。保持平稳的发信节奏让接收方觉得你是一个正常的发件人。提示可以用一些在线工具检查你的域名SPF、DKIM、DMARC配置是否正确也可以检查你的IP是否在常见黑名单里。5.3 邮件内容安全防钓鱼与防伪造除了送达率邮件安全还包括防钓鱼和防伪造。作为发信方你要确保自己的邮件不被用来钓鱼作为收信方你要能识别钓鱼邮件。发信方要做的配置好SPF、DKIM、DMARC让接收方能验证你的邮件。邮件里的链接要用HTTPS不要用短链接掩盖真实地址。不要在邮件里索要密码、验证码等敏感信息。收信方要做的检查邮件头里的Received字段看邮件实际经过哪些服务器。检查From和Return-Path是否一致。检查链接的真实地址不要只看显示文字。对可疑附件不要打开尤其是.exe、.scr、.js这种可执行文件。我处理过一起钓鱼邮件事件攻击者伪造了公司域名发信但SPF没配好接收方服务器直接拒收了。后来我们赶紧把DMARC策略从none改成quarantine再改成reject伪造邮件就基本进不来了。所以DMARC策略不要一直停在none要逐步升级。6. 常见问题排查与实战避坑指南6.1 发信失败认证错误、连接超时、被拒收发信失败是最常见的问题原因五花八门。我整理了一个排查表按报错信息快速定位。报错信息可能原因排查方法535 Authentication failed用户名密码错误或未用授权码检查是否开启SMTP服务是否用授权码代替密码Connection timed out端口被封或服务器地址错误检查端口是否开放尝试587或465端口550 Relay access denied未认证或不允许中继确保先认证再发信检查发件人域名是否匹配554 Message rejected内容被判定为垃圾邮件检查邮件内容降低垃圾邮件特征421 Too many connections连接数超限降低并发增加发送间隔认证错误是最多的。除了授权码问题还有一种情况是邮箱服务要求用特定的认证方式。比如有的只支持LOGIN有的只支持PLAIN。你可以用telnet或openssl手动测试看服务器支持哪些认证方式。连接超时通常是网络问题或端口被封。很多云服务器默认封25端口你需要用587或465。如果587和465也连不上检查防火墙规则和安全组设置。被拒收的原因就更多了。可能是你的IP在黑名单里可能是发件人域名没配SPF可能是邮件内容触发了垃圾邮件规则也可能是收件人不存在。需要看具体的退信信息里面通常会有原因代码。6.2 收信异常乱码、附件丢失、连接断开收信异常里乱码是最常见的。乱码分几种主题乱码、正文乱码、附件名乱码。主题乱码通常是编码声明和实际编码不一致或者没做MIME编码。正文乱码可能是charset设错了比如实际是GBK但声明成UTF-8。附件名乱码则是RFC 2047和RFC 2231的兼容性问题。解决乱码的思路是先看原始邮件内容找到Content-Type里的charset再看Content-Transfer-Encoding然后用对应的方式解码。如果charset是unknown-8bit那就得猜编码通常中文邮件不是UTF-8就是GBK。附件丢失可能是解析时没遍历到或者附件部分被当成了正文。用msg.walk()遍历所有部分检查每个部分的Content-Disposition。如果是inline可能显示在正文里如果是attachment就是附件。连接断开通常是IMAP连接超时。IMAP连接默认空闲一段时间后会被服务器断开。解决办法是定期发NOOP命令保持连接或者每次操作前检查连接状态断了就重连。6.3 送达率优化从黑名单到白名单的实战路径送达率优化是一个长期过程没有一劳永逸的办法。我的经验是分几步走。第一步检查基础配置。SPF、DKIM、DMARC是否都配了MX记录是否正确反向DNSPTR记录是否配了反向DNS特别重要很多接收方会检查发信IP的PTR记录如果没有或者不匹配直接拒收。第二步检查IP信誉。用在线工具查你的发信IP是否在常见黑名单里。如果在先申请移除然后找出被封的原因避免再次被封。第三步优化邮件内容。做A/B测试看哪种主题、哪种内容、哪种发送时间的打开率最高。避免垃圾邮件高频词保持文字和图片的合理比例。第四步管理收件人列表。定期清理无效地址处理退信尊重退订请求。不要购买邮件列表不要给未订阅的用户发信。第五步逐步提升发信量。新IP或新域名要慢慢预热不要急于求成。可以先给活跃用户发再逐步扩大范围。提示送达率优化是一个持续的过程不是配好SPF就完事了。要定期检查、定期调整。6.4 独家避坑技巧那些文档里不会写的东西最后分享几个文档里不会写但特别实用的技巧。第一个测试发信时不要用自己的主邮箱。用一个专门的测试邮箱避免测试邮件污染主邮箱也避免主邮箱被标记。测试邮箱最好用不同服务商的比如一个用A服务商一个用B服务商这样能测试不同接收方的兼容性。第二个邮件里的链接要用完整的绝对路径不要用相对路径。有些邮件客户端会把相对路径解析错导致链接打不开。而且链接域名最好和发件人域名一致不一致容易被判定为钓鱼。第三个附件文件名不要用特殊字符。空格、中文、括号、斜杠这些字符在不同客户端表现不一样。最稳妥的是用英文、数字、下划线、连字符长度控制在50个字符以内。第四个发信日志要保留。至少保留最近30天的发信日志包括收件人、发信时间、服务器响应。出问题的时候日志是排查的唯一依据。我见过有人发信失败但什么日志都没留只能靠猜。第五个不要忽视邮件模板的兼容性。同一个HTML邮件在Outlook、Gmail、Foxmail里显示效果可能完全不同。发之前最好在多个客户端里测试一下或者用一些在线工具预览。第六个退订链接要简单直接。不要要求用户登录才能退订不要设置复杂的退订流程。退订越麻烦用户越可能直接点“标记为垃圾邮件”这对你的发信信誉伤害更大。我个人在实际操作中的体会是电子邮件这套东西入门容易精通难。协议本身不复杂但实际用起来细节特别多每个细节都可能成为翻车的点。最好的学习方式就是动手发几封然后看退信、看日志、看垃圾箱慢慢就摸清楚规律了。别怕犯错但要从错误里总结下次别再犯同样的错。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑