ora-24247错误根本原因是acl未正确配置,需确保principal大小写与dba_users.username完全一致、host和端口精确匹配目标服务、utl_*包已授execute权限,并执行commit。

ORA-24247 错误不是权限没给全,而是 ACL 没配对 —— principal 大小写必须和实际用户名完全一致,host 和端口范围没覆盖 SMTP 服务实际使用的地址与端口,或者 UTL_SMTP/UTL_TCP 包本身没被授权执行。
ACL 创建时 principal 大小写敏感且必须存在
Oracle 对 principal 参数严格区分大小写,且该用户必须已存在。比如你用的是 APEX_190200,但实际登录用户名是 apex_190200 或 APEX_190200(注意 Oracle 默认大写),写错就白配。
-
principal必须和dba_users.username中查到的值完全一致(可用SELECT username FROM dba_users WHERE UPPER(username) LIKE '%APEX%'确认) - 不能填角色名(如
CONNECT)、不能填通配符、不能拼错(APEX_190200≠APEX_1902000) - 如果用户是通过外部认证或代理连接的,需确认其直接数据库用户名,而非应用层别名
assign_acl 的 host 和 port 范围必须匹配真实 SMTP 服务
dbms_network_acl_admin.assign_acl 的 host 参数不支持正则或模糊匹配,只接受精确域名、IP 或通配符 *;lower_port/upper_port 若未指定,默认为 NULL,即只允许端口 NULL(无效),必须显式设范围。
- QQ 邮箱 SMTP 地址是
smtp.qq.com,端口是587(STARTTLS)或465(SSL),所以host应填'smtp.qq.com'或'*',但后者更宽松 - 若填
host => 'smtp.qq.com',但代码里连的是smtp.exmail.qq.com,就会拒绝 - 务必加端口范围:例如
lower_port => 587, upper_port => 587或宽泛点lower_port => 1, upper_port => 65535 - 测试是否生效:用被授权用户执行
UTL_TCP.OPEN_CONNECTION('smtp.qq.com', 587),不报 ORA-24247 才算通
UTL_* 包的 EXECUTE 权限不能漏
ACL 控制网络访问路径,但 UTL_SMTP 和 UTL_TCP 是独立的 PL/SQL 包,DBA 还需显式授予 EXECUTE 权限,否则会报 PLS-00201: identifier 'UTL_SMTP' must be declared 或权限不足。
- 用 DBA 账户执行:
GRANT EXECUTE ON UTL_SMTP TO APEX_190200 - 同样要授
UTL_TCP:GRANT EXECUTE ON UTL_TCP TO APEX_190200 - 注意:
UTL_MAIL虽更简单,但依赖内部配置(SMTP_OUT_SERVER),且默认禁用,不推荐新项目使用 - 如果用的是 Oracle 12c+,确认用户没有被限制在 PDB 内而 ACL 在 CDB 级创建 —— 跨容器需用
CDB$ROOT上下文操作
验证 ACL 是否真正生效的三步检查法
光看 SQL 不报错不代表 ACL 生效,得逐层验证。最容易忽略的是 ACL 文件没提交或没 assign 到对应 host。
- 查 ACL 是否注册:
SELECT any_path FROM resource_view WHERE any_path LIKE '/sys/acls/%.xml',没结果说明CREATE_ACL后没COMMIT - 查权限是否绑定到用户:
SELECT acl, principal, privilege, is_grant FROM dba_network_acl_privileges WHERE principal = 'APEX_190200' - 查 host 映射是否命中:
SELECT host, lower_port, upper_port, acl FROM dba_network_acls WHERE host IN ('*', 'smtp.qq.com'),确保返回行包含你配的acl名
ACL 配置不是“一次写完就完事”,它本质是 XML 文件存于 XDB,assign_acl 是把规则挂载到某个 host 节点上 —— 挂载失败、host 写错、端口没开、包没授权,四个环节任一出错都会卡在 ORA-24247。最稳妥的做法是:先用最小集(单 host + 单端口 + 单用户)验证通路,再逐步放宽范围。











