You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PLSQL使用UTL_MAIL发邮件报ORA-29278 STARTTLS错误如何解决

解决方案

错误核心原因

ORA-29278报错的核心是Hotmail/Office365的SMTP服务强制要求STARTTLS加密传输,低于12cR2版本的Oracle原生UTL_MAIL包默认不支持TLS加密的SMTP连接,因此直接调用会触发该错误。

方案1:通用UTL_SMTP实现(兼容所有Oracle版本)

前置配置1:配置网络ACL权限

用SYS用户执行以下命令,替换<数据库用户名>为实际执行发邮件操作的数据库账号:

BEGIN
  DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
    host => 'smtp.office365.com',
    lower_port => 587,
    upper_port => 587,
    ace => XS$ACE_TYPE(
      privilege_list => XS$NAME_LIST('connect', 'resolve'),
      principal_name => '<数据库用户名>',
      principal_type => XS_ACL.PTYPE_DB
    )
  );
  COMMIT;
END;
/

前置配置2:导入SMTP服务证书到Oracle钱包

  • 导出Office365 SMTP服务的根证书(可通过openssl命令获取,或从浏览器访问Outlook官网导出根证书)
  • 创建Oracle自动登录钱包,执行操作系统命令:
    orapki wallet create -wallet /home/oracle/wallet/smtp_wallet -pwd <钱包密码> -auto_login
  • 导入根证书到钱包:
    orapki wallet add -wallet /home/oracle/wallet/smtp_wallet -pwd <钱包密码> -trusted_cert -cert /path/office365_root.cer

发送邮件代码

替换代码内的钱包路径、密码、邮箱账号等参数后执行:

DECLARE
  l_smtp_conn UTL_SMTP.connection;
  l_wallet_path VARCHAR2(100) := 'file:/home/oracle/wallet/smtp_wallet';
  l_wallet_pwd VARCHAR2(30) := '<你的钱包密码>';
  l_smtp_server VARCHAR2(50) := 'smtp.office365.com';
  l_smtp_port PLS_INTEGER := 587;
  l_sender VARCHAR2(100) := 'example@hotmail.com';
  l_recipient VARCHAR2(100) := 'test1@hotmail.com';
BEGIN
  -- 初始化SMTP连接
  l_smtp_conn := UTL_SMTP.open_connection(
    host => l_smtp_server,
    port => l_smtp_port,
    wallet_path => l_wallet_path,
    wallet_password => l_wallet_pwd,
    secure_connection_before_smtp => FALSE
  );
  -- 开启STARTTLS加密
  UTL_SMTP.starttls(
    con => l_smtp_conn,
    wallet_path => l_wallet_path,
    wallet_password => l_wallet_pwd
  );
  -- SMTP身份认证
  UTL_SMTP.ehlo(l_smtp_conn, l_smtp_server);
  UTL_SMTP.auth(l_smtp_conn, 'example@hotmail.com', '<你的邮箱应用专用密码>', UTL_SMTP.ALL_SCHEMES);
  -- 写入邮件内容
  UTL_SMTP.mail(l_smtp_conn, l_sender);
  UTL_SMTP.rcpt(l_smtp_conn, l_recipient);
  UTL_SMTP.open_data(l_smtp_conn);
  UTL_SMTP.write_data(l_smtp_conn, 'From: ' || l_sender || UTL_TCP.crlf);
  UTL_SMTP.write_data(l_smtp_conn, 'To: ' || l_recipient || UTL_TCP.crlf);
  UTL_SMTP.write_data(l_smtp_conn, 'Subject: Test Mail' || UTL_TCP.crlf);
  UTL_SMTP.write_data(l_smtp_conn, 'Content-Type: text/plain; charset=us-ascii' || UTL_TCP.crlf || UTL_TCP.crlf);
  UTL_SMTP.write_data(l_smtp_conn, 'Hello World');
  UTL_SMTP.close_data(l_smtp_conn);
  UTL_SMTP.quit(l_smtp_conn);
EXCEPTION
  WHEN OTHERS THEN
    UTL_SMTP.quit(l_smtp_conn);
    RAISE;
END;
/

方案2:12cR2及以上版本直接使用UTL_MAIL发送

12cR2版本之后UTL_MAIL包新增了加密相关参数,配置后可直接使用:

第一步:修改SMTP服务配置

ALTER SYSTEM SET SMTP_OUT_SERVER='smtp.office365.com:587';

第二步:执行发送代码

BEGIN
  UTL_MAIL.send(
    sender => 'example@hotmail.com',
    recipients => 'test1@hotmail.com',
    subject => 'Test Mail',
    message => 'Hello World',
    mime_type => 'text; charset=us-ascii',
    secure => 'STARTTLS',
    wallet_path => 'file:/home/oracle/wallet/smtp_wallet',
    wallet_password => '<你的钱包密码>'
  );
END;
/

注意事项

  • 微软邮箱默认禁用基础身份认证,需要提前在账号安全设置中开启应用专用密码,或为账号开启SMTP基础认证权限,否则会触发认证错误
  • 配置钱包时必须开启auto_login属性,避免数据库重启后钱包无法正常访问
  • 提前确认数据库服务器可以正常访问smtp.office365.com的587端口,可通过telnet、nc等工具测试网络连通性

内容的提问来源于stack exchange,提问作者AlanV

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 09:39:02