Sendmail向Odoo发邮件不止?定位原因与解决方法
2025-04-24 15:31:27
揪出幕后黑手:解决 Sendmail 不停向 Odoo 发送邮件的问题
服务器遇到怪事了?明明感觉没做什么,却收到服务商警告说你的 IP 正在疯狂往外发邮件,查了下网络连接,发现一堆 sendmail
进程死磕 Odoo 的邮件服务器 (mx*.odoo.com
),端口 25 忙得不亦乐乎。更头疼的是,你尝试停掉 sendmail
服务,它却像打不死的小强,过会儿又自己跑起来了。这到底是怎么回事?怎么才能让它停下来?
别慌,这篇文章就带你一步步排查,找出那个在背后捣鬼的“家伙”,让服务器恢复清净。
问题现象复现
先看看你遇到的典型场景是不是这样:
-
服务商邮件轰炸警告: Contabo 或者其他主机提供商发来邮件,说你的服务器 IP 因为对外发送大量邮件(通常是 SMTP 协议,端口 25),触发了他们的监控警报。
-
检查网络连接 (
lsof -i :25
): 执行这个命令,你会看到类似下面的输出,显示sendmail
进程与mx*.odoo.com
建立了多个 SMTP 连接。这些连接可能反复出现。COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sendmail- 1361 root 4u IPv4 19981 0t0 TCP localhost:smtp (LISTEN) # 这个是 Sendmail 监听本地连接 sendmail- 20971 root 6u IPv4 401805 0t0 TCP myserver:44362->mx1a.odoo.com:smtp (ESTABLISHED) sendmail- 20971 root 7u IPv4 401805 0t0 TCP myserver:44362->mx1a.odoo.com:smtp (ESTABLISHED) # ... 可能还有更多到 mx1b, mx1c, mx1d 的连接
-
查看邮件日志 (
/var/log/mail.log
): 用tail -f /var/log/mail.log
盯着日志看,会发现大量类似下面的记录不断刷屏:Feb 22 07:56:35 myserver sm-mta[20971]: 51IKDucD1512089: to=<[email protected]>, delay=3+10:42:39, xdelay=00:00:05, mailer=esmtp, pri=44852439, relay=mx1d.odoo.com. [91.134.56.180], dsn=4.3.5, stat=Deferred: 451 4.3.5 Server configuration error Feb 22 07:56:37 myserver sm-mta[20971]: 51IKDucD1512089: to=<[email protected]>, delay=3+10:42:41, xdelay=00:00:07, mailer=esmtp, pri=44852439, relay=mx1a.odoo.com. [141.94.255.216], dsn=4.3.5, stat=Deferred: 451 4.3.5 Server configuration error # ... 反复尝试不同的 Odoo MX 服务器
注意这里的关键信息:
to=<[email protected]>
,stat=Deferred: 451 4.3.5 Server configuration error
。这说明 Sendmail 正在尝试给 Odoo 的某个地址发邮件,但 Odoo 服务器返回了一个临时错误(451
),告诉 Sendmail “服务器配置有问题,稍后再试”。Deferred
状态意味着 Sendmail 会把这封邮件暂存起来,过段时间继续重试。delay=3+10:42:41
表明这封邮件已经被尝试发送了 3 天 10 多个小时了! -
尝试禁用 Sendmail (
systemctl stop/disable/mask sendmail
): 你可能试过用systemctl
命令来停止并禁用 Sendmail,甚至mask
它,理论上这应该能彻底阻止它运行。但奇怪的是,过了一段时间,sendmail
进程又出现了,邮件还在继续发。
剖析问题根源
综合以上现象,问题可能出在以下几个方面:
- Sendmail 的重试机制: 日志里的
Deferred
和451 4.3.5
错误是核心线索。这表明最初有某个进程或脚本(我们还不知道是谁)通过 Sendmail 发送了一封或多封邮件给 Odoo。但由于 Odoo 服务器端的原因(可能是你的服务器 IP 被 Odoo 暂时阻止,或者 Odoo 那边确实有配置问题,或者邮件内容触发了 Odoo 的反垃圾策略),邮件发送失败了,但失败类型是“临时性”的。Sendmail 作为邮件传输代理(MTA),职责就是保证邮件送达,遇到这种临时失败,它会默认把邮件放入队列 (/var/spool/mqueue
或类似目录),然后定期尝试重新发送。只要邮件还在队列里,并且 Sendmail 服务在运行,它就会不停地尝试。 - 邮件源头未知:
lsof
和日志只能看到是sendmail
进程在对外连接和记录日志。但sendmail
只是个邮差,它本身不生产邮件内容。我们需要找到是谁(哪个脚本、哪个应用、哪个用户)把信交给了sendmail
这个邮差。 - Sendmail "自动复活"之谜:
systemctl disable
和systemctl mask
是 systemd 管理服务比较强的禁用手段了。如果执行后sendmail
依然能启动,那极有可能是:- 有其他脚本或
cron
定时任务在检测到sendmail
停止后,又手动启动了它。 - 服务器可能被入侵,恶意软件在后台监控并重新启动
sendmail
服务,或者直接利用sendmail
发送垃圾邮件。 - 存在某种进程守护工具(如
monit
、supervisor
等,虽然不常见于守护sendmail
)配置了自动重启。
- 有其他脚本或
定位邮件始作俑者
好,理论分析完了,该动手找“真凶”了。思路是:先找到是哪封(或哪些)邮件卡在队列里,然后顺藤摸瓜找是谁投递的。
方案一:检查 Sendmail 邮件队列
这是最直接的方法,看看队列里都有些啥。
-
列出队列内容:
sudo mailq # 或者 sudo sendmail -bp
这个命令会显示当前在队列中的邮件摘要,包括邮件 ID(例如日志中的
51IKDucD1512089
)、发件人、收件人、以及邮件大小和入队时间。留意那些收件人是@notification.odoo.com
的邮件。记下它们的邮件 ID。 -
查看邮件头和内容(需要 root 权限):
Sendmail 的邮件队列通常在/var/spool/mqueue/
目录下(具体路径可能因配置而异,可以查看 Sendmail 配置文件确认)。每个邮件由两个文件组成:qf
文件(包含信封信息和头部)和df
文件(包含邮件正文)。# 假设邮件 ID 是 51IKDucD1512089 # 查看对应的 qf 文件内容 sudo ls -l /var/spool/mqueue/qf51IKDucD1512089 sudo less /var/spool/mqueue/qf51IKDucD1512089
在
qf
文件里,仔细查找From:
、Sender:
、Received:
或X-
开头的自定义头部。这些头部信息有时能提供线索,比如:Received:
头部记录了邮件经过的服务器路径,最原始的那条可能包含最初提交邮件的脚本或本地主机信息。- 某些应用程序在发送邮件时会添加特定的
X-Mailer:
或User-Agent:
头部。 - 发件人地址
From:
有时也能提供线索。
安全建议: 查看文件内容时使用
less
或cat
,不要执行文件里的任何内容。进阶技巧: 如果队列里邮件很多,可以写个脚本批量分析
qf
文件,提取特定头部信息。例如,用grep
在所有qf
文件中搜索可疑的 IP 地址或脚本名。
方案二:审计系统进程和计划任务
如果队列信息不够明确,或者你想找的是持续生成新邮件的源头,那就得查查服务器上正在运行的进程和定时任务了。
-
检查当前运行的进程:
ps aux | grep -Ei 'sendmail|mail|php|python|script|cron'
看看有没有可疑的脚本进程在运行,或者与邮件发送相关的应用进程(比如,如果服务器上运行了 Odoo 实例,那 Odoo 本身就可能尝试发邮件)。
-
检查 Cron 定时任务:
恶意脚本或配置错误的正常脚本常常通过 Cron 定期执行。# 检查 root 用户的 cron sudo crontab -l # 检查其他用户的 cron (例如 www-data 用户) sudo crontab -u www-data -l # 检查系统级的 cron 目录 ls -l /etc/cron.* # 特别留意 /etc/crontab 文件和 /etc/cron.d/ 目录下的文件 sudo less /etc/crontab sudo ls -l /etc/cron.d/
仔细检查每个定时任务执行的命令,看有没有调用
sendmail
、mail
命令,或者执行可疑脚本的。 -
检查 Systemd Timers:
现在很多定时任务也通过 Systemd Timer 实现。sudo systemctl list-timers --all
查看是否有可疑的定时器单元在运行。
-
检查 Web 服务器和应用日志:
如果是 Web 应用(比如 PHP 写的网站)在发邮件,检查 Web 服务器(Nginx, Apache)的访问日志和错误日志,以及应用程序自身的日志。有时能找到是哪个请求触发了邮件发送。
安全建议: 对于不认识的进程或 Cron 任务,上网搜索一下它的名字,判断是否正常。修改或删除 Cron 任务前最好先备份。
方案三:利用 auditd 进行深度追踪
如果上面的方法都找不到源头,或者你想精确知道是哪个程序调用了 sendmail
,可以使用 Linux 的审计工具 auditd
。
-
安装并配置 auditd:
sudo apt-get update sudo apt-get install auditd sudo systemctl enable auditd sudo systemctl start auditd
-
添加审计规则:
我们想监控对sendmail
可执行文件的执行。# 找到 sendmail 的准确路径 which sendmail # 假设路径是 /usr/sbin/sendmail # 添加规则,监控对 /usr/sbin/sendmail 的执行(-p x 表示执行权限),并给这个规则打个标签 sendmail_exec sudo auditctl -w /usr/sbin/sendmail -p x -k sendmail_exec
为了让规则在重启后依然生效,需要将其添加到
/etc/audit/rules.d/
目录下的规则文件中(例如audit.rules
),然后重启auditd
服务。 -
分析审计日志:
当有进程执行/usr/sbin/sendmail
时,相关信息会被记录到/var/log/audit/audit.log
。sudo ausearch -k sendmail_exec -i
或者直接
tail -f /var/log/audit/audit.log
观察。日志会包含执行sendmail
的进程 PID、父进程 PID (PPID)、用户 ID (uid, euid)、以及完整的命令行参数。通过 PID 和 PPID,你可以用ps
命令追溯到最初发起调用的进程。
安全建议: auditd
会记录大量日志,可能影响性能。规则要尽量精确。问题解决后记得评估是否需要移除或调整规则。
进阶技巧: 可以设置更复杂的规则,例如监控对 sendmail
配置文件的修改,或者监控特定的系统调用。
方案四:分析网络流量
实在没办法了,还可以抓包看看 Sendmail 到底在往外发什么。
sudo tcpdump -i any -s 0 -A 'port 25 and host mx1a.odoo.com'
# 或者抓所有 Odoo MX 服务器的包
sudo tcpdump -i any -s 0 -A 'port 25 and (host mx1a.odoo.com or host mx1b.odoo.com or host mx1c.odoo.com or host mx1d.odoo.com)'
# 使用 tshark 可能更方便阅读 SMTP 协议
sudo apt-get install tshark # 如果没装的话
sudo tshark -i any -Y 'tcp.port == 25 && (ip.addr == 91.134.56.180 || ip.addr == 141.94.255.216 || ip.addr == 141.94.241.170)' -O smtp
观察抓到的 SMTP 对话内容。特别是 MAIL FROM:
, RCPT TO:
, 以及 DATA
部分的内容,或许能提供邮件来源的线索。比如邮件正文里包含某个应用的特定错误信息或标识。
安全建议: 抓包可能捕获敏感信息。结束后务必停止抓包,并妥善处理捕获文件。
彻底阻止 Sendmail 发送并处理潜在风险
定位源头的同时,或者实在找不到源头但必须立刻停止邮件发送时,可以采取以下措施。
措施一:强制停止并清理 Sendmail
既然 disable
/mask
不一定管用(因为可能有“外力”在重启它),我们需要更强硬的手段,并解决它“复活”的问题。
-
找到重启 Sendmail 的元凶: 在执行停止操作后,持续监控进程 (
ps aux | grep sendmail
)。一旦发现它又启动了,立刻用ps -ef --forest
查看它的进程树,找到它的父进程是谁。或者检查系统日志 (/var/log/syslog
或journalctl
) 看是否有启动sendmail
的记录。重点排查 Cron、Systemd Timers、以及可疑的守护进程。 -
解决元凶: 如果是 Cron 或 Timer,注释掉或删除对应任务。如果是未知进程,可能需要先定位该进程并处理掉(可能是恶意软件,参考下面的“安全入侵”部分)。
-
确保 Sendmail 停止: 在解决了重启源头之后,再次执行:
sudo systemctl stop sendmail sudo systemctl disable sendmail sudo systemctl mask sendmail # 极端情况下,如果它还在跑,可能需要找到进程PID直接kill # sudo pkill sendmail # sudo pkill -9 sendmail # 强制杀死,作为最后手段
-
清理邮件队列(非常重要): 即使 Sendmail 停了,队列里的邮件还在。一旦 Sendmail 被(意外或故意)再次启动,它会继续尝试发送这些邮件。
# 确认队列目录,通常是 /var/spool/mqueue # 清空队列 (!! 操作危险,确认路径无误 !!) sudo rm -rf /var/spool/mqueue/* # 有些系统可能还有一个 clientmqueue 目录也需要检查 # sudo rm -rf /var/spool/clientmqueue/*
-
考虑彻底移除 Sendmail(如果不需要): 如果服务器根本不需要运行 Sendmail 服务(比如所有邮件都通过外部 SMTP 服务商发送,或者本机不需要发邮件),在确认没有其他服务依赖它之后,可以考虑卸载。
# 模拟卸载,看看会影响哪些包 sudo apt-get -s purge sendmail* # 如果确认没问题,执行卸载 sudo apt-get purge sendmail*
安全建议: rm -rf
操作非常危险,执行前务必再三确认路径正确。卸载 Sendmail 前一定用 -s
参数模拟,检查依赖关系,避免破坏系统。
措施二:使用防火墙阻止出站 SMTP
这是一个比较“暴力”但有效的临时或永久措施:直接在防火墙层面禁止服务器对外访问 TCP 端口 25。
-
使用 UFW (Uncomplicated Firewall):
sudo ufw status # 查看 UFW 状态和现有规则 sudo ufw deny out 25/tcp comment 'Block outgoing SMTP port 25' sudo ufw reload # 或者 enable UFW 如果之前没启用
-
使用 iptables:
sudo iptables -A OUTPUT -p tcp --dport 25 -j REJECT --reject-with tcp-reset # 或者直接丢弃数据包(让连接超时) # sudo iptables -A OUTPUT -p tcp --dport 25 -j DROP # 查看 OUTPUT 链规则 sudo iptables -L OUTPUT -v -n --line-numbers # 保存规则(方法因发行版而异,例如使用 iptables-persistent) sudo apt-get install iptables-persistent # Debian/Ubuntu sudo netfilter-persistent save
影响和风险:
- 优点: 能立刻阻止所有通过端口 25 发送的邮件,包括来自 Sendmail 或其他任何程序的。很多主机商也推荐或强制执行此操作以防滥用。
- 缺点: 会阻止所有依赖端口 25 的合法 邮件发送。例如,某些老旧应用或配置不当的应用可能硬编码使用端口 25。系统本身的一些通知邮件(比如 Cron 的输出)如果默认走本地 Sendmail 转发出也可能失败。
- 替代方案: 现代应用和服务通常推荐使用 SMTP 提交端口 587 (带 STARTTLS 加密) 或 SMTPS 端口 465 (带 SSL/TLS 加密) ,并需要身份验证。阻止端口 25 不会影响这些端口。如果你的应用需要发邮件,应配置它们使用这些端口连接到你的邮件服务商(如 Mailgun, SendGrid, Gmail 等)或你自己的邮件服务器(如果设置了 Submission 服务)。
安全建议: 实施防火墙规则后,要监控是否有合法应用因此失败。
应对潜在的服务器安全入侵
Sendmail 无法正常停止并自行重启,这本身就是一个危险信号,暗示服务器可能已经被入侵。
如果你怀疑服务器被黑了,必须严肃对待:
-
立即隔离(如果可能): 在不影响业务的前提下,考虑通过网络防火墙或云平台安全组限制服务器的入站和出站连接,尤其是对外的敏感端口。
-
修改所有凭证: 从一个干净、可信 的电脑上,立刻修改服务器的 root 密码、所有用户密码、SSH 密钥对。检查
/root/.ssh/authorized_keys
和用户家目录下的~/.ssh/authorized_keys
是否有未知的公钥,并移除。检查数据库、应用后台等所有相关服务的密码。 -
运行安全扫描工具: 安装并运行
chkrootkit
和rkhunter
等工具,检查 rootkit 和后门。sudo apt-get install chkrootkit rkhunter sudo chkrootkit sudo rkhunter --update sudo rkhunter --check --sk # --sk 跳过按键等待
注意:已被入侵的系统上运行这些工具可能结果不可靠,因为工具本身也可能被篡改。
-
检查系统文件和进程:
- 用
last
命令查看最近登录记录。 - 检查
/etc/passwd
,/etc/shadow
,/etc/group
文件是否有异常用户或用户组。 - 使用
netstat -tulnp
或ss -tulnp
检查监听的端口和对应程序,看是否有不认识的服务。 - 使用
ps aux
或top
/htop
仔细检查运行中的进程。 - 检查系统日志(
/var/log/auth.log
,/var/log/syslog
,journalctl
)寻找可疑活动。 - 检查系统文件的完整性(如 Debian/Ubuntu 用
debsums -c
)。
- 用
-
终极方案:重装系统: 如果确认被入侵,或者强烈怀疑但无法彻底清理,最安全、最推荐的做法是:备份必要且确认安全 的数据(注意:不要备份可执行文件或配置文件,除非你完全理解它们且确信未被篡改),然后彻底格式化硬盘,重装操作系统 。之后,从可信来源重新安装应用,恢复数据,并加强安全措施(如配置防火墙、定期更新、使用强密码、禁用不必要的服务等)。
处理 Sendmail 异常邮件发送问题,既需要排查技术配置,也得时刻警惕安全风险。按部就班地检查队列、进程、定时任务,并结合强制停止和防火墙策略,通常能解决问题。但如果遇到无法解释的“复活”现象,务必优先考虑服务器安全,采取更深层次的检查甚至重装。