UTL_MAIL是Oracle提供的内置PL/SQL工具包,用于在数据库内部直接发送电子邮件。它基于UTL_SMTP实现,但封装了SMTP通信细节,支持纯文本、HTML正文和常见附件类型。使用UTL_MAIL之前,需要确认数据库已安装相关对象,并完成SMTP服务参数与ACL权限配置,否则可能在调用时遇到ORA-24247或ORA-29278错误。

一、UTL_MAIL与UTL_SMTP的区别及适用场景
UTL_SMTP是Oracle提供的底层SMTP客户端接口,开发者需要手动处理SMTP会话,例如发送EHLO、MAIL FROM、RCPT TO、DATA等命令,同时还要负责MIME头编码、附件分隔和内容传输。这种方式非常灵活,可以实现SMTP认证、自定义邮件头以及超大附件等高级需求,但代码量通常较大,容易出错。
UTL_MAIL则在UTL_SMTP之上做了一层高层封装,提供了UTL_MAIL.SEND、UTL_MAIL.SEND_ATTACH_VARCHAR2、UTL_MAIL.SEND_ATTACH_RAW等过程,一次调用即可完成投递。对于大多数数据库自动告警、定时报表和任务完成通知等场景,UTL_MAIL的开发效率明显更高。不过它的主要限制是不能直接携带SMTP认证用户名和密码,只能连接一个无需认证或已配置为允许数据库服务器IP中继的SMTP服务。如果企业邮件网关强制要求AUTH LOGIN,则可能需要改用UTL_SMTP自己实现认证命令。
此外,UTL_MAIL对邮件头部的自定义能力有限,无法方便地添加自定义X-Header,但常规的收件人、抄送、密送、主题、优先级等需求均能满足。因此在选择方案时,应根据SMTP网关的认证要求、邮件格式复杂度以及是否有大规模邮件发送需求来综合判断。
二、启用UTL_MAIL的完整配置步骤
UTL_MAIL并非所有版本的Oracle数据库都会默认创建。可以通过查询DBA_OBJECTS确认SYS模式下是否存在UTL_MAIL包。因为UTL_MAIL属于SYS用户下的内置包,普通用户需要获得相应的执行权限才能调用。
SELECT object_name, object_type, status FROM dba_objects WHERE object_name LIKE 'UTL_MAIL%' AND owner = 'SYS';
如果查询结果为空,则需要以SYS用户登录,执行Oracle自带的安装脚本。脚本通常位于$ORACLE_HOME/rdbms/admin目录下,文件名分别为utlmail.sql和prvtmail.plb。执行顺序不能颠倒,先执行utlmail.sql创建包规范,再执行prvtmail.plb创建包体。完成后需要给业务用户授权,例如GRANT EXECUTE ON UTL_MAIL TO SCOTT;。
接下来需要设置数据库初始化参数SMTP_OUT_SERVER,该参数指定UTL_MAIL默认使用的SMTP服务器地址和端口。通常使用25端口,但如果SMTP服务部署在非标准端口,则需要显式写明端口号。
ALTER SYSTEM SET smtp_out_server = 'mail.ipipp.com:25' SCOPE = BOTH;
从Oracle 12c开始,数据库网络访问受到ACL(Access Control List)的严格限制。即使已经设置了SMTP_OUT_SERVER,如果没有为访问目标SMTP主机的用户授予connect权限,调用UTL_MAIL时仍会报ORA-24247错误。下面给出一个完整的ACL配置示例,创建ACL并将连接权限授予SCOTT用户,同时允许解析目标主机名。
BEGIN
DBMS_NETWORK_ACL_ADMIN.CREATE_ACL(
acl => 'utl_mail_acl.xml',
description => 'Allow SMTP access for UTL_MAIL',
principal => 'SCOTT',
is_grant => TRUE,
privilege => 'connect'
);
DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL(
acl => 'utl_mail_acl.xml',
host => 'mail.ipipp.com',
lower_port => 25,
upper_port => 25
);
DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE(
acl => 'utl_mail_acl.xml',
principal => 'SCOTT',
is_grant => TRUE,
privilege => 'resolve'
);
COMMIT;
END;
/
上述配置完成后,可以撰写一个简单的PL/SQL块测试邮件发送,如果能够正常收到邮件,则说明数据库侧配置已经生效。
三、纯文本与HTML邮件发送示例
UTL_MAIL.SEND是发送邮件最基础的过程,核心参数包括sender发件人地址、recipients收件人列表、cc抄送、bcc密送、subject主题、message正文以及mime_type内容类型。如果不显式传入mime_type,默认值为text/plain,适合发送普通文本通知。
下面示例演示从Oracle数据库发送一封纯文本告警邮件,收件人为管理员,主题说明表空间使用率情况。多个收件人可以使用分号或逗号进行分隔。
BEGIN
UTL_MAIL.SEND(
sender => 'oracle@ipipp.com',
recipients => 'admin@ipipp.com',
cc => NULL,
bcc => NULL,
subject => '数据库告警通知',
message => '表空间使用率已达到85%,请及时处理。',
mime_type => 'text/plain; charset=UTF-8'
);
END;
/
如果需要发送HTML格式的邮件,只需将mime_type设置为text/html; charset=UTF-8,并在message参数中放入HTML标记即可。要注意HTML内容中的尖括号在PL/SQL字符串中需要正确转义,否则数据库不会识别为字符串内容。以下示例展示如何发送一个包含标题和强调文本的HTML邮件。
DECLARE
v_body VARCHAR2(4000);
BEGIN
v_body := '<h1>告警通知</h1>' ||
'<p>请关注表空间 <strong>USERS</strong> 的使用情况。</p>';
UTL_MAIL.SEND(
sender => 'oracle@ipipp.com',
recipients => 'admin@ipipp.com',
subject => 'HTML格式告警邮件',
message => v_body,
mime_type => 'text/html; charset=UTF-8'
);
END;
/
需要注意的是,VARCHAR2变量在PL/SQL中最大长度为4000字节,在UTF-8字符集下每个中文字符占用3字节,因此HTML正文不宜过长。若邮件内容可能超过该限制,可以考虑拆分为多条发送,或者改用UTL_SMTP实现流式发送。
四、带附件邮件的实现
UTL_MAIL提供了一组专门用于发送附件的子程序,其中最常用的是SEND_ATTACH_VARCHAR2和SEND_ATTACH_RAW。前者适用于文本附件,后者适用于二进制附件。附件相关的参数包括att_filename附件文件名、att_mime_type附件的MIME类型以及attachment附件内容本身。
以下示例将一段CSV格式的日报数据作为附件发送给管理员。att_mime_type设置为text/csv,以便邮件客户端能够正确识别并打开附件。
DECLARE
v_report VARCHAR2(4000);
BEGIN
v_report := '日期,销售额' || CHR(13) || CHR(10) ||
'2025-01-01,1200' || CHR(13) || CHR(10) ||
'2025-01-02,1500';
UTL_MAIL.SEND_ATTACH_VARCHAR2(
sender => 'oracle@ipipp.com',
recipients => 'admin@ipipp.com',
subject => '日报附件',
message => '请查收附件中的日报数据。',
mime_type => 'text/plain; charset=UTF-8',
att_filename => 'daily_report.csv',
att_mime_type => 'text/csv',
attachment => v_report
);
END;
/
SEND_ATTACH_VARCHAR2的附件内容同样是VARCHAR2类型,因此也受到4000字节限制。如果需要发送二进制文件,可以从BLOB中读取数据并转换为RAW,再调用SEND_ATTACH_RAW,但RAW的长度同样有限,不适合超大文件。对于较大的附件,建议使用UTL_SMTP手动构造MIME多部分消息,或者借助外部调度工具完成投递。
五、常见错误与安全建议
调用UTL_MAIL时遇到ORA-24247错误,意味着网络访问被ACL拒绝。此时需要检查DBMS_NETWORK_ACL_ADMIN中配置的主机、端口和principal是否与当前数据库用户和SMTP服务器信息一致。即使ACL已经创建,也要确认COMMIT是否执行,以及是否为主机名和IP都分配了权限。另一个常见错误是ORA-29278,表示SMTP传输失败,通常与SMTP服务未启动、端口不通、防火墙拦截或SMTP_OUT_SERVER参数配置错误有关。可以先用telnet mail.ipipp.com 25测试网络连通性,再检查SMTP服务日志。
安全方面,建议为数据库发信使用一个专用的SMTP中继服务,并且只在ACL中开放必要的主机和端口。避免将数据库服务器直接暴露给外部SMTP网关,也不要在邮件正文中附带生产环境的敏感数据。如果SMTP服务支持白名单机制,可以仅允许数据库服务器的IP地址进行中继,否则邮件网关可能会被滥用。对于必须使用SMTP认证的环境,应改用UTL_SMTP实现认证过程,或使用操作系统级别的邮件客户端命令来完成发送。
另外,UTL_MAIL的调用会在数据库服务器上产生网络活动,建议对关键业务用户的UTL_MAIL执行权限进行最小化授权,并定期审查ACL列表。通过合理配置和规范使用,UTL_MAIL可以成为数据库自动运维通知体系中非常实用的组件。
Oracle UTL_MAIL发送邮件SMTP配置修改时间:2026-09-21 12:52:35