net.lookupmx可直接获取域名mx记录,返回*net.mx切片,需传纯域名(如"github.com"),错误输入会报"no such host"或"no mx record";查不到时返回nil和error,须先判错;返回切片不保证按优先级排序,应手动sort.slice按pref升序排列。

用 net.LookupMX 获取域名 MX 记录最简路径
Go 标准库直接支持,不用额外包。调用 net.LookupMX 就能拿到 MX 主机名和优先级,返回的是 []*net.MX 切片,每个元素含 Host 和 Pref 字段。
常见错误是传入带 mail. 或 smtp. 前缀的域名,或者误加 http:// —— 它只接受纯域名(如 "google.com"),不接受 URL 或子域名(除非你真想查那个子域名的 MX)。
- 正确:
net.LookupMX("github.com") - 错误:
net.LookupMX("mail.github.com")(除非该子域单独配置了 MX) - 错误:
net.LookupMX("https://github.com")(会报no such host)
查不到 MX 时,net.LookupMX 返回什么
它不会静默失败。查不到记录时,返回 nil, error,error 通常是 *net.DNSError,其中 Err 字段为 "no such host" 或 "no MX record"。注意:这两个错误含义不同 —— 前者是域名根本解析失败(DNS 层问题),后者才是明确没有 MX 记录。
- 遇到
"no such host":先用nslookup github.com或dig github.com A确认基础 DNS 是否通 - 遇到
"no MX record":说明该域名确实没配邮件路由,比如纯前端站点 - 别把
nil切片当成空切片 —— 检查前务必先判错:if err != nil { ... }
MX 记录顺序不等于投递优先级
net.LookupMX 返回的切片默认按优先级(Pref)升序排列,但 RFC 5321 明确要求:客户端必须按优先级升序尝试,同优先级才可随机或轮询。Go 不保证返回顺序绝对稳定(底层依赖系统 resolver),所以不能依赖切片索引取“第一台服务器”。
立即学习“go语言免费学习笔记(深入)”;
- 务必手动排序:
sort.Slice(mxRecords, func(i, j int) bool { return mxRecords[i].Pref - 同优先级的 MX(如两个 Pref=10)必须都保留,不能只取第一个
- 真实投递时还要做连接探测(TCP 连接 + EHLO),优先级只是初始调度依据
本地 DNS 配置可能干扰结果
net.LookupMX 默认走系统 resolver(/etc/resolv.conf 或 Windows DNS 设置),不是直连根 DNS。这意味着:公司内网、Docker 容器、某些 macOS 的 mDNS 配置,都可能导致查到私有 MX 记录(比如内部 Exchange 地址),而非公网结果。
- 调试时用
dig +short example.com MX对比,确认是否 resolver 差异 - 生产环境若需确定性,可换用
miekg/dns库直连指定 DNS 服务器(如8.8.8.8:53) - Go 1.19+ 支持
net.DefaultResolver替换,但需注意PreferGo和StrictErrors行为差异
MX 查询看着简单,但实际落地时,resolver 行为、错误分类、优先级语义、网络环境这四点,任何一个没对齐,发信逻辑就可能静默降级或失败。










