AI 机器人代发的邮件进 139 垃圾箱?一次 EX-QQ-AI-BOTID 指纹定位与 SMTP 直发对照实验

上一篇《企业邮箱发 139 邮箱总进垃圾箱:一次 SPF / DKIM / DMARC 排查实录》解决了 DNS 认证缺项,邮件恢复正常进收件箱,我以为这事就完结了。结果当天晚上,同一套企业邮箱、同一个收件人、三项认证齐全,测试邮件又进了 139 的垃圾箱——区别只有一个:这封信不是我自己点的发送,而是让 AI 助手(企业微信机器人)代发的。这篇记录怎么用三封对照邮件把问题钉死,以及顺手解掉的另一个谜:为什么自己的邮件会被 139 标注”来自境外”。

先说结论

  1. 机器人代发指纹是进垃圾箱的决定性因素。企业微信接口代发的邮件,源码里带有 EX-QQ-AI-BOTID 头,且 From 显示名是机器人名——收件方反垃圾引擎据此加权,直接进垃圾箱。
  2. 发件地址用主地址还是别名,对落点没有影响。两条地址走 SMTP 直发都进了收件箱。
  3. SMTP 直发的邮件会被腾讯调度到海外网关投出,因此被 139 标注”来自境外”——但实测垃圾分为 0、正常进收件箱,标签没有实际负面影响。

现象:同一邮箱,三种发法,三种待遇

域名是同一个 *.site 子域,SPF / DKIM / DMARC 三项认证前一天刚全部补齐并验证生效,收件人都是我自己的 139 邮箱:

# 发件地址 发信通道 发件人显示名 139 落点
1 别名地址 企业微信机器人接口代发 机器人名(YSBot) ❌ 垃圾箱
2 主地址 SMTP 直连 本人名字 ✅ 收件箱
3 别名地址 SMTP 直连 本人名字 ✅ 收件箱

三封信主题相近、正文长短相近、发送时间在一小时内。变量只剩两个:发信通道和发件地址。对照实验正好能把它们分开。

定位:邮件源码里写着答案

在 139 邮箱网页版打开进垃圾箱的那封 →「更多」→「查看邮件源码」。这里有个小坑:139 的 RichMail 系统通常不回注 Authentication-Results 行,上一篇提到的”看认证结果”技巧在 139 侧经常派不上用场。但没有关系,源码里的另外几个头部足够说明问题:

X-RM-SPAM-FLAG:00000005          ← 139 反垃圾引擎的垃圾判定,非 0 即被判了
EX-QQ-AI-BOTID: 33777000132280559 ← 腾讯给这封信打上的"AI 机器人发送"标记
From: "YSBot" <you@mail.example.com>  ← 发件人显示名是机器人名
DKIM-Signature: v=1; a=rsa-sha256; d=mail.example.com; s=qfog2609; ...
                                  ← 签名正常,通道认证没问题

判读思路:

  • X-RM-SPAM-FLAG:00000005 说明垃圾判定是 139 自己的反垃圾引擎打出来的;
  • EX-QQ-AI-BOTID + 机器人显示名,等于明明白白告诉收件方”这是机器批量发的”——个人邮箱收到一封显示名为机器人的来信,像垃圾邮件几乎是合理怀疑;
  • DKIM 签名的 d=、s= 与后台配置完全一致,说明 DNS 认证链路完好,问题不在”谁发的”认证上,而在”怎么发的”方式上。

关键是:企业微信的邮件发送接口没有任何参数可以去掉这些标记——EX-QQ-AI-BOTID 是接口代发的固有指纹,显示名取自机器人配置。想不带指纹,只能换通道。

解决:绕开接口,SMTP 直连

腾讯企业邮箱本身提供标准 SMTP 服务,直连发送的邮件没有机器人指纹,而且发件地址、显示名完全由自己指定——顺便解决了另一个痛点:企业微信接口代发时 From 自动取邮箱的”默认发信地址”,想用主地址还是别名,得去网页版手动切换;SMTP 直发想用哪个就用哪个。

前提准备(一次性):

  1. 邮箱网页版「设置 → 收发信设置」开启 IMAP/SMTP 服务(服务器 smtp.exmail.qq.com,SSL 端口 465);
  2. 「设置 → 账户 → 账户安全」生成客户端专用密码(安全密码)。它是独立于登录密码的专用凭据,泄露了可以随时单独重置;不要把登录密码写进脚本。

发送端用 Python 标准库就够了,不需要任何第三方依赖:

import smtplib
from email.mime.text import MIMEText
from email.header import Header
from email.utils import formataddr

msg = MIMEText(open("body.txt", encoding="utf-8").read(), "plain", "utf-8")
msg["Subject"] = Header("测试邮件", "utf-8")
msg["From"] = formataddr((str(Header("你的名字", "utf-8")), "you@example.com"))
msg["To"] = "18xxxxxxxxx@139.com"

with smtplib.SMTP_SSL("smtp.exmail.qq.com", 465, timeout=30) as s:
    s.login("you@example.com", "客户端专用密码")   # 密码放本地配置文件,别提交进仓库
    s.sendmail("you@example.com", ["18xxxxxxxxx@139.com"], msg.as_string())

发完做对照实验,三封信的落点就是开头那张表:SMTP 直发的两封(主地址、别名)全部进收件箱,接口代发的那封进垃圾箱。变量分离干净利落。

彩蛋:为什么 SMTP 直发的信被标”来自境外”

SMTP 直发的两封虽然进了收件箱,列表里却被 139 标注了”来自境外”,而机器人代发那封反而没有。继续看源码最后一跳:

# SMTP 直发(标"来自境外"):
Received: from smtpbguseast1.qq.com (unknown[54.204.34.129])
    by rmmx-lg_mx13-12072 (RichMail) with SMTP id ...

# 机器人接口代发(不标):
Received: from bg5.exmail.qq.com (unknown[43.154.155.102])
    by rmmx-lg_mx18-12111 (RichMail) with SMTP id ...

54.204.x.x 是 AWS 美东(弗吉尼亚)网段,主机名里的 useast1 就是 US-East-1——腾讯把 SMTP 提交的邮件调度到了海外边界网关投出,139 按 IP 归属地打了标签;接口代发走内部队列,从国内出口集群投出,所以没标签。这个调度由腾讯内部决定,客户端无法指定。

要不要紧?看数据:境外出口那封 X-RM-SPAM-FLAG:00000000——垃圾分是 0,比代发那封的 00000005 还干净,且正常进收件箱。所以这个标签目前纯属观感问题,接受现状即可,后续留意它是否开始影响落点就行。

排查速查表

现象 结论与动作
认证三项齐全,仍进垃圾箱,且 From 显示名是机器人名 查源码有无 EX-QQ-AI-BOTID 等代发标记;换 SMTP 直连发送
139 源码里找不到 Authentication-Results 正常,RichMail 不回注;改看 X-RM-SPAM-FLAG 和 DKIM-Signature 的 d=/s=
想按次指定发件地址(主地址/别名) 企微接口无 from 参数;SMTP 直发可任意指定自有地址和显示名
SMTP 直发的邮件被标”来自境外” 腾讯出口网关调度所致(实测 AWS US-East-1),垃圾分不受影响,可接受
子域发信地址是不是必须改绑主域 子域确属减分项,但实测 SMTP 直发进收件箱;先跑起来观察,不急着动 DNS

写在最后

上一篇把”DNS 认证”这层确定性问题解决后,我以为邮件投递的坑已经见底,结果”发信通道”这个更隐蔽的变量紧跟着浮了出来——同一个邮箱,换个发送方式,命运截然不同。AI 助手代发确实方便,但收件方的反垃圾系统认的是种种”像人”的信号:显示名、发送指纹、历史行为。让邮件看起来是”你”发的,而不只是”以你的地址”发的,这件事在接口代发场景下做不到,那就换一条做得到的路。

方法论上,这次再次验证了两把刀的好用:对照实验(控制变量,一封封发)和邮件源码(所有结论都要落到具体头部字段上)。玄学问题的答案,通常就写在 header 里。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

顶部