
后台点了“发送测试邮件”,页面提示成功,客户却始终没收到。登录主机面板一测才知道,共享主机的出站 25 端口已经被封,邮件根本没离开机房。这不是配置写错,而是绝大多数共享主机(一台服务器上同时跑多个网站的主机方案)的默认策略:25 端口是垃圾邮件最主要的出口,服务商通常在网络边界上直接丢包。
这篇文章按“先判断问题在哪一层、再把发信路径改道、最后用真实收信记录验证”的顺序,讲清楚如何在不换主机的情况下把网站发信切换到 SMTP 中继(由第三方邮件服务代为投递的中转服务器),以及怎样确认邮件进了收件箱。
先分清是端口不通,还是账号与域名的问题
不少站长把“发不出去”直接归因于封端口,其实相当一部分是凭据过期或 SPF 没覆盖新的发信 IP。判断顺序从网络层往应用层走,一层层排掉,免得在错的方向上改插件。PHP 默认经本机 sendmail 或本地 MTA(邮件传输代理)投递,走的就是 25 端口,这层不通,后面配什么都没用。
# 本机 25 端口:本地通、外部不通,说明出站方向被拦
nc -vz 127.0.0.1 25
# 中继的提交端口,587 是客户端投递邮件的标准端口
nc -vz smtp.yourprovider.com 587
# TLS 握手:失败通常是中间设备拦截了加密流量
openssl s_client -connect smtp.yourprovider.com:587 -starttls smtp
# 当前 SPF 记录:确认里面有中继服务商的授权段
dig +short TXT yourdomain.com
再去主机面板的邮件日志里搜 Connection timed out 和 Connection refused:前者是丢包,后者是明确拒绝,处理方式完全不同。如果 25 端口超时、587 端口能通,就别再等主机商解封,直接在应用层改道。

把 WordPress 的发信切到中继
改道的本质是把“本机投递”换成“认证后交给中继投递”。中继服务商校验账号密码后替你把邮件送到对方邮件服务器,既不需要开放入站端口,也不受 25 端口封锁影响,改动只发生在应用层,不用动系统服务。

方式一:用插件配置,适合不想碰代码的站点
装一个 SMTP 插件后填四项:中继地址、端口(常用 587,加密选 STARTTLS)、发信账号、应用专用密码。密码别用邮箱登录密码,主流邮箱都提供可单独吊销的应用密码,泄露时影响面小得多。
站点有本地、测试、生产多套环境时,建议在 wp-config.php 用常量固定,省得每次迁移重填:
define('WPMS_ON', true);
define('WPMS_SMTP_HOST', 'smtp.yourprovider.com');
define('WPMS_SMTP_PORT', 587);
define('WPMS_SSL', 'tls');
define('WPMS_SMTP_AUTH', true);
define('WPMS_SMTP_USER', 'no-reply@yourdomain.com');
define('WPMS_SMTP_PASS', 'app-specific-password');
define('WPMS_MAIL_FROM', 'no-reply@yourdomain.com');
define('WPMS_MAIL_FROM_FORCE', true);
define('WPMS_MAIL_FROM_NAME', 'Your Site Name');
define('WPMS_MAILER', 'smtp');
WPMS_MAIL_FROM_FORCE 这一行最容易被忽略。WordPress 默认发件地址是 wordpress@你的域名,多数中继要求发信账号与 From 一致,否则报 550 Sender address rejected,强制统一之后这类退信会立刻消失。
方式二:不装插件,用 mu-plugin 接管 PHPMailer
装了多个表单、通知类插件之后,插件冲突是共享主机上的常见麻烦。更干净的做法是把下面这段代码放进 wp-content/mu-plugins/smtp-relay.php:mu-plugin 自动加载、优先级高于普通插件,也不需要激活。
<?php
add_action('phpmailer_init', function ($phpmailer) {
$phpmailer->isSMTP();
$phpmailer->Host = 'smtp.yourprovider.com';
$phpmailer->Port = 587;
$phpmailer->SMTPAuth = true;
$phpmailer->Username = 'no-reply@yourdomain.com';
$phpmailer->Password = 'app-specific-password';
$phpmailer->SMTPSecure = 'tls';
$phpmailer->From = 'no-reply@yourdomain.com';
$phpmailer->FromName = 'Your Site Name';
});
这段代码只影响 WordPress 自身的邮件。站点若还跑着独立 PHP 脚本(订单通知、定时报表),它们不走这个钩子。至于要不要干脆把发信交给一台自己的邮件服务器,可以对照 VPS(虚拟专用服务器)邮件服务器搭建指南 评估:可控性更高,但 IP 信誉、反向解析和黑名单申诉都要自己扛。
方式三:用 msmtp 接管 sendmail 路径
共享主机一般允许在用户目录放可执行文件,但未必给 root,这时 msmtp 最省事:它把对 sendmail 的调用转成一次认证的中继投递。先写好 ~/.msmtprc,权限设成 600,否则 msmtp 会拒绝读取:
defaults
auth on
tls on
tls_starttls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.msmtp.log
account relay
host smtp.yourprovider.com
port 587
from no-reply@yourdomain.com
user no-reply@yourdomain.com
password app-specific-password
account default : relay
接着把 PHP 的 sendmail_path 指过去:面板能改 php.ini 就直接写 sendmail_path = "/home/账号/bin/msmtp -t -i";不开放就用 .user.ini 覆盖,注意它只对 PHP-FPM 生效,并且要等一个 user_ini.cache_ttl 周期(默认 300 秒)才刷新。
用命令行直发一次,能立刻分清“脚本没被调用”和“中继拒收”:
printf "Subject: relay test\nFrom: no-reply@yourdomain.com\nTo: you@example.com\n\nhello\n" | msmtp -v you@example.com
看到 250 2.0.0 Ok: queued as ... 说明中继已接收;报 authentication failed 是账号或应用密码的问题;报 TLS 错误多半是缺 CA 证书包。真要自建发信,签名细节(selector 轮换、反向解析与 include 的配合)可以对照 Postfix 与 SPF、DKIM、DMARC 实战配置 逐项核对。
送达验证:从解析记录看到达收件箱
中继收下邮件,不等于收件人能看到邮件。决定它落进收件箱还是垃圾箱的,是收件方的 SPF、DKIM、DMARC 三项校验。换中继后发信 IP 变成服务商的地址段,SPF 里若还只有原来那台主机,校验必然失败。

这套检查建议固定下来,每次换中继或换发信域名都重跑一遍:
- SPF:
dig +short TXT 域名应看到v=spf1 include:中继域名 -all;一条记录里出现两个v=spf1会直接判定失败。 - DKIM:
dig +short TXT selector._domainkey.域名能返回公钥才说明签名可用,selector 用服务商给的名字。 - DMARC:至少先有
v=DMARC1; p=none,观察两周再从quarantine往上收紧,避免误伤正常业务邮件。 - 邮件头:导出收到的原文,搜
Authentication-Results,三项都是 pass 才算链路干净。 - 真实投递:给 Gmail、Outlook 各发一封,两边都进收件箱再上线。
DMARC 的对齐检查看的是 From 头里的域名,不是信封发件人。用中继代发时 From 若写成中继域名,SPF 过了对齐照样失败,所以 From 必须是你自己的域名,账号只是登录凭据。
四个最常见的返工点
- 端口与加密方式配错。587 配 SSL(安全传输协议,隐式加密)会一直挂到超时,正确的是 587 配
tls(STARTTLS),465 才配隐式加密;表现是“没报错,只是很慢然后失败”。 - 发件地址与登录账号不一致。中继普遍校验信封发件人,报错常见
550 Sender address rejected,改成同一个地址即可,不必换服务商。 - 表单插件自带一套发信设置。它优先级高于全局配置,结果是“测试邮件能收到、客户填表收不到”,排查先看插件自己的邮件设置页。
- SPF 记录叠加过多。一次校验最多 10 次 DNS(域名解析系统)查询,每多一个
include多一次,超出后返回permerror,收件方按失败处理。
一个外贸站点的例子:日均发出 200 多封询盘通知,约三成客户回信收不到。运维先怀疑封端口,换中继后仍有退信,最后查到是表单插件覆盖了全局设置、SPF 堆了六个 include 触发查询上限。两处改完,退信率从 12% 降到不足 1%。
什么情况下该换方案,而不是继续调配置
中继能解决“发不出去”,解决不了“发得太多”。多数共享主机有明确的发信量限制,常见区间是每小时 200 到 500 封,超出后要么排队延迟,要么直接被限流。出现下面这些信号,瓶颈已经不在 25 端口:
- 每小时发信量贴近上限,通知邮件延迟十几分钟才到,说明配额不够用了。
- 需要在同一台主机上跑邮件列表或批量通知,进程与连接数限制会先撞墙。
- 业务要求固定发信 IP 供对方做白名单,而共享主机的出口地址并不固定。
- 站点从单一网站扩成多站,共享主机的隔离能力开始成为风险点。
这些情况下继续在插件层微调收益很低,更合理的是升级到资源独立的方案。先看 Hostease 共享主机方案 的配额说明,判断现有套餐还有多少余量;发信量与并发都接近上限时,迁到独立资源更稳。迁移当天的顺序可以按 网站迁移后 DNS(域名解析系统)与邮件联动检查清单 走,避免网站和邮件一起中断。
总结:把 25 端口问题当成一次发信路径的重构
共享主机限制出站 25 端口是行业惯例,跟主机商争论解封,通常不如直接改道。要做的事只有三步:用 nc 和 openssl 确认阻塞发生在哪一层,把发信切到 587 端口的认证中继,再拿 SPF、DKIM、DMARC 的对齐结果和真实邮件头验证一遍。
配置阶段最容易翻车的是发件地址与登录账号不一致,以及表单插件覆盖全局设置。上线前建议固定做一次全链路测试:后台测试邮件、联系表单、订单通知各发一封,用不同邮箱域名接收,再查邮件头三项是否都是 pass。三项都过而退信仍在,问题通常在收件方的内容评分,不在发信链路。
总结下来,这份流程值得写进运维文档,当作换主机、换域名、换中继时的固定动作。链路稳定之后再评估配额与并发,顺序反了往往要花两倍时间返工。