You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python使用SMTPLIB、DKIMPY发邮件偶现550无From头退信问题

问题根因

这个偶发报错的核心原因是邮件头序列化时偶发丢失CRLF换行分隔符,导致接收方MTA无法识别独立的From头,和DKIM签名逻辑本身无关,你贴出的异常邮件源码已经暴露了序列化异常的特征:

  • 非参数类的头值末尾出现无意义的分号
  • MIME-Version: 1.0 没有作为独立头存在,直接拼在了上一个Content-Type头的boundary参数同一行

触发这个bug的直接原因是代码逻辑存在顺序问题:

  1. 第一次调用msg.as_bytes()生成待签名内容时,Python email模块会触发内部序列化逻辑,生成头折行缓存
  2. 之后手动给msg对象追加DKIM-Signature头,再第二次调用msg.as_bytes()生成最终发送内容时,旧版本email模块(尤其是Python3.6及以下使用compat32策略的版本)会偶发丢失头之间的换行符,导致多个头被拼接成同一个头的内容
  3. 当换行丢失的位置刚好出现在From头附近时,From头会被识别为上一个头的参数/值内容,接收方严格按RFC解析时就会统计到0个From头,触发550报错。因为折行逻辑和头长度、内容长度强相关,所以问题是偶发的,和你观察到的50封出1-2封的概率完全吻合。

另外还有两个潜在风险点:

  • 没有对传入头字段的变量做特殊字符清洗,如果个别发件人名称、主题、收件人地址里携带\r/\n换行字符,会触发头注入,同样会破坏头结构
  • DKIM签名覆盖的头列表不全,没有包含Date、Message-ID、Content-Type等标准头,容易被严格反垃圾系统拦截。
修复方案

按以下步骤调整代码即可彻底解决问题:

  1. 调整序列化和签名顺序,避免二次序列化
    先把所有邮件正文(plain、html部分)、所有标准头(To、From、Subject、Date、Message-ID)全部添加到msg对象完成后,只做一次序列化,DKIM签名生成后直接拼接在邮件字节流的头部,不要追加头到msg对象后再二次序列化。
    修正后的核心代码参考:
    msg = MIMEMultipart("alternative")
    msg.attach(MIMEText(self.email_text, "plain"))
    msg.attach(MIMEText(self.email_html, "html"))
    
    msg["To"] = self.to_email
    msg["From"] = f"{self.from_name} <{self.from_email}>" if self.from_name else self.from_email
    msg["Subject"] = self.subject
    msg['Date'] = formatdate()
    msg['Message-ID'] = make_msgid(domain=self.sender_domain)
    
    # 所有内容、头添加完成后,只做一次序列化拿到待签名原文字节流
    msg_bytes = msg.as_bytes()
    # 补全签名覆盖的头列表
    headers = [b'to', b'from', b'subject', b'date', b'message-id', b'mime-version', b'content-type']
    # 生成完整的DKIM签名字节串
    sig = dkim.sign(
        msg_bytes, 
        self.dkim_selector.encode(), 
        self.sender_domain.encode(), 
        self.dkim_key.encode(), 
        include_headers=headers
    )
    # 直接把签名拼在邮件字节流最前面,不再走msg对象序列化
    self.msg_data = sig + msg_bytes
    
  2. 增加头字段输入清洗
    所有赋值给头字段的变量(to_email、from_name、from_email、subject)提前做清洗,移除其中的\r、\n字符,避免偶发头注入破坏结构。
  3. 升级email模块策略(可选)
    如果使用Python3.7以下版本,建议升级到3.7+,使用默认的EmailPolicy替代旧的compat32策略,旧策略的折行、序列化逻辑存在多个已知的偶发bug。

内容的提问来源于stack exchange,提问作者Mr Growbot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 16:51:18