有网友询问电子邮件发送不到Gmail的相关问题,我查了一下,大多数原因可能是Gmail连IPv6都要验证的关系,虽说Gmail真的满挑剔垃圾信件的(龙头老大的权威?!),但最重要的还是要设定好SPF (Sender Policy Framework“寄件者政策架构”)、DKIM (DomainKeys Identified Mail“网域金钥认证邮件”)、DMARC (Domain-based Message Authentication, Reporting & Conformance“网域型邮件验证、报告与一致性”)三大防堵垃圾信的规则,只要设定好三大规则和rDNS (Reverse DNS“IP反解”)/也可称之为PTR (Domain Name Pointer“指标记录”),几乎很难被判断为垃圾信件 😱🥶🙀
接下来我做的范例是在一个使用子网域的CentOS 8系统上,用既有的Let’s Encrypt免费SSL证书,大约花10分钟设定好Postfix使用TLS(Transport Layer Security“传输层安全性”)通讯协定,并且安装OpenDKIM替伺服器签署DKIM来防止被判断为垃圾信件 🤓
### 首先无论如何一定要设定好rDNS/PTR,无论是自己设定或是找主机商,都一定要先设定好rDNS/PTR来增强电子邮件的可靠度,这对现今的DNSBL(Domain Name System-based Blackhole List)或是RBL(Remote Blackhole List)两种主流的反垃圾信的黑清单列表服务是相对友好的,可以透过MxToolbox这个线上查询工具来查询IP是否被加入列表中;另外也很推荐到Google邮件管理员工具来验证网域名称拥有者 🏎🚄🚀
章节一、安装、设定相关套件
# 安装OpenDKIM、Postfix相关套件,并且移除sendmail 🤓
1 2 3 4 5 6 |
yum install -y dnf dnf-plugins-core epel-release redhat-lsb-core dnf install -y opendkim postfix telnet mailx mutt lsof curl perl net-tools yum-utils dnf remove -y sendmail dnf update -y systemctl enable opendkim && systemctl is-enabled opendkim systemctl enable postfix && systemctl is-enabled postfix |
### 因为我都是习惯用主机的子网域名称做为主机名称,所以只要替换好了验证器名称(lax7)与网域名称(520.be),下方的指令存到笔记之后,可以很方便的设定好伺服器 🤖🤓🤖
# 修改主机名称 🤓
sudo hostnamectl set-hostname lax7.520.be && sudo hostname lax7.520.be
exec bash
sed -i '/HOSTNAME/d' /etc/sysconfig/network
echo HOSTNAME=lax7.520.be >> /etc/sysconfig/network
cat /etc/sysconfig/network
# 修改hosts for IPv6,没IPv6的用下方指令 🤓
1 2 3 4 5 6 7 8 9 |
rm -f /etc/hosts.bak mv -f /etc/hosts /etc/hosts.bak sudo bash -c "echo '127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 `/usr/bin/curl -4 icanhazip.com` `cat /etc/hostname` `/usr/bin/curl -6 icanhazip.com` `cat /etc/hostname`' > /etc/hosts" clear cat /etc/hosts # vi /etc/hosts |
# 修改hosts for IPv4 🤓
1 2 3 4 |
sudo bash -c "echo '127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 `/usr/bin/curl -4 icanhazip.com` `cat /etc/hostname`' > /etc/hosts" clear cat /etc/hosts |
# 产生OpenDKIM的使用者,密码部分要输入两次唷 🤓
adduser opendkim
passwd opendkim
# 产生OpenDKIM的金钥,最重要的-s是指Selector (验证器名称),这个可以用来分别对子网域做DKIM,这边需要将lax7替换成要指定的验证器名称,例如a001、b002之类的都任意 🤓
# -d 小写的d是指所使用的网域名称,需要使用主网域而不是子网域,这点请特别注意。 🤓
# -D 大写的D是指输出档案到特定资料夹 🤓
# rm -fr /etc/opendkim/keys
mkdir -p /etc/opendkim/keys/520.be
opendkim-genkey -s lax7 -d 520.be -D /etc/opendkim/keys/520.be/
# 自订OpenDKIM的白名单,这边填上网域名称或拥有多个IP 🤓
1 2 3 4 5 6 7 8 9 10 11 |
cat <<"EOF" > /etc/opendkim/TrustedHosts # OPENDKIM TRUSTED HOSTS 127.0.0.1 ::1 localhost 520.be lax7.520.be EOF clear cat /etc/opendkim/TrustedHosts # vi /etc/opendkim/TrustedHosts |
### 从这边开始,接下来可以一次贴上一大堆指令 🏂🐱🏍🏄♂️
# 设定OpenDKIM相关资料夹、档案的权限 🤓
1 2 3 4 5 6 |
cd /etc/opendkim/keys/520.be usermod -a -G opendkim opendkim chown -R opendkim:opendkim /etc/opendkim chmod go-rwx /etc/opendkim/* chmod -R 0600 /etc/opendkim/keys/520.be/* ls -al |
# 自订OpenDKIM的验证器(Selector)名称、要通行的信箱名称 🤓
1 2 3 4 5 6 7 |
cat <<"EOF" > /etc/opendkim/SigningTable # OpenDKIM SIGNING TABLE *@lax7.520.be lax7._domainkey.520.be EOF clear cat /etc/opendkim/SigningTable # vi /etc/opendkim/SigningTable |
# 自订OpenDKIM金钥存放的位置 🤓
1 2 3 4 5 6 7 |
cat <<"EOF" > /etc/opendkim/KeyTable # OpenDKIM KEY TABLE lax7._domainkey.520.be 520.be:lax7:/etc/opendkim/keys/520.be/lax7.private EOF clear cat /etc/opendkim/KeyTable # vi /etc/opendkim/KeyTable |
# 编辑OpenDKIM的设定档 🤓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
cat <<"EOF" > /etc/opendkim.conf ### BASIC OpenDKIM CONFIGURATION FILE LogWhy Yes Syslog Yes SyslogSuccess Yes Mode sv Canonicalization relaxed/simple ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts KeyTable refile:/etc/opendkim/KeyTable SigningTable refile:/etc/opendkim/SigningTable SignatureAlgorithm rsa-sha256 Socket inet:8891@localhost PidFile /var/run/opendkim/opendkim.pid UMask 022 UserID opendkim:opendkim TemporaryDirectory /var/tmp EOF clear cat /etc/opendkim.conf # vi /etc/opendkim.conf |
# 重启OpenDKIM 🤓
1 2 3 |
systemctl restart opendkim && systemctl status opendkim -l lsof -itcp -n -P | grep opendkim lsof -itcp -n -P | grep ":8891" |
### 可以一次贴上的指令到这里,是不是省事很多 🐱👤🐱👤🐱👤
### 从这边开始,接下来是设定Postfix,只要你是CentOS 8系统,接下来一样可以一次贴上一大堆指令 🏂🐱🏍🏄♂️
# 备份Postfix设定档main.cf 🤓
1 2 |
curl -sF 'clbin=<-' https://clbin.com < /etc/postfix/main.cf cp /etc/postfix/main.cf /etc/postfix/main.cf.bak |
# 编辑Postfix的main.cf设定档,并且在最尾端增加启用DKIM、TLS的设定 🤓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
sed -i 's/^#myhostname = host.domain.tld/myhostname = lax7.520.be/g' /etc/postfix/main.cf cat /etc/postfix/main.cf | grep "myhostname =" sed -i 's/^#mydomain = domain.tld/mydomain = lax7.520.be/g' /etc/postfix/main.cf cat /etc/postfix/main.cf | grep "mydomain =" sed -i 's/^#myorigin = $mydomain/myorigin = $mydomain/g' /etc/postfix/main.cf cat /etc/postfix/main.cf | grep "myorigin =" sed -i 's/^inet_interfaces = localhost/inet_interfaces = all/g' /etc/postfix/main.cf cat /etc/postfix/main.cf | grep "inet_interfaces =" sed -i 's/^mydestination = $myhostname, localhost.$mydomain, localhost/# mydestination = $myhostname, localhost.$mydomain, localhost\nmydestination = $myhostname, localhost.$mydomain, localhost, $mydomain/g' /etc/postfix/main.cf cat /etc/postfix/main.cf | grep "mydestination =" sed -i 's/^#mynetworks = 168.100.189.0\/28, 127.0.0.0\/8/mynetworks = 192.168.1.0\/24, 127.0.0.0\/8/g' /etc/postfix/main.cf cat /etc/postfix/main.cf | grep "mynetworks =" sed -i 's/^#home_mailbox = Maildir\//home_mailbox = Maildir\//g' /etc/postfix/main.cf cat /etc/postfix/main.cf | grep "home_mailbox =" sed -i '$a\smtpd_use_tls = yes\nsmtpd_tls_auth_only = yes\nsmtpd_tls_loglevel = 1\nsmtpd_milters = inet:localhost:8891\nnon_smtpd_milters = \$smtpd_milters\nmilter_protocol = 2\nmilter_default_action = accept\nsmtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1\nsmtp_tls_protocols = !SSLv2, !SSLv3' /etc/postfix/main.cf tail -9 /etc/postfix/main.cf |
### 可以一次贴上的指令到这里 🐱👤🐱👤🐱👤
# 注意此处要填上fullchain档案的完整路径,且资料夹路径的/斜杠之前一个字要加一个反斜杠\,路径才会被正确解析 🤓
sed -i 's/^smtpd_tls_cert_file =.*$/smtpd_tls_cert_file = \/root\/.acme.sh\/lax7.520.be\/fullchain.cer/g' /etc/postfix/main.cf
cat /etc/postfix/main.cf | grep "smtpd_tls_cert_file ="
# 注意此处要填上SSL key档案的完整路径,且资料夹路径的/斜杠之前一个字要加一个反斜杠\,路径才会被正确解析 🤓
sed -i 's/^smtpd_tls_key_file =.*$/smtpd_tls_key_file = \/root\/.acme.sh\/lax7.520.be\/lax7.520.be.key/g' /etc/postfix/main.cf
cat /etc/postfix/main.cf | grep "smtpd_tls_key_file ="
# 如果没有做IPv6的rDNS(PTR),编辑Postfix的main.cf设定档,强制使用IPv4传输比较好对付挑剔的Gmail 🤓
1 2 |
sed -i 's/^inet_protocols =.*$/inet_protocols = ipv4/g' /etc/postfix/main.cf cat /etc/postfix/main.cf | grep inet_protocols |
# 重启Postfix 🤓
1 2 3 4 |
systemctl restart postfix && systemctl status postfix -l lsof -itcp -n -P | grep master lsof -itcp -n -P | grep ":25" lsof -itcp -n -P | grep ":587" |
章节二、添加相关的DNS记录
### 接下来到DNS服务商的网站将DKIM、DMARC、SPF三条记录加上,然后稍后测试发信,由于我的网域几乎都转到Gandi,这边是范例,首先读取一开始产生的OpenDKIM的公开金钥 🤖🤖🤖
cat /etc/opendkim/keys/520.be/lax7.txt
# 将p=后面一大串的数字替换到下方DKIM同样p=的内容,然后添加到DNS服务商 ⛷
lax7._domainkey 1800 IN TXT "v=DKIM1; k=rsa; " "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCebFp0On19i9mkwNRLUD/IpvtvQZsKykILf9xGDiWnpYrYy2hUMQrsMApJedzH0g5A5FNmUqDOZu73M+QnHX9j8G7tje0CJhrIUBHh+5LYhQcmlTAwSqhes21L661sGk9XtO5KvnvYt0dbDr7c+yb8FlBXgM3VfJd7mQaPCGsYYwIDAQAB"
# 添加SPF记录,注意SPF的部分要分别设定好IPv4/v6喔 🏂
lax7 1800 IN TXT "v=spf1 ip4:104.148.40.50 ip6:2001:470:c:995::2 ~all"
# 添加DMARC记录 🏇
_dmarc.lax7.520.be 1800 IN TXT "v=DMARC1; p=quarantine; sp=quarantine"
# Gandi的DNS大约1到10分钟内就能解析,所以喝口水、站起来动一动再回来验证密钥,只要看到最后出现key OK的字眼,就可以测试发信了 🥤🍩☕
host -ttxt lax7._domainkey.520.be
dig txt +short lax7._domainkey.520.be
opendkim-testkey -d 520.be -s lax7 -k /etc/opendkim/keys/520.be/lax7.private -v -v -v
### 验证方法,最简便的就是verifier.port25.com了,将xxoo替换成你的gmail前辍就行啦,port25.com就会将测试报告寄过来,另外也寄一封信到自己的gmail做测试 👺
echo "DKIM Test" | mutt -s "DKIM Test" check-auth-xxoo=gmail.com@verifier.port25.com
mail -vs "DKIM Test" check-auth@verifier.port25.com < /dev/null
echo "BACKUP" | mutt -s "BACKUP" xxoo@gmail.com -a "/etc/resolv.conf"
tail -20 /var/log/maillog
# 另外还有其他几个相同性质的测试网站 🤓
章节三、结语
# 其实这些操作都不难,很容易就能大功告成的,难的是思路(一点思路都没有就是多看书多吸收知识👹),有时就是会鬼打墙陷进某种不可说的循环 XD 另外如果你检查原始邮件档案的标头,会看到dkim=pass、spf=pass、dmarc=pass三大规则都通过了 🤖🤓🤖
Authentication-Results: mx.google.com;
dkim=pass header.i=@520.be header.s=lax7 header.b="GhAq/X84";
spf=pass (google.com: domain of root@lax7.520.be designates 104.148.40.50 as permitted sender) smtp.mailfrom=root@lax7.520.be;
dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=520.be
Received: by lax7.520.be (Postfix, from userid 0) id D6FFA40F6A84; Fri,
4 Dec 2020 11:48:36 +0800 (CST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=520.be; s=lax7; t=1607053716; bh=5g22i38m5ab1CDk2XO5BVyX7c5UtL2kHd7C21wyYSZE=; h=Date:To:Subject:From; b=GhAq/X84Nqs4BT2cz4CG5GkusJmOryR5vx1slte5lUKZzw+dMZuR2a9vDIJRgUSpC
+iwY6ls26AW+9EXsYXyddK2g+5NJ8CX7zYVqfzOgj6ySRCYEPlKhSmBZcYK5RxodJh
6bBsuJVq7FIq4AGoeVvP9E8aGZuA6hk9o3FzMuzM=
Date: Fri, 04 Dec 2020 11:48:36 +0800
To: xxoo@gmail.com
Subject: Postfix Test
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20201204034836.D6FFA40F6A84@lax7.520.be>
From: root
# SpamAssassin的标头结果如下,虽然我这台VPS的rDNS/PTR还没设定好,但结果还是负分-55,可以顺利进入收件箱;先试着做一次,之后将操作纪录存在记事本,很方便操作的 🍻🍺🍻
Return-Path:
Delivered-To: admin@xxoo.xxoo
Received: from arrow.mxrouting.net
by arrow.mxrouting.net with LMTP
id kPiiFdTHyV/CUAAATRu94g
(envelope-from
for
Return-path:
Envelope-to: admin@xxoo.xxoo
Delivery-date: Fri, 04 Dec 2020 06:23:32 +0100
Received: from xiaohe1.4iuhi.top ([104.148.40.50] helo=lax7.520.be)
by arrow.mxrouting.net with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
(Exim 4.94)
(envelope-from
id 1kl3Z5-0006nj-UZ
for admin@xxoo.xxoo; Fri, 04 Dec 2020 06:23:32 +0100
Received: by lax7.520.be (Postfix, from userid 0)
id 9567640F6A84; Fri, 4 Dec 2020 13:23:29 +0800 (CST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=520.be; s=lax7;
t=1607059409; bh=Axz2UOhEIqTuGOd8EYt6W3BJ1kk8HwljY6RakfeOtsk=;
h=Date:From:To:Subject;
b=hw+03di2vuU3WgbC64JE1YyFKsTcqLqdeXDPYrSCKC/tThgOFaiNElaXC8dOiIE5d
jnG7f9Zl+LtmavcJ+YFN3PB4GhYgUFRn9Uz8g0jqJiB8zyIeEu8Je4Ho2WnZQLDbNv
OjaOSuc0f/21bGbD7FCsKPQdqQqaCIQaL5vfWjgk=
Date: Fri, 4 Dec 2020 13:23:29 +0800
From: root
To: admin@xxoo.xxoo
Subject: BACKUP
Message-ID: <20201204052329.GA746738@lax7.520.be>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="sdtB3X0nJg68CQEu"
Content-Disposition: inline
User-Agent: Mutt/1.10.1 (2018-07-13)
Forward-Confirmed-ReverseDNS: Reverse and forward lookup success on 104.148.40.50, -10 Spam score
SPFCheck: Server passes SPF test, -30 Spam score
X-DKIM: signer='520.be' status='pass' reason=''
DKIMCheck: Server passes DKIM test, -20 Spam score
X-Spam-Bar: /
SpamTally: Final spam score: -55
ref.
- NCC – 邮件过滤
- HiNet IP反解服务使用说明
- 被gmail判成垃圾信件原因与建议处理方式
- CentOS Wiki – zh-tw/HowTos/Amavisd
- CentOS Wiki – zh-tw/HowTos/postfix_sasl
- Postfix TLS Support
- How to Set Up OpenDKIM on CentOS 8/RHEL 8 Mail Server
