PL/SQL 下邮件发送程序

对DBA而言,尽管在os级别下发送邮件是轻而易举的事情,然而很多时候我们也需要在PL/SQL中来发送邮件,比如监控job的执行状况等。本文根据网友(源作者未考证)的代码将其改装并封装到了package,感谢这位网友的无私奉献。文章首先给出演示调用该包发送邮件的情形后面给出了完整的代码。经测试Oracle 10g,Oracle 11g下均可用。关于os下发送邮件可参考:不可或缺的 sendEmail

 

1、调用SENDMAIL_PKG来发送邮件

  1. gx_admin@SYBO2SZ> set serveroutput on;  
  2. gx_admin@SYBO2SZ> DECLARE   
  3.   2    P_RECEIVER VARCHAR2(32767);  
  4.   3    P_SUB VARCHAR2(32767);  
  5.   4    P_TXT VARCHAR2(32767);  
  6.   5    ERR_NUM NUMBER;  
  7.   6    ERR_MSG VARCHAR2(32767);  
  8.   7    
  9.   8  BEGIN   
  10.   9    P_RECEIVER := 'robinson.chen@12306.com';  
  11.  10    P_SUB := 'Test mail';  
  12.  11    P_TXT := 'This is a test mail.';  
  13.  12    ERR_NUM := NULL;  
  14.  13    ERR_MSG := NULL;  
  15.  14    
  16.  15    SENDMAIL_PKG.SENDMAIL ( P_RECEIVER, P_SUB, P_TXT, ERR_NUM, ERR_MSG );  
  17.  16    
  18.  17    DBMS_OUTPUT.Put_Line('ERR_NUM = ' || TO_CHAR(ERR_NUM));  
  19.  18    DBMS_OUTPUT.Put_Line('ERR_MSG = ' || ERR_MSG);  
  20.  19    
  21.  20    DBMS_OUTPUT.Put_Line('');  
  22.  21    
  23.  22    COMMIT;   
  24.  23  END;  
  25.  24  /  
  26. ERR_NUM = 0  
  27. ERR_MSG =  
  28.   
  29. PL/SQL procedure successfully completed.  


2、邮件发送结果

     

3、原代码

  1. --specification section  
  2. CREATE OR REPLACE PACKAGE "SENDMAIL_PKG"  
  3. IS  
  4.    PROCEDURE sendmail (p_receiver       VARCHAR2,  
  5.                        p_sub            VARCHAR2,  
  6.                        p_txt            VARCHAR2,  
  7.                        err_num      OUT NUMBER,  
  8.                        err_msg      OUT VARCHAR2);  
  9. END;  
  10. /  
  11.   
  12. --body section  
  13. CREATE OR REPLACE PACKAGE BODY "SENDMAIL_PKG"  
  14. IS  
  15.    PROCEDURE sendmail (p_receiver       VARCHAR2,  
  16.                        p_sub            VARCHAR2,  
  17.                        p_txt            VARCHAR2,  
  18.                        err_num      OUT NUMBER,  
  19.                        err_msg      OUT VARCHAR2)  
  20.    IS  
  21.       /*   p_receiver   =>  receiver  
  22.              p_sub              =>  mail subject  
  23.              p_txt                => mail content  
  24.       */  
  25.       p_user                         VARCHAR2 (30) := NULL;  
  26.       p_pass                         VARCHAR2 (30) := NULL;  
  27.       p_sendor                       VARCHAR2 (40) := 'DBA@gotrade.com';  
  28.       p_server                       VARCHAR2 (20)  
  29.                            --             := system_pkg.get_sys_para_value ('TC_SMTP_IP'); --'192.168.7.65';  
  30.                                         :='192.168.7.65';  
  31.       p_port                         NUMBER := 25;  
  32.       p_need_smtp                    NUMBER := 0;  
  33.       p_subject                      VARCHAR2 (4000);  
  34.       l_crlf                         VARCHAR2 (2) := UTL_TCP.crlf;  
  35.       l_sendoraddress                VARCHAR2 (4000);  
  36.       l_splite                       VARCHAR2 (10) := '++';  
  37.       boundary              CONSTANT VARCHAR2 (256) := '-----BYSUK';  
  38.       first_boundary        CONSTANT VARCHAR2 (256) := '--' || boundary || l_crlf;  
  39.       last_boundary         CONSTANT VARCHAR2 (256)  
  40.                                         := '--' || boundary || '--' || l_crlf ;  
  41.       multipart_mime_type   CONSTANT VARCHAR2 (256)  
  42.          := 'multipart/mixed; boundary="' || boundary || '"' ;  
  43.   
  44.       TYPE address_list IS TABLE OF VARCHAR2 (100)  
  45.                               INDEX BY BINARY_INTEGER;  
  46.   
  47.       my_address_list                address_list;  
  48.   
  49.       ---------------------------------------split mail address----------------------------------------------  
  50.       PROCEDURE p_splite_str (p_str VARCHAR2, p_splite_flag INT DEFAULT 1)  
  51.       IS  
  52.          l_addr   VARCHAR2 (254) := '';  
  53.          l_len    INT;  
  54.          l_str    VARCHAR2 (4000);  
  55.          j        INT := 0;  
  56.       BEGIN  
  57.          /*Handle recieve mail address, such like blank, semicolon*/  
  58.          l_str :=  
  59.             TRIM (RTRIM (REPLACE (REPLACE (p_str, ';'','), ' '''), ','));  
  60.          l_len := LENGTH (l_str);  
  61.   
  62.          FOR i IN 1 .. l_len  
  63.          LOOP  
  64.             IF SUBSTR (l_str, i, 1) <> ','  
  65.             THEN  
  66.                l_addr := l_addr || SUBSTR (l_str, i, 1);  
  67.             ELSE  
  68.                j := j + 1;  
  69.   
  70.                IF p_splite_flag = 1  
  71.                THEN  
  72.                   --Add  symbol  '<>'  for each mail address. else could not send to many reciever  
  73.                   l_addr := '<' || l_addr || '>';  
  74.   
  75.                   my_address_list (j) := l_addr;  
  76.                END IF;  
  77.   
  78.                l_addr := '';  
  79.             END IF;  
  80.   
  81.             IF i = l_len  
  82.             THEN  
  83.                j := j + 1;  
  84.   
  85.                IF p_splite_flag = 1  
  86.                THEN  
  87.                   l_addr := '<' || l_addr || '>';  
  88.                   my_address_list (j) := l_addr;  
  89.                END IF;  
  90.             END IF;  
  91.          END LOOP;  
  92.       END;  
  93.   
  94.       -----------------------------------write mail header and mail content----------------------------------  
  95.       PROCEDURE write_data (p_conn     IN OUT NOCOPY UTL_SMTP.connection,  
  96.                             p_name     IN            VARCHAR2,  
  97.                             p_value    IN            VARCHAR2,  
  98.                             p_splite                 VARCHAR2 DEFAULT ':',  
  99.                             p_crlf                   VARCHAR2 DEFAULT l_crlf)  
  100.       IS  
  101.       BEGIN  
  102.          /* utl_raw.cast_to_raw  to handle chinese code*/  
  103.          UTL_SMTP.write_raw_data (  
  104.             p_conn,  
  105.             UTL_RAW.cast_to_raw (  
  106.                CONVERT (p_name || p_splite || p_value || p_crlf,  
  107.                         'ZHS16CGB231280')));  
  108.       END;  
  109.   
  110.       ----------------------------------------write mime mail tail-----------------------------------------------------  
  111.       PROCEDURE end_boundary (conn   IN OUT NOCOPY UTL_SMTP.connection,  
  112.                               LAST   IN            BOOLEAN DEFAULT FALSE)  
  113.       IS  
  114.       BEGIN  
  115.          UTL_SMTP.write_data (conn, UTL_TCP.crlf);  
  116.   
  117.          IF (LAST)  
  118.          THEN  
  119.             UTL_SMTP.write_data (conn, last_boundary);  
  120.          END IF;  
  121.       END;  
  122.   
  123.       ---------------------------------------------send mail procedure--------------------------------------------  
  124.       PROCEDURE p_email (p_sendoraddress2      VARCHAR2,      --sender address  
  125.                          p_receiveraddress2    VARCHAR2)    --reciever address  
  126.       IS  
  127.          l_conn   UTL_SMTP.connection;                   --create a connection  
  128.       BEGIN  
  129.          /*Initial mail server*/  
  130.          l_conn := UTL_SMTP.open_connection (p_server, p_port);  
  131.          UTL_SMTP.helo (l_conn, p_server);  
  132.   
  133.          /* smtp authentication*/  
  134.          IF p_need_smtp = 1  
  135.          THEN  
  136.             UTL_SMTP.command (l_conn, 'AUTH LOGIN''');  
  137.             UTL_SMTP.command (  
  138.                l_conn,  
  139.                UTL_RAW.cast_to_varchar2 (  
  140.                   UTL_ENCODE.base64_encode (UTL_RAW.cast_to_raw (p_user))));  
  141.             UTL_SMTP.command (  
  142.                l_conn,  
  143.                UTL_RAW.cast_to_varchar2 (  
  144.                   UTL_ENCODE.base64_encode (UTL_RAW.cast_to_raw (p_pass))));  
  145.          END IF;  
  146.   
  147.          /*configure sender and reciever mail address*/  
  148.          UTL_SMTP.mail (l_conn, p_sendoraddress2);  
  149.          UTL_SMTP.rcpt (l_conn, p_receiveraddress2);  
  150.          /*configure mail header*/  
  151.          UTL_SMTP.open_data (l_conn);  
  152.          /*configure date*/  
  153.          --write_data(l_conn, 'Date', to_char(sysdate-1/3, 'dd Mon yy hh24:mi:ss'));  
  154.          /*configure sender*/  
  155.          write_data (l_conn, 'From', p_sendor);  
  156.          /*configure reciever*/  
  157.          write_data (l_conn, 'To', p_receiver);  
  158.   
  159.          /*add mail subject*/  
  160.          SELECT REPLACE (  
  161.                    '=?GB2312?B?'  
  162.                    || UTL_RAW.cast_to_varchar2 (  
  163.                          UTL_ENCODE.base64_encode (RAWTOHEX (p_sub)))  
  164.                    || '?=',  
  165.                    UTL_TCP.crlf,  
  166.                    '')  
  167.            INTO p_subject  
  168.            FROM DUAL;  
  169.   
  170.          write_data (l_conn, 'Subject', p_subject);  
  171.          write_data (l_conn, 'Content-Type', multipart_mime_type);  
  172.          UTL_SMTP.write_data (l_conn, UTL_TCP.crlf);  
  173.          UTL_SMTP.write_data (l_conn, first_boundary);  
  174.          write_data (l_conn, 'Content-Type''text/html');  
  175.   
  176.          UTL_SMTP.write_data (l_conn, UTL_TCP.crlf);  
  177.   
  178.          write_data (  
  179.             l_conn,  
  180.             '',  
  181.             REPLACE (REPLACE (p_txt, l_splite, CHR (10)), CHR (10), l_crlf),  
  182.             '',  
  183.             '');  
  184.          end_boundary (l_conn);  
  185.          /*close write data*/  
  186.          UTL_SMTP.close_data (l_conn);  
  187.          /*close connection*/  
  188.          UTL_SMTP.quit (l_conn);  
  189.       END;  
  190.    ---------------------------------------------main procedure -----------------------------------------------------  
  191.    BEGIN  
  192.       err_num := 0;  
  193.       l_sendoraddress := '<' || p_sendor || '>';  
  194.       p_splite_str (p_receiver);                         --handle mail address  
  195.   
  196.       FOR k IN 1 .. my_address_list.COUNT  
  197.       LOOP  
  198.          p_email (l_sendoraddress, my_address_list (k));  
  199.       END LOOP;  
  200.    END;  
  201. END;  
  202. /  

Oracle&nbsp;牛鹏社    Oracle DBsupport

更多参考

使用 DBMS_PROFILER 定位 PL/SQL 瓶颈代码

使用PL/SQL Developer剖析PL/SQL代码

对比 PL/SQL profiler 剖析结果

PL/SQL Profiler 剖析报告生成html

DML Error Logging 特性 

PL/SQL --> 游标

PL/SQL --> 隐式游标(SQL%FOUND)

批量SQL之 FORALL 语句

批量SQL之 BULK COLLECT 子句

PL/SQL 集合的初始化与赋值

PL/SQL 联合数组与嵌套表 
PL/SQL 变长数组
PL/SQL --> PL/SQL记录

SQL tuning 步骤

高效SQL语句必杀技

父游标、子游标及共享游标

绑定变量及其优缺点

dbms_xplan之display_cursor函数的使用

dbms_xplan之display函数的使用

执行计划中各字段各模块描述

使用 EXPLAIN PLAN 获取SQL语句执行计划

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值