背景知识:什么是 SPF?
SPF(Sender Policy Framework,发送方策略框架)是一种电子邮件验证协议,定义在 https://datatracker.ietf.org/doc/html/rfc7208 中。它的核心作用是让域名所有者声明:哪些 IP 地址或服务器被允许代表该域名发送邮件。
接收方邮件服务器收到邮件后,会查询发件人域名的 SPF 记录(一条 DNS TXT 记录),检查连接 IP 是否在授权列表中。这能有效防止邮件伪造和钓鱼攻击。
一条典型的 SPF 记录长这样:
v=spf1 ip4:192.0.2.0/24 include:_spf.google.com ~all
Golang 解析
注意:这个库只有 12 次提交,已经 2 年多没有更新,肯定不完备,但是放在小工具中简单使用也没有什么问题。
UPDATE: 这个库太简陋了,不如自己写一个。
mileusna/spf 是一个轻量级的 Go 语言 SPF 检查库,提供了两个核心接口:
| 功能 | 函数 | 说明 |
|---|---|---|
| SPF 校验 | spf.CheckHost() |
给定 IP、域名和发件人,返回完整的 SPF 判定结果 |
| 记录查询 | spf.LookupSPF() |
仅从 DNS 拉取原始 SPF TXT 字符串 |
package main
import (
"net"
"github.com/mileusna/spf"
)
func main() {
// optional, set DNS server which will be used by resolver.
// Default is Google's 8.8.8.8:53
spf.DNSServer = "1.1.1.1:53"
ip := net.ParseIP("123.123.123.123")
r := spf.CheckHost(ip, "qq.com", "service@qq.com", "");
// returns spf check result
// "PASS" / "FAIL" / "SOFTFAIL" / "NEUTRAL" / "NONE" / "TEMPERROR" / "PERMERROR"
// if you only need to retrive SPF record as string from DNS
spfRecord, _ := spf.LookupSPF("qq.com")
fmt.Println(spfRecord)
// v=spf1 include:spf.mail.qq.com -all
}
spf.CheckHost() 返回以下 7 种字符串结果之一:
| 返回值 | 含义 | 邮件处理建议 |
|---|---|---|
"PASS" |
IP 被明确授权 | 正常接收 |
"FAIL" |
IP 不在授权列表中(-all 或 -ip4 匹配失败) |
建议拒收 |
"SOFTFAIL" |
软失败(~all),IP 可能未授权但无法确定 |
接受但标记/放入垃圾箱 |
"NEUTRAL" |
策略判定为中立(?all) |
按常规流程处理 |
"NONE" |
域名无 SPF 记录或记录无法解析 | 建议拒收 |
"TEMPERROR" |
DNS 临时错误(超时、SERVFAIL 等) | 可能是 DNS 抖动,稍后重试,暂不拒收 |
"PERMERROR" |
SPF 记录存在永久错误(语法错误、多重记录等) | 配置异常,建议拒收 |