Oracle

oracle 3106 采用oracle过程发邮件

这个网上有好多人已经做了解释,相关代码也很多,代码参考

收件人只有一个的过程如下:

CREATE OR REPLACE PROCEDURE p_mail_sina(sender    IN VARCHAR2,--发送人
                                                                    recipient IN VARCHAR2,--接收人
                                                                    subject   IN VARCHAR2,--邮件主题
                                                                    message   IN VARCHAR2) IS --邮件内容
   mailhost VARCHAR2(30) := '' ; --新浪邮箱服务器
   c        utl_smtp.connection;
   msg      VARCHAR2(1000);
BEGIN
   msg := 'Date: ' || to_char(SYSDATE - 1, 'dd mon yy hh24:mi:ss') ||
              utl_tcp.crlf || 'From: <' || sender || '>' || utl_tcp.crlf ||
              'subject: ' || subject || utl_tcp.crlf || 'To: <' || recipient || '>' ||
              utl_tcp.crlf || '' || utl_tcp.crlf || message;
   c   := utl_smtp.open_connection(mailhost, 25);
   mand(c, 'auth login'); --1
   mand(c, --2
                    utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw('用户名')))); --3 --发送邮箱用户名
   mand(c, --4
                    utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw('密码'))));--5 --发送邮箱密码
   utl_smtp.helo(c, mailhost);
   utl_smtp.mail(c, sender);
   utl_smtp.rcpt(c, recipient);
   utl_smtp.open_data(c);
   utl_smtp.write_raw_data(c, utl_raw.cast_to_raw(msg));
   utl_smtp.close_data(c);
   utl_smtp.quit(c);
EXCEPTION
   WHEN utl_smtp.transient_error OR utl_smtp.permanent_error THEN
      BEGIN
         utl_smtp.quit(c);
      EXCEPTION
         WHEN OTHERS THEN
            NULL;
      END;
   WHEN OTHERS THEN
      dbms_output.put_line(SQLERRM);
END p_mail_sina;

注意事项:

1.由于在测试中我采用的都是外网的方式发送接收邮件,因此必须加上用黄色圈出的这部分代码进行认证。内网内部发送就不需要了,不过没测试。

2. 黄色圈出的这部分代码第三行和第五行填写的内容分别是邮箱服务器对应的邮箱用户名和密码。

3.用于发送的邮箱的服务器必须创建acl,主要是三个步骤

 1)创建访问控制列表acl

 BEGIN

    DBMS_NETWORK_ACL_ADMIN.CREATE_ACL (
                                                                      acl          => 'email_server_permissions.xml',
                                                                      description  => 'Enables network permissions for the e-mail server',
                                                                      principal    => 'database_user',--进行操作的数据库用户且用户要大写
                                                                      is_grant     => TRUE,
                                                                      privilege    => 'connect');
END;

2)将ACL与邮件服务器关联(这一步,采用不同的邮箱服务器就需要分别执行,如想用qq邮箱发送,那么就必须换成qq邮箱服务器执行一遍)

BEGIN
DBMS_NETWORK_ACL_ADMIN.assign_acl (
                                                             acl         => 'email_server_permissions.xml',
                                                             host        => '', /*新浪的邮箱服务器地址,如果是用qq作为发送邮件,

                                                                                                         则用qq邮箱服务器地址*/
                                                             lower_port  => 25,
                                                             upper_port  => NULL);
  COMMIT;
END;

 关联后,可用dba_network_acls查看是否已经生成

SELECT host, lower_port, upper_port, acl FROM sys.dba_network_acls;

 3)为执行的数据库用户授予连接邮件服务器的权限

BEGIN
  dbms_network_acl_admin.add_privilege(
                                                           acl        => 'email_server_permissions.xml',
                                                           principal =>'database_user',--进行操作的数据库用户且用户要大写                                                                        

                                                           is_grant   =>  TRUE,
                                                           privilege  => 'connect');
END;

 采用dba_network_acl_privileges视图查看授予的权限

SELECT acl,
       principal,
       privilege,
       is_grant,
       TO_CHAR(start_date, 'DD-MON-YYYY') AS start_date,
       TO_CHAR(end_date, 'DD-MON-YYYY') AS end_date
  FROM sys.dba_network_acl_privileges;

 4.utl_tcp.crlf作用:换行

注意在写邮件标题,发送人,接收人,邮件内容时,各个之间一定要有换行,否则会无法发送或者是邮件内容为空。

5.中文乱码问题

    utl_smtp.write_raw_data 用该过程替代utl_smtp.write_data可以解决中文乱码的问题。

6.自己测试中发现如果采用qq邮箱发送邮件,则

utl_smtp.helo(c, mailhost);语句必须放在mand之前,否则无法发送,但是新浪邮箱则无所谓,这个不知何故。 ???

发给多个人

CREATE OR REPLACE PROCEDURE p_sendmailto_many(sender     IN VARCHAR2,
                                              recipient1 IN VARCHAR2,
                                              recipient2 IN VARCHAR2,
                                              recipient3 IN VARCHAR2,
                                              subject    IN VARCHAR2,
                                              message    IN VARCHAR2) IS
   mailhost VARCHAR2(30) := '';
   c        utl_smtp.connection;
   msg      VARCHAR2(1000);
BEGIN
   msg := 'Date: ' || to_char(SYSDATE - 1, 'dd mon yy hh24:mi:ss') ||
          utl_tcp.crlf || 'From: <' || sender || '>' || utl_tcp.crlf ||
          'subject: ' || subject || utl_tcp.crlf || 'To: <' || recipient1 ||
          '>;<' || recipient2 || '>' || utl_tcp.crlf || 'Cc: <' ||
          recipient3 || '>' || utl_tcp.crlf || '' || utl_tcp.crlf ||
          message;
   c   := utl_smtp.open_connection(mailhost, 25);
   utl_smtp.helo(c, mailhost);
   mand(c, 'auth login');
   mand(c,
                    utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(sender))));
   mand(c,
                    utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw('password'))));
   utl_smtp.mail(c, sender);
   utl_smtp.rcpt(c, recipient1);
   utl_smtp.rcpt(c, recipient2);
   utl_smtp.rcpt(c, recipient3);
   utl_smtp.open_data(c);
   utl_smtp.write_raw_data(c, utl_raw.cast_to_raw(msg));
   utl_smtp.close_data(c);
   utl_smtp.quit(c);
END p_sendmailto_many;