MySQL触发器不能直接发邮件,必须依赖外部程序中转;其本质是通过UDF(如sys_exec)调用Python/PHP等脚本执行SMTP发送,该过程非原子、不可靠,且存在权限、超时、日志、安全等多重隐患。

MySQL触发器不能直接发邮件,必须靠外部程序中转
MySQL 触发器本身不支持 SMTP、不内置 mail() 函数,也不允许执行 system() 或 exec()。所谓“触发器发邮件”,本质是触发器调用一个 UDF(如 sys_exec),再由该 UDF 启动外部脚本(如 Python/PHP/shell)去真正发信。这个过程不是原子的:数据库事务成功提交 ≠ 邮件发出成功。
用 lib_mysqludf_sys 的 sys_exec 调用邮件脚本最常见
这是目前落地最广的方案,但需手动编译安装、权限适配,且容易因环境差异失败:
-
sys_exec返回的是进程退出码(0 表示成功),不是邮件发送结果;脚本内部出错(比如 SMTP 认证失败)只会返回非 0,触发器里无法捕获具体错误信息 - MySQL 默认以
mysql用户运行,该用户通常无权访问网络或读取邮箱配置文件 —— 必须给/etc/mail.rc或 Python 脚本加chmod 644,并确保mysql用户能读取 - 脚本路径必须绝对路径,且不能含空格或特殊字符;传参要用
CONCAT()拼接,例如:sys_exec(CONCAT('/usr/bin/python3 /opt/alert_mail.py ', NEW.id, ' "', NEW.email, '"')) - 若用
sendmail命令,注意 CentOS 默认没装,得yum install mailx;Debian/Ubuntu 则常用mailutils,命令是echo "body" | mail -s "subject" to@ex.com
邮件脚本必须自己处理重试、超时和日志,不能依赖触发器
触发器只负责“发起一次调用”,后续全靠脚本健壮性。常见疏漏包括:
- Python 脚本未设
timeout=10,SMTP 连接卡住会导致整个 MySQL 写入阻塞(尤其在AFTER INSERT中) - 没做异常兜底,
try/except漏掉socket.timeout或smtplib.SMTPAuthenticationError,导致静默失败 - 日志写到
/tmp下,但 MySQL 容器或加固系统会清空该目录;建议写入/var/log/mysql-alert/并由mysql用户可写 - 脚本中硬编码密码 —— 应改用配置文件 +
chmod 600,或从环境变量注入(需提前在 mysqld 启动环境里 export)
生产环境更推荐 outbox 表 + 外部轮询,而非触发器直调
当告警频率超过每秒几次,或对可靠性要求高时,sys_exec 方案会迅速暴露问题:
- 并发高时,大量子进程 fork() 可能打满 ulimit -u,MySQL 连接卡死
- 脚本崩溃或磁盘满,邮件丢失无迹可查;而写入
alert_outbox表后,可用独立服务做幂等消费、失败重试、死信队列 - MySQL 8.0.30+ 默认禁用
plugin_dir外加载,且secure_file_priv限制严格,sys_exec很可能被 outright 拒绝 - 审计合规常禁止数据库直连外网;outbox 模式天然隔离,网络出口统一收口在应用层
真正难的不是让邮件发出去,而是让每次数据变更都“可靠、可观测、可追溯”——这三点,触发器+UDF 组合几乎无法满足。


















