邮件通知预警和提示在当前系统中已经是一个比较常见的功能。各类型语言分别针对邮件提供了功能包和API接口方法,本篇介绍如何在PL/SQL代码中使用UTL_MAIL工具包发送邮件,同时还介绍配置中注意的细节要点。
1、安装UTL_MAIL包
UTL_MAIL是在Oracle10g推出的新邮件发送开发包。之前Oracle 8i开始,支持使用utl_smtp包进行RFC所定义的简单邮件传输协议(SMTP)。使用UTL_MAIL要简单与传统方式,免除很多额外工作。
默认情况下,UTL_MAIL工具包是没有安装到Oracle程序包中的,如果需要使用需要额外进行安装。安装的方法是在sys用户下,调用$ORACLE_HOME/rdbms/admin目录下的两个脚本文件。
SQL> conn / as sysdba;
Connected.
SQL> @$ORACLE_HOME/rdbms/admin/utlmail.sql
Package created.
Synonym created.
SQL> @$ORACLE_HOME/rdbms/admin/prvtmail.plb
Package created.
Package body created.
Grant succeeded.
Package body created.
No errors.
两个脚本的作用就是建立utl_mail工具包。之后要进行一些参数配置,其中最重要的是smtp_out_server参数。该参数指定的是连接邮件服务器的名称(或者ip地址)。默认情况下,该字符串类型参数的取值为空。
SQL> show parameter smtp
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
smtp_out_server string
设置上指定的邮件服务器。
--需要设置该参数
SQL> alter system set smtp_out_server='10.1.2.55'scope=both;
System altered.
//动态修改后立刻生效
SQL> show parameter smtp
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
smtp_out_server string 10.1.2.55
注意:在一些Oracle早期版本中,该参数smtp_out_server是不支持动态修改(scope=memory)的。所以只能使用静态修改(scope=spfile),之后重启动数据库服务器。笔者实验的环境是oracle11gR2,是支持动态修改的。
2、在SYS上直接使用utl_mail包
首先实验下在sys下使用utl_mail包,发送邮件的方法是utl_mail.send方法。下面是方法签名。
Send方法参数很多,大部分都有使用默认值的机会。下面分别介绍一下各个参数。
ü Sender:发送者,为必填参数。填写邮件发送者邮箱地址;
ü Recipients:接收者邮箱列表,如果是多个使用逗号进行分割;
ü Cc:邮件抄送列表;
ü Bcc:邮件密文抄送列表;
ü Subject:邮件主题;
ü Message:邮件信息内容;
ü Mine_type:编码格式;
ü Priority:消息的优先级;
下面在sys下使用utl_mail.send方法发送邮件。
--直接使用在sys上
begin
utl_mail.send(sender => 'liuziyu@acca.com.cn',
recipients => 'realkid4@126.com',
message => 'sdlfsdfsdfsdfseew**师地方是',
subject => 'SCCS航空');
end;
/
SQL>
PL/SQL procedure successfully completed
到接受邮箱中,果然看到了发送邮件。SYS下使用成功。
3、非SYS用户使用邮箱配置
如果是在非SYS用户下直接使用utl_mail包,需要进行何种配置呢?首先是进行包执行权限配置。需要将utl_tcp、utl_mail、utl_smtp和dbms_network_acl_admin四个包的执行权限赋给该用户。
SQL> grant execute on utl_tcp to scott;
Grant succeeded
SQL> grant execute on utl_smtp to scott;
Grant succeeded
SQL> grant execute on utl_mail to scott;
Grant succeeded
SQL> grant execute on dbms_network_acl_admin to scott;
Grant succeeded
之后,实验使用。
//在scott用户下调用
SQL>
begin
utl_mail.send(sender => 'liuziyu@acca.com.cn',
recipients => 'realkid4@126.com',
message => 'sdlfsdfsdfsdfseew**师地方是',
subject => ' SCCS航空');
end;
ORA-24247:网络访问被访问控制列表(ACL)拒绝
ORA-06512:在"SYS.UTL_MAIL", line 654
ORA-06512:在"SYS.UTL_MAIL", line 671
ORA-06512:在line 2
相同的执行语句,并且已经进行赋予执行权限,为什么报错24247呢?使用utl_mail要求系统对调用用户开启ACL(Access Control List)访问控制列表权限,允许用户具有连接connect到网络邮件服务器的权限。可以使用如下方法进行赋予权限操作。
Begin
//设置权限项目
DBMS_NETWORK_ACL_ADMIN.CREATE_ACL (acl => 'email_server_permissions.xml',
description => 'Enables network permissions for the e-mail server',
principal => 'SCOTT',
is_grant => TRUE,
privilege => 'connect');
end;
/
BEGIN
//指定访问主机和相应端口;
DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL (acl => 'email_server_permissions.xml',
host => '10.1.2.55',
lower_port => 25);
END;
/
之后再使用发送邮件方法:
SQL> begin
2 utl_mail.send(sender => 'liuziyu@acca.com.cn',
3 recipients => 'realkid4@126.com',
4 message => 'sdlfsdf电风扇fsdfseew**师地方是',
5 subject => '中国中心');
6
7 end;
8 /
PL/SQL procedure successfully completed
发送成功,也在接受邮箱上发现邮件。
4、乱码问题解决
我们上面邮件打开之后,发现邮件subject显示正常中文,而message内容显示出乱码。为如下:
sdlfsdf???fsdfseew??????
看来是中文引起的编码问题。可以通过调用中改写mine_type参数的方法来解决。默认情况下,邮件字符集是us-ascii方式的。支持中文可以使用UTF-8。
SQL> begin
2 utl_mail.send(sender => 'liuziyu@acca.com.cn',
3 recipients => 'realkid4@126.com',
4 message => 'sdlfsdf电风扇fsdfseew**师地方是',
5 subject => '中国中心',
6 mime_type => 'text/plain;charset=UTF-8');
7
8 end;
9 /
PL/SQL procedure successfully completed
接受到的邮件内容为:
sdlfsdf电风扇fsdfseew**师地方是
显示正常。
5、Utl_mail使用实践和结论
系统功能中,邮件是一个比较特殊的功能。其中发送者邮箱、邮件服务器位置等内容常常是统一,而且不对一般模块可配置的。所以,笔者建议如下使用UTL_MAIL包方法。
ü 使用包封装方法,将UTL_MAIL方法不直接暴露给系统用户,而是在SYS下建立一个自定义邮件发送方法,预设值好发送者邮箱等内容。主题和信息都已参数的形式传入;
ü 借用所有者权限机制,将执行自定义方法的执行权限赋给系统用户schema。这样可以控制用户的权限不会滥用,也便于管理;
UTL_MAIL较传统的简单邮件传输方法,调用方式简化了很多,易用性增强。除了本次介绍的send方法,还可以实现附件内容的发送。这些复杂功能就留待日后继续研究。
常见错误:
首先打开一个SMTP连接,输入一个邮件服务器的地址,注意如果邮件服务器地址不正确会出现类似这样的错误:
第 1 行出现错误:
ORA-29278: SMTP 临时性错误: 421 Service not available
ORA-06512: 在 "SYS.UTL_SMTP", line 21
ORA-06512: 在 "SYS.UTL_SMTP", line 97
ORA-06512: 在 "SYS.UTL_SMTP", line 139
ORA-06512: 在 line 4
随后输入的分别是用户名和密码。
其实本来打算用UTL_MAIL包实现发邮件的功能,使用UTL_MAIL包基本上一行代码就可以了,但是现在几乎所有的邮件服务器都要求授权验证,因此只能使用UTL_SMTP包来实现,注意如果用户名、密码出现错误,则会报错:
第 1 行出现错误:
ORA-29279: SMTP 永久性错误: 535 authorization failed (#5.7.0)
ORA-06512: 在 "SYS.UTL_SMTP", line 21
ORA-06512: 在 "SYS.UTL_SMTP", line 99
ORA-06512: 在 "SYS.UTL_SMTP", line 159
ORA-06512: 在 line 8
如果没有将用户名密码进行编码就直接发送,会碰到下面的错误:
第 1 行出现错误:
ORA-29279: SMTP 永久性错误: 501 malformed auth input (#5.5.4)
ORA-06512: 在 "SYS.UTL_SMTP", line 21
ORA-06512: 在 "SYS.UTL_SMTP", line 99
ORA-06512: 在 "SYS.UTL_SMTP", line 159
ORA-06512: 在 line 7
如果没有设置用户名、密码,或者使用UTL_MAIL包连接到需要授权验证的邮件服务器,则会报错如下:
第 1 行出现错误:
ORA-29279: SMTP 永久性错误: 554 auth login first
ORA-06512: 在 "SYS.UTL_SMTP", line 21
ORA-06512: 在 "SYS.UTL_SMTP", line 99
ORA-06512: 在 "SYS.UTL_SMTP", line 241
ORA-06512: 在 "SYS.UTL_MAIL", line 424
ORA-06512: 在 "SYS.UTL_MAIL", line 594
ORA-06512: 在 line 2