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

Python邮件服务中dkimpy生成的DKIM签名验证失败问题求助

核心问题:To头添加时机错误

你在签名完成后才添加To头,但签名配置的include_headers包含了To字段。这会导致:

  • 签名生成时,邮件中还没有To头,签名的哈希计算不包含该字段
  • 最终发送的邮件带有To头,验证方会检查该字段是否被签名,发现签名与实际内容不匹配,直接判定DKIM失败

修复方案及潜在问题排查

1. 调整To头设置顺序

将To头的设置移到签名之前,确保签名时包含所有指定的头字段:

def sendTest(self, target):
    self.mail_tests = MIMEText("YO")
    self.mail_tests['Subject'] = "TEST"
    self.mail_tests['From'] = "NAME <" + self.address + ">"
    self.mail_tests['Message-ID'] = email.utils.make_msgid(domain='DOMAIN.TLD')
    # 先设置To头,再执行签名
    self.mail_tests['To'] = target
    self.signMail(self.mail_tests)

    self.sendMail(self.mail_tests.as_bytes(), target)

2. 避免格式转换破坏签名

使用as_string()可能会自动修改邮件的换行格式(如将\n转为\r\n),破坏签名的哈希一致性。建议直接发送as_bytes()生成的原始字节内容:

def sendMail(self, content_bytes, target):
    try:
        self.smtp.sendmail(self.address, target, content_bytes)
        print("sended", content_bytes.decode())
    except smtplib.SMTPException as e:
        print(f"Error sending a mail : {e}")

3. 统一域名格式

签名时使用的域名是DOMAIN.tld,但邮件和DNS记录中是DOMAIN.TLD。虽然DKIM对域名大小写不敏感,但统一格式可避免潜在解析问题:

sig = dkim.sign(
    message=mail.as_bytes(),
    selector="SELECTOR".encode(),
    domain="DOMAIN.TLD".encode(),  # 与DNS记录保持一致
    privkey=self.private.encode(),
    include_headers=headers,
)

4. 验证私钥有效性

确保私钥是标准PEM格式,包含完整的首尾标记(-----BEGIN RSA PRIVATE KEY-----和-----END RSA PRIVATE KEY-----),无多余空格或换行错误。


验证修复效果

修复后可通过以下方式确认:

  1. 对比邮件bh字段与正文的SHA256哈希(注意保持正文换行符与签名时一致)
  2. 使用离线DKIM验证工具检查签名有效性

内容的提问来源于stack exchange,提问作者lou habert

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 00:07:06