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
相关产品推荐
相关产品推荐

