PL/SQL调用UTL_SMTP发邮件报ORA-29279 503 5.5.2错误
问题现象
在PL/SQL中通过UTL_SMTP对接Outlook SMTP服务器(587端口)发送邮件时,抛出如下永久错误:
ORA-29279: SMTP permanent error: 503 5.5.2 Send hello first [LO4P123CA0158.GBRP123.PROD.OUTLOOK.COM]
原有业务实现代码如下:
l_mail_conn := UTL_SMTP.open_connection(host, '587'); utl_smtp.starttls(l_mail_conn); UTL_SMTP.AUTH(l_mail_conn, msg_from, password, schemes => 'PLAIN'); UTL_SMTP.mail(l_mail_conn, msg_from); UTL_SMTP.rcpt(l_mail_conn, msg_to); UTL_SMTP.open_data(l_mail_conn); UTL_SMTP.write_data(l_mail_conn, 'Date: ' || TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') || UTL_TCP.crlf); UTL_SMTP.write_data(l_mail_conn, 'To: ' || msg_to || UTL_TCP.crlf); UTL_SMTP.write_data(l_mail_conn, 'From: ' || msg_from || UTL_TCP.crlf); UTL_SMTP.write_data(l_mail_conn, 'Subject: ' || 'Test Email' || UTL_TCP.crlf); UTL_SMTP.write_data(l_mail_conn, 'Reply-To: ' || msg_to || UTL_TCP.crlf || UTL_TCP.crlf); UTL_SMTP.write_data(l_mail_conn, 'Sent using UTL_SMTP' || UTL_TCP.crlf || UTL_TCP.crlf); UTL_smtp.close_data(l_mail_conn); UTL_SMTP.quit(l_mail_conn);
报错原因
按照SMTP协议规范,客户端必须先向服务器发送EHLO(兼容认证、TLS等扩展能力的扩展SMTP指令)或HELO(基础SMTP指令),携带客户端标识完成会话初始化,才能执行后续认证、邮件传输操作。
原有代码存在两处流程缺失:
- 建立明文TCP连接后,未发送
EHLO指令就直接调用starttls发起TLS握手 - TLS握手完成后,未重新发送
EHLO指令初始化加密会话上下文,就直接发起AUTH认证请求
Outlook SMTP服务器未收到hello指令就接收到后续操作请求,直接返回503永久错误拒绝请求。
修复方法
在对应流程节点补充UTL_SMTP.ehlo调用即可,第二个参数传入客户端标识,无特殊标识可填写localhost或发件人域名。
修正后的完整代码:
l_mail_conn := UTL_SMTP.open_connection(host, '587'); -- 明文连接建立后先发送EHLO,声明支持TLS扩展 UTL_SMTP.ehlo(l_mail_conn, 'localhost'); utl_smtp.starttls(l_mail_conn); -- TLS握手完成后,重新在加密会话上发送EHLO,声明支持认证扩展 UTL_SMTP.ehlo(l_mail_conn, 'localhost'); UTL_SMTP.AUTH(l_mail_conn, msg_from, password, schemes => 'PLAIN'); UTL_SMTP.mail(l_mail_conn, msg_from); UTL_SMTP.rcpt(l_mail_conn, msg_to); UTL_SMTP.open_data(l_mail_conn); UTL_SMTP.write_data(l_mail_conn, 'Date: ' || TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') || UTL_TCP.crlf); UTL_SMTP.write_data(l_mail_conn, 'To: ' || msg_to || UTL_TCP.crlf); UTL_SMTP.write_data(l_mail_conn, 'From: ' || msg_from || UTL_TCP.crlf); UTL_SMTP.write_data(l_mail_conn, 'Subject: ' || 'Test Email' || UTL_TCP.crlf); UTL_SMTP.write_data(l_mail_conn, 'Reply-To: ' || msg_to || UTL_TCP.crlf || UTL_TCP.crlf); UTL_SMTP.write_data(l_mail_conn, 'Sent using UTL_SMTP' || UTL_TCP.crlf || UTL_TCP.crlf); UTL_smtp.close_data(l_mail_conn); UTL_SMTP.quit(l_mail_conn);
注意:如果EHLO调用返回不支持的错误,可替换为
UTL_SMTP.helo调用,Outlook系SMTP服务默认兼容EHLO扩展。
内容的提问来源于stack exchange,提问作者Kushal Shah
相关产品推荐
相关产品推荐

