90%的定时邮件告警失败源于未配置mta,而非脚本或crontab错误;需确认mta存在、smtp配置正确并测试发送,再通过显式调用mail命令加状态判断实现稳定告警。

系统定时邮件告警发不出去,90% 是因为没配 MTA(邮件传输代理),不是脚本或 crontab 写错了。
crontab 的 MAILTO 为什么从来不发邮件
默认情况下,crontab 只在任务产生 stdout 或 stderr 输出时才尝试发邮件,且必须有本地 MTA(如 postfix、sendmail 或能调用 SMTP 的 mailx)可用。绝大多数 Linux 发行版不预装 MTA,which sendmail 或 systemctl is-active postfix 返回空或 inactive 就说明根本没通路。
-
MAILTO只控制收件人,不解决“怎么发”;它甚至不保证成功——失败时静默丢弃 - 用户级
crontab -e顶部加MAILTO=you@domain.com仅当 MTA 已就绪才有效 - /etc/crontab 中的
MAILTO=root默认发给本地 root 用户,但 root 邮箱通常没人查
用 mail 命令手动发信前必须确认三件事
别跳过验证环节,否则所有告警逻辑都建立在流沙上。
- 确认命令存在:
which mail、which mailx、which s-nail—— 不同发行版默认工具不同(Ubuntu 多用bsd-mailx,CentOS 多用mailx) - 确认 SMTP 配置生效:编辑
/etc/mail.rc或/etc/s-nail.rc,必须包含四要素:set from=、set smtp=、set smtp-auth-user=、set smtp-auth-password=(QQ 邮箱必须用授权码,非登录密码) - 测试发送:
echo "test" | mail -s "test-$(date +%H%M)" your@domain.com,收不到就检查/var/log/mail.log或运行mail -v -s "test" your@domain.com 看详细报错
让 cron 任务稳定触发邮件的两种可靠写法
依赖 MAILTO 太脆弱;显式调用 mail + 退出状态判断才是生产环境通用解法。
- 单行判断(适合简单任务):
0 3 * * * /path/to/script.sh && echo "OK $(date)" | mail -s "Backup OK" admin@example.com || echo "FAIL $(date): $?" | mail -s "Backup FAILED" admin@example.com - 封装脚本(推荐,便于加日志、重试、超时):
写一个/opt/bin/notify-wrap.sh,接收命令和描述作为参数,内部执行并统一处理$?、记录/var/log/notify.log、限制每小时最多发 3 封防刷屏 - 关键细节:crontab 的 PATH 极窄(
/usr/bin:/bin),脚本里所有命令(如python3、jq)必须写绝对路径,或开头加PATH=/usr/local/bin:/usr/bin:/bin
常见陷阱:为什么邮件内容总是空或格式乱码
不是编码问题,而是 mail 命令默认不识别 UTF-8,且对换行、空格敏感。
- 中文主题必须加
-S sendcharsets=utf-8(s-nail)或-r(某些mailx),否则显示为问号 - 多行内容不要直接 pipe 给
mail,先拼成变量或用 here-document:mail -s "Alert" admin@example.com - 附件要用
s-nail -a /path/file.log,bsd-mailx不支持-a,得用uuencode手动编码
最易被忽略的是权限链:crontab 以用户身份运行 → 脚本读取 /etc/mail.rc 需要读权限 → SMTP 密码明文存配置中需防其他用户读取(chmod 600 /etc/mail.rc)。别让告警本身变成安全漏洞。











