# 自建邮局排查指南


自建邮局能发不能收，是很常见的坑。发信和收信走的是两条完全不同的链路：发信靠出站 SMTP，收信则依赖 `MX` 记录、入站 `25` 端口、本地域名配置，以及客户端通过 `IMAP` / `POP3` 取信的能力——任何一环出问题都会导致收信失败。

不管你是"别人发给我的邮件根本收不到"，还是"服务器上明明有邮件，客户端却看不到"，都可以按本文的顺序逐层排查，比一上来就翻配置文件更高效。

## 先判断故障发生在哪一层

在动手之前，先把问题分成下面三类：

1. **外部发件人根本投递不进来**
   重点检查 `MX`、`A/AAAA`、公网 `25` 端口、反向解析和服务器是否真的在监听。
2. **服务器已经收到了邮件，但客户端读不到**
   重点检查 `IMAP` / `POP3` 监听、TLS 证书、账号认证、邮箱配额和客户端配置。
3. **手动配置能用，但自动配置失败**
   重点检查自动发现接口、`SRV` 记录，以及客户端的自动发现机制。

如果你不确定属于哪一类，最简单的办法是同时做两件事：

- 用外部邮箱（如 Gmail、Outlook）给你的域名发一封测试邮件。
- 立即查看服务器日志，确认这封邮件有没有到达。

只要日志里完全没有新的入站记录，问题大概率还停留在 `DNS`、网络或 `25` 端口这一层。

## 1. 先检查 DNS 解析

收信链路里，`DNS` 是第一关。`MX` 错了，后面的配置再正确也没用。

### I. 检查 MX 记录

```bash
dig example.com MX
```

需要确认两点：

- `MX` 记录确实存在。
- `MX` 指向的是一个**域名**，而不是 IP 地址。

例如下面这种写法才是正常的：

```text
example.com.  300  IN  MX  10 mail.example.com.
```

### II. 检查 MX 指向的 A/AAAA 记录

```bash
dig mail.example.com A
dig mail.example.com AAAA
```

`MX` 指向的主机名必须能继续解析到可访问的公网地址。

这里有一个很常见的坑：`AAAA` 记录存在，但服务器其实没有正确配置 IPv6。这样一来，部分发件方会优先走 IPv6 投递，结果表现为“有些邮件能收到，有些收不到”。如果你暂时不打算支持 IPv6，宁可先去掉错误的 `AAAA` 记录，也不要让它半通不通。

### III. 检查 PTR 反向解析

```bash
dig -x <服务器公网IP>
```

虽然 `PTR` 错误不一定会导致完全无法收信，但它会显著影响投递质量，某些服务商也会更严格地对待这类主机。理想情况是：

- 公网 IP 的 `PTR` 指回你的邮件主机名，例如 `mail.example.com`
- 这个主机名再正向解析回同一个 IP

### IV. 注意 DNS 生效延迟和本地缓存

如果你刚改过记录，别忘了考虑两件事：

- 解析未完全传播，外部仍在命中旧记录
- 本地机器或路由器缓存了旧结果

可以额外做一次查询验证：

```bash
dig +short example.com MX
dig +short mail.example.com A
dig +short mail.example.com AAAA
```

## 2. 确认入站端口是否真的可达

“发信正常”经常会让人误以为网络没问题，但这只能说明**出站**路径大致可用，并不能证明别人可以从公网连到你的服务器。

### I. 优先测试 SMTP 25 端口

如果外部邮件根本投递不进来，最应该先查的是 `25` 端口：

```bash
nc -zv -w 3 mail.example.com 25
```

如果你还要顺手检查客户端收信相关端口，可以一起测：

```bash
nc -zv -w 3 mail.example.com 143
nc -zv -w 3 mail.example.com 993
nc -zv -w 3 mail.example.com 110
nc -zv -w 3 mail.example.com 995
nc -zv -w 3 mail.example.com 465
nc -zv -w 3 mail.example.com 587
```

### II. 常见邮件端口对照

| 服务  | 端口 | 用途           | 加密方式    |
| ----- | ---- | -------------- | ----------- |
| SMTP  | 25   | 服务器间收发信 | 无/STARTTLS |
| SMTP  | 587  | 客户端提交发信 | STARTTLS    |
| SMTPS | 465  | 客户端提交发信 | SSL/TLS     |
| IMAP  | 143  | 客户端收信     | STARTTLS    |
| IMAPS | 993  | 客户端收信     | SSL/TLS     |
| POP3  | 110  | 客户端收信     | STARTTLS    |
| POP3S | 995  | 客户端收信     | SSL/TLS     |

### III. 不要只看服务器防火墙

端口不通时，问题可能出在下面任意一层：

- 服务器本机防火墙没有放行
- 云厂商安全组或网络 ACL 没开
- 路由器或 NAT 没有做端口转发
- 宿主机到容器的端口映射不正确
- 上游运营商或机房对邮件端口有限制

如果你部署在家宽或某些云平台上，`25` 端口尤其值得重点确认。有些环境不是“服务没启动”，而是上游直接不让你接这类连接。

### IV. 其他检测方式

```bash
nmap -p 25,110,143,465,587,993,995 mail.example.com
curl -v --connect-timeout 3 telnet://mail.example.com:25
```

如果你希望完全不依赖外部工具，也可以用 Bash 自带的 TCP 探测：

```bash
(echo >/dev/tcp/mail.example.com/25) && echo "开放" || echo "关闭"
```

## 3. 检查 TLS 和证书

如果问题表现为“服务器能收到邮件，但客户端连 IMAP/POP3 总是报证书错误、握手失败或一直转圈”，那下一步就该看 TLS。

### I. 测试隐式 TLS 端口

```bash
openssl s_client -connect mail.example.com:993 -servername mail.example.com
openssl s_client -connect mail.example.com:465 -servername mail.example.com
openssl s_client -connect mail.example.com:995 -servername mail.example.com
```

### II. 测试 STARTTLS 端口

```bash
openssl s_client -connect mail.example.com:143 -servername mail.example.com -starttls imap
openssl s_client -connect mail.example.com:587 -servername mail.example.com -starttls smtp
openssl s_client -connect mail.example.com:110 -servername mail.example.com -starttls pop3
```

> **注意**：`openssl s_client -starttls` 的协议协商并不总是可靠的——有些服务器在 STARTTLS 之前要求先完成认证或特定交互，`openssl` 做不到这些，就会导致测试失败，但服务器本身其实没问题。如果隐式 TLS 端口（993/465/995）全部通过，而 STARTTLS 端口全部失败，大概率是测试工具的局限，而不是服务器配置有误。大多数客户端默认使用隐式 TLS 连接，所以只要隐式 TLS 正常，收信一般不受影响。

### III. 快速提取证书信息

```bash
openssl s_client -connect mail.example.com:993 -servername mail.example.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates
```

### IV. 常见证书问题

最常见的几类问题通常是：

- 证书是自签的，客户端默认不信任
- 证书上的域名与客户端连接用的域名不一致
- 证书已经过期
- 服务端口根本没有正确启用 TLS，输出里会看到 `no peer certificate available`

要注意一点：`SMTP 25` 端口缺少 TLS 并不一定会让收信完全失败，但 `IMAP` / `POP3` 端口的 TLS 配置错误，往往会直接表现为“明明有邮件，但客户端就是登录不了”。

## 4. 检查邮件服务本身

如果 `DNS` 和端口都没问题，接下来就该确认邮件服务本身有没有正确对外提供“收信”和“取信”能力。

### I. 确认服务监听在公网地址

先看相关端口到底监听在什么地址上：

```bash
ss -tlnp | rg ':(25|110|143|465|587|993|995)\\b'
```

正常情况下，至少应该看到服务监听在 `0.0.0.0`、`[::]` 或你的公网可达地址上。
如果只监听在 `127.0.0.1` 或 `::1`，那外部客户端当然连不上。

### II. 确认服务器愿意接收你的域名

这是另一个非常常见的配置问题：服务启动了，端口也通，但服务器根本没把 `example.com` 当作本地域名处理。

不同邮件服务器的叫法不完全一样，但你需要检查的核心都是同一件事：

- 你的域名是否被列入本地投递域名
- 该域名下的邮箱账号或别名是否真实存在
- 邮件到达后是否有正确的投递目标

如果这一层配置有误，常见表现是：

- 外部会收到 `relay access denied`
- 服务器把发给你自己的邮件当成要继续转发的外部邮件
- 日志里能看到邮件进来，但最终被拒收或落到了错误的位置

### III. 检查账号、配额和本地存储

如果外部投递已经成功，但客户端看不到邮件，还要继续排查：

- 该账号是否真的存在
- 邮箱是否已满
- 邮件是否被投递到了意料之外的文件夹
- 是否有过滤规则把邮件转移、归档或删除了

### IV. 留意封禁和限速策略

很多人排查时只盯着主配置，却忘了还有额外的访问控制层，例如：

- fail2ban 或类似封禁工具
- 服务自身的 IP 黑名单或灰名单
- 登录失败后的限速或临时封锁

这类问题特别像“偶发故障”：同一套配置，在一台设备上能连，在另一台设备上又不行。

### V. 直接看日志

日志通常比猜配置更快。无论你是系统服务、容器还是面板部署，都应该优先找到最近几十行日志：

```bash
journalctl -u <你的邮件服务> --no-pager -n 100
docker logs <你的邮件容器> --tail 100
```

重点关注这些关键词：

- `connect`
- `reject`
- `relay`
- `tls`
- `certificate`
- `authentication failed`
- `timeout`
- `rate limit`
- `mailbox full`

如果你在外部发出测试邮件的同时盯着日志，往往几分钟内就能判断问题是在“进不来”还是“进来了但处理失败”。

## 5. 检查客户端自动发现

如果手动填服务器地址和端口可以正常收发，但 Thunderbird、Outlook 或手机系统的自动配置失败，那问题通常不在收信本身，而在“自动发现”这层。

### I. 常见自动发现方式

不同客户端会使用不同机制，常见的有：

- `Autoconfig`
  例如 `https://autoconfig.example.com/mail/config-v1.1.xml`
- `Autodiscover`
  例如 `https://autodiscover.example.com/autodiscover/autodiscover.xml`
- `DNS SRV` 记录
  例如 `_imaps._tcp`、`_submission._tcp`
- 猜测常见主机名
  例如 `mail.example.com`、`imap.example.com`、`smtp.example.com`

### II. 可以先直接验证相关地址

```bash
curl -v "https://autoconfig.example.com/mail/config-v1.1.xml"
curl -v "https://autodiscover.example.com/autodiscover/autodiscover.xml"
```

如果这些地址根本打不开、证书不对，或者返回内容不是客户端期望的格式，那么自动配置自然会失败。

### III. 常见 SRV 记录示例

| 记录类型 | 主机记录            | 记录值                      |
| -------- | ------------------- | --------------------------- |
| SRV      | `_imaps._tcp`       | `0 1 993 mail.example.com.` |
| SRV      | `_imap._tcp`        | `0 1 143 mail.example.com.` |
| SRV      | `_submissions._tcp` | `0 1 465 mail.example.com.` |
| SRV      | `_submission._tcp`  | `0 1 587 mail.example.com.` |
| SRV      | `_pop3s._tcp`       | `0 1 995 mail.example.com.` |

### IV. 手动配置往往是最快的验证方式

如果你只想先确认服务本身是否可用，直接手动配置通常更高效：

| 项目      | 服务器           | 端口 | 安全    |
| --------- | ---------------- | ---- | ------- |
| 收信 IMAP | mail.example.com | 993  | SSL/TLS |
| 发信 SMTP | mail.example.com | 465  | SSL/TLS |

只要手动配置能通，就说明“邮件服务”本身大概率没问题，剩下只是自动发现资料没补齐。

## 6. 排除本地网络和缓存干扰

有些“收信异常”其实不是服务器坏了，而是你当前网络环境在捣乱。

### I. 先换一个网络再试

如果出现下面这些现象，很值得怀疑本地网络或运营商干扰：

- `nc` 能连上，但 TLS 握手异常中断
- 同一账号在手机热点下正常，在公司或家里网络下异常
- 只有个别设备、个别网络环境出问题

最简单的验证方式是：

- 用手机热点再试一次
- 开 VPN 再试一次
- 换另一台设备再试一次

### II. 必要时抓包看连接有没有到服务器

如果你有服务器权限，可以直接在服务端抓包确认客户端流量是否到达：

```bash
sudo tcpdump -i any -n 'port 25 or port 993'
```

观察思路很简单：

- 客户端连接根本没到服务器，优先查 DNS、路由、端口映射
- 连接到了服务器，但服务没有回应，优先查服务状态和 TLS
- 连接到了服务器，服务器立刻拒绝，优先查认证、封禁和访问策略

### III. 清理本地缓存

改过 `DNS` 或证书后，还可以顺手排查一下本地缓存：

```bash
sudo resolvectl flush-caches
resolvectl query mail.example.com
grep example /etc/hosts
```

如果 `hosts` 里残留了旧记录，或者系统还在使用旧解析结果，排查方向很容易被带偏。

## 7. 用命令行做一次最小化验证

图形客户端的信息往往不够直接。怀疑客户端本身有问题时，可以用命令行做一次最小验证。

### I. 测试 IMAP 登录

```bash
curl -v --url "imaps://mail.example.com/INBOX" --user "user@example.com:密码"
```

只要这一步能成功列出或访问邮箱内容，说明至少下面几层已经基本打通：

- 域名解析
- `993` 端口连通
- TLS 握手正常
- 用户名和密码正确
- IMAP 服务可用

### II. 手动与 IMAP 服务交互

```bash
openssl s_client -connect mail.example.com:993 -servername mail.example.com -quiet
```

连接后可以手工输入：

```text
a1 LOGIN user@example.com 密码
a2 LIST "" "*"
a3 SELECT INBOX
a4 LOGOUT
```

这种方式虽然原始，但在排查“到底是客户端问题，还是服务器问题”时非常直接。


---

> 作者: Nite  
> URL: https://www.nite07.com/zh-cn/posts/mail-server-receive-troubleshooting/  

