utl_mail发不出邮件主因是数据库服务器网络不通smtp,需在db server上telnet/openssl验证端口连通性,检查utl_mail包状态、smtp_out_server参数、字符集与格式规范、acl权限及是否支持tls。

UTL_MAIL 发不出邮件,90% 不是代码写错了,而是数据库服务器根本连不上 SMTP 服务器——它不走你本地机器的网络,只依赖 DB Server 自身的 outbound 连通性。
UTL_MAIL.SEND 调用后静默失败或报 ORA-29279?先验证 SMTP 端口是否真通
ORA-29279(SMTP permanent error)和“没报错但收不到邮件”这两类现象,根源几乎都在网络层。UTL_MAIL 不会告诉你“连不上”,只会把底层 TCP 失败包装成 SMTP 协议错误。
- 必须在数据库服务器操作系统上执行
telnet smtp.example.com 587或openssl s_client -connect smtp.example.com:465 -crlf,不能在开发机或应用服务器上测 - 企业环境常见限制:DB Server 禁外网,只允许连内部中继(如
mail-relay.internal:25),需确认该地址+端口是否被运维白名单放行 - 若
telnet超时或拒绝连接,检查防火墙、SELinux(Oracle 用户是否被限制 socket)、代理配置,而非调优 PL/SQL 代码
UTL_MAIL 包未启用或参数配置缺失
UTL_MAIL 不是开箱即用的包,缺任何一环都会让 UTL_MAIL.SEND 直接失败,且错误信息不指向真实原因。
- 确认包已安装:
SELECT object_name FROM dba_objects WHERE object_name = 'UTL_MAIL' AND status = 'VALID'; - 检查当前用户权限:
SELECT * FROM dba_tab_privs WHERE table_name = 'UTL_MAIL' AND grantee = 'YOUR_USER'; - 确认
smtp_out_server参数已设且带端口:ALTER SYSTEM SET smtp_out_server = 'smtp.example.com:587' SCOPE=BOTH;(不能写成http://或漏端口) - 验证生效:
SELECT value FROM v$parameter WHERE name = 'smtp_out_server';返回非空才表示配置成功
参数格式与字符集陷阱导致乱码或静默丢弃
UTL_MAIL.SEND 对输入极其敏感,一个空格、一个换行、一个未声明的字符集,都可能让邮件被 SMTP 服务器拒收而不报错。
-
sender和recipients必须是完整邮箱格式(如'alert@company.com'),多个收件人用英文逗号分隔且**末尾不能有空格**:'a@x.com,b@y.com'✅,'a@x.com, b@y.com'❌ -
subject中避免CHR(10)、CHR(9)、中文双引号;建议预处理:REPLACE(subject, CHR(10), ' ') - 必须显式指定
mime_type => 'text/plain; charset=utf-8',否则默认用数据库字符集(如 WE8ISO8859P1),中文变问号 -
message长度上限为 32767 字节,超长会抛出误导性错误ORA-29260: network error: TNS:connection refused
ACL 权限缺失(Oracle 11g+ 特有)
11g 引入网络 ACL 控制后,即使包装好了、参数对了、网络通了,没 ACL 权限照样报 ORA-24247 —— 这个错误和密码、认证完全无关,纯属权限拦截。
- 需 DBA 执行:
DBMS_NETWORK_ACL_ADMIN.create_acl创建 ACL,并授予当前用户connect权限 - 再执行:
DBMS_NETWORK_ACL_ADMIN.assign_acl将该 ACL 绑定到目标 SMTP 地址和端口(注意lower_port和upper_port要覆盖实际使用的端口) - 验证 ACL 是否生效:
SELECT * FROM dba_network_acls;和SELECT * FROM dba_network_acl_privileges; - 常见误操作:ACL 名称拼错、host 写成域名但 DNS 解析失败、只赋权没 assign,三者缺一不可
最易被忽略的是:UTL_MAIL 只支持明文 SMTP,不支持 STARTTLS 或 SSL 加密协商。如果 SMTP 服务强制要求 TLS(比如 Gmail 的 587 端口、OCI Email Delivery),它必然失败——此时只能切到 UTL_SMTP 手动处理握手,别在 UTL_MAIL 上硬扛。











