使用UTL_MAIL/UTL_SMTP时Outlook收件人列表被截断问题
问题描述
使用Oracle的UTL_MAIL或UTL_SMTP发送邮件时,Outlook的收件人(TO)字段仅显示240-260字符(约8-9个收件人),但实际所有80+收件人均能正常收到邮件。此前功能正常,近期出现该问题,测试场景(自身邮箱+70+测试邮箱)下问题复现。
测试代码如下:
DECLARE vemail VARCHAR2(4000); BEGIN SELECT LISTAGG(email,';') WITHIN GROUP(ORDER BY email) INTO vemail FROM (SELECT 'raa@nyc.org' email FROM dual UNION SELECT 'raa'||LEVEL||'@nyc.org' FROM dual connect BY LEVEL < 80 ); utl_mail.send (sender => 'test@nyc.org', recipients => vemail, cc => NULL, bcc => NULL, subject => 'TESTING', message => 'TESTING', mime_type => 'text/html; charset=us-ascii'); END;
可能原因
核心问题是邮件头行长度超出RFC规范导致Outlook解析截断。RFC 5322要求邮件头每行不超过78字符(需用软换行拆分),UTL_MAIL处理超长收件人列表时,未自动进行符合规范的换行处理,使得Outlook渲染To字段时仅显示前一部分内容,但不影响实际投递。
近期功能异常大概率源于以下变更:
- Outlook客户端/Exchange服务器更新,调整了邮件头解析逻辑
- Oracle数据库组件(UTL_MAIL/UTL_SMTP)更新,改变了长字段的处理方式
解决方案
方案1:使用UTL_SMTP逐个添加收件人
避免一次性传入超长收件人字符串,改用UTL_SMTP的RCPT命令逐个添加收件人,SMTP协议会自动处理邮件头的规范换行,Outlook能正确显示所有收件人:
DECLARE v_smtp_host VARCHAR2(100) := '你的SMTP服务器地址'; v_smtp_port NUMBER := 25; -- 或对应端口,如587 v_conn UTL_SMTP.CONNECTION; CURSOR c_recipients IS SELECT 'raa@nyc.org' email FROM dual UNION ALL SELECT 'raa'||LEVEL||'@nyc.org' FROM dual CONNECT BY LEVEL < 80; v_to_list VARCHAR2(4000); BEGIN -- 拼接收件人列表用于邮件头显示 SELECT LISTAGG(email, '; ') WITHIN GROUP(ORDER BY email) INTO v_to_list FROM c_recipients; -- 建立SMTP连接 v_conn := UTL_SMTP.OPEN_CONNECTION(v_smtp_host, v_smtp_port); UTL_SMTP.HELO(v_conn, 'nyc.org'); UTL_SMTP.MAIL(v_conn, 'test@nyc.org'); -- 逐个添加收件人 FOR rec IN c_recipients LOOP UTL_SMTP.RCPT(v_conn, rec.email); END LOOP; -- 发送邮件内容(包含规范格式的邮件头) UTL_SMTP.DATA(v_conn, 'From: test@nyc.org' || UTL_TCP.CRLF || 'To: ' || v_to_list || UTL_TCP.CRLF || 'Subject: TESTING' || UTL_TCP.CRLF || 'MIME-Version: 1.0' || UTL_TCP.CRLF || 'Content-Type: text/html; charset=us-ascii' || UTL_TCP.CRLF || UTL_TCP.CRLF || 'TESTING' ); UTL_SMTP.QUIT(v_conn); EXCEPTION WHEN OTHERS THEN IF UTL_SMTP.IS_CONNECTED(v_conn) THEN UTL_SMTP.QUIT(v_conn); END IF; RAISE; END;
方案2:手动为UTL_MAIL添加规范换行
如果坚持使用UTL_MAIL,可在拼接收件人列表时手动插入符合RFC规范的软换行(分号后加\r\n ,即换行+空格),确保邮件头每行长度合规:
DECLARE vemail VARCHAR2(4000); BEGIN SELECT LISTAGG(email, ';'||UTL_TCP.CRLF||' ') WITHIN GROUP(ORDER BY email) INTO vemail FROM (SELECT 'raa@nyc.org' email FROM dual UNION SELECT 'raa'||LEVEL||'@nyc.org' FROM dual connect BY LEVEL < 80 ); utl_mail.send (sender => 'test@nyc.org', recipients => vemail, cc => NULL, bcc => NULL, subject => 'TESTING', message => 'TESTING', mime_type => 'text/html; charset=us-ascii'); END;
验证建议
测试时可通过Outlook查看邮件原始头(右键邮件→查看邮件头),检查To字段是否按规范换行,确保每行长度不超过78字符。
内容的提问来源于stack exchange,提问作者Rajiv A
相关产品推荐
相关产品推荐

