PL/SQL 下邮件发送程序

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

 

1、调用SENDMAIL_PKG来发送邮件

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

PL/SQL procedure successfully completed.


2、邮件发送结果

    

3、原代码

--specification section
CREATE OR REPLACE PACKAGE "SENDMAIL_PKG"
IS
   PROCEDURE sendmail (p_receiver       VARCHAR2,
                       p_sub            VARCHAR2,
                       p_txt            VARCHAR2,
                       err_num      OUT NUMBER,
                       err_msg      OUT VARCHAR2);
END;
/

--body section
CREATE OR REPLACE PACKAGE BODY "SENDMAIL_PKG"
IS
   PROCEDURE sendmail (p_receiver       VARCHAR2,
                       p_sub            VARCHAR2,
                       p_txt            VARCHAR2,
                       err_num      OUT NUMBER,
                       err_msg      OUT VARCHAR2)
   IS
      /*   p_receiver   =>  receiver
             p_sub              =>  mail subject
             p_txt                => mail content
      */
      p_user                         VARCHAR2 (30) := NULL;
      p_pass                         VARCHAR2 (30) := NULL;
      p_sendor                       VARCHAR2 (40) := 'DBA@gotrade.com';
      p_server                       VARCHAR2 (20)
                           --             := system_pkg.get_sys_para_value ('TC_SMTP_IP'); --'192.168.7.65';
                                        :='192.168.7.65';
      p_port                         NUMBER := 25;
      p_need_smtp                    NUMBER := 0;
      p_subject                      VARCHAR2 (4000);
      l_crlf                         VARCHAR2 (2) := UTL_TCP.crlf;
      l_sendoraddress                VARCHAR2 (4000);
      l_splite                       VARCHAR2 (10) := '++';
      boundary              CONSTANT VARCHAR2 (256) := '-----BYSUK';
      first_boundary        CONSTANT VARCHAR2 (256) := '--' || boundary || l_crlf;
      last_boundary         CONSTANT VARCHAR2 (256)
                                        := '--' || boundary || '--' || l_crlf ;
      multipart_mime_type   CONSTANT VARCHAR2 (256)
         := 'multipart/mixed; boundary="' || boundary || '"' ;

      TYPE address_list IS TABLE OF VARCHAR2 (100)
                              INDEX BY BINARY_INTEGER;

      my_address_list                address_list;

      ---------------------------------------split mail address----------------------------------------------
      PROCEDURE p_splite_str (p_str VARCHAR2, p_splite_flag INT DEFAULT 1)
      IS
         l_addr   VARCHAR2 (254) := '';
         l_len    INT;
         l_str    VARCHAR2 (4000);
         j        INT := 0;
      BEGIN
         /*Handle recieve mail address, such like blank, semicolon*/
         l_str :=
            TRIM (RTRIM (REPLACE (REPLACE (p_str, ';', ','), ' ', ''), ','));
         l_len := LENGTH (l_str);

         FOR i IN 1 .. l_len
         LOOP
            IF SUBSTR (l_str, i, 1) <> ','
            THEN
               l_addr := l_addr || SUBSTR (l_str, i, 1);
            ELSE
               j := j + 1;

               IF p_splite_flag = 1
               THEN
                  --Add  symbol  '<>'  for each mail address. else could not send to many reciever
                  l_addr := '<' || l_addr || '>';

                  my_address_list (j) := l_addr;
               END IF;

               l_addr := '';
            END IF;

            IF i = l_len
            THEN
               j := j + 1;

               IF p_splite_flag = 1
               THEN
                  l_addr := '<' || l_addr || '>';
                  my_address_list (j) := l_addr;
               END IF;
            END IF;
         END LOOP;
      END;

      -----------------------------------write mail header and mail content----------------------------------
      PROCEDURE write_data (p_conn     IN OUT NOCOPY UTL_SMTP.connection,
                            p_name     IN            VARCHAR2,
                            p_value    IN            VARCHAR2,
                            p_splite                 VARCHAR2 DEFAULT ':',
                            p_crlf                   VARCHAR2 DEFAULT l_crlf)
      IS
      BEGIN
         /* utl_raw.cast_to_raw  to handle chinese code*/
         UTL_SMTP.write_raw_data (
            p_conn,
            UTL_RAW.cast_to_raw (
               CONVERT (p_name || p_splite || p_value || p_crlf,
                        'ZHS16CGB231280')));
      END;

      ----------------------------------------write mime mail tail-----------------------------------------------------
      PROCEDURE end_boundary (conn   IN OUT NOCOPY UTL_SMTP.connection,
                              LAST   IN            BOOLEAN DEFAULT FALSE)
      IS
      BEGIN
         UTL_SMTP.write_data (conn, UTL_TCP.crlf);

         IF (LAST)
         THEN
            UTL_SMTP.write_data (conn, last_boundary);
         END IF;
      END;

      ---------------------------------------------send mail procedure--------------------------------------------
      PROCEDURE p_email (p_sendoraddress2      VARCHAR2,      --sender address
                         p_receiveraddress2    VARCHAR2)    --reciever address
      IS
         l_conn   UTL_SMTP.connection;                   --create a connection
      BEGIN
         /*Initial mail server*/
         l_conn := UTL_SMTP.open_connection (p_server, p_port);
         UTL_SMTP.helo (l_conn, p_server);

         /* smtp authentication*/
         IF p_need_smtp = 1
         THEN
            UTL_SMTP.command (l_conn, 'AUTH LOGIN', '');
            UTL_SMTP.command (
               l_conn,
               UTL_RAW.cast_to_varchar2 (
                  UTL_ENCODE.base64_encode (UTL_RAW.cast_to_raw (p_user))));
            UTL_SMTP.command (
               l_conn,
               UTL_RAW.cast_to_varchar2 (
                  UTL_ENCODE.base64_encode (UTL_RAW.cast_to_raw (p_pass))));
         END IF;

         /*configure sender and reciever mail address*/
         UTL_SMTP.mail (l_conn, p_sendoraddress2);
         UTL_SMTP.rcpt (l_conn, p_receiveraddress2);
         /*configure mail header*/
         UTL_SMTP.open_data (l_conn);
         /*configure date*/
         --write_data(l_conn, 'Date', to_char(sysdate-1/3, 'dd Mon yy hh24:mi:ss'));
         /*configure sender*/
         write_data (l_conn, 'From', p_sendor);
         /*configure reciever*/
         write_data (l_conn, 'To', p_receiver);

         /*add mail subject*/
         SELECT REPLACE (
                   '=?GB2312?B?'
                   || UTL_RAW.cast_to_varchar2 (
                         UTL_ENCODE.base64_encode (RAWTOHEX (p_sub)))
                   || '?=',
                   UTL_TCP.crlf,
                   '')
           INTO p_subject
           FROM DUAL;

         write_data (l_conn, 'Subject', p_subject);
         write_data (l_conn, 'Content-Type', multipart_mime_type);
         UTL_SMTP.write_data (l_conn, UTL_TCP.crlf);
         UTL_SMTP.write_data (l_conn, first_boundary);
         write_data (l_conn, 'Content-Type', 'text/html');

         UTL_SMTP.write_data (l_conn, UTL_TCP.crlf);

         write_data (
            l_conn,
            '',
            REPLACE (REPLACE (p_txt, l_splite, CHR (10)), CHR (10), l_crlf),
            '',
            '');
         end_boundary (l_conn);
         /*close write data*/
         UTL_SMTP.close_data (l_conn);
         /*close connection*/
         UTL_SMTP.quit (l_conn);
      END;
   ---------------------------------------------main procedure -----------------------------------------------------
   BEGIN
      err_num := 0;
      l_sendoraddress := '<' || p_sendor || '>';
      p_splite_str (p_receiver);                         --handle mail address

      FOR k IN 1 .. my_address_list.COUNT
      LOOP
         p_email (l_sendoraddress, my_address_list (k));
      END LOOP;
   END;
END;
/

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语句执行计划

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Oracle P/L SQL实现发送Email、浏览网页等网络操作功能 Oracle P/L SQL实现发送Email、浏览网页等网络操作功能,以下是此过程包的头部,包体经常打包处理plb,感兴趣用户可以下载下来。 --.使用聚合函数实现 多行合并 Drop Type Strcat_type; Drop Function f_StrCat; Drop Package UTL_INet; Variable ls_ObjectName VarChar2(128); Begin Select Sequence_Name Into :ls_ObjectName From User_Sequences Where Sequence_Name = 'SYS_RAND_ID'; DBMS_Output.Put_Line( :ls_ObjectName ); Exception When No_Data_Found Then Execute Immediate 'Create Sequence SYS_RAND_ID minvalue 1 maxValue 99999999999999999 Start With 1 increment by 1 cache 5 cycle order'; End; / --1、创建类型 Create Or Replace Type Strcat_type As Object ( cat_string varchar2(4000), Static Function ODCIAggregateInitialize(cs_ctx In Out strcat_type) Return Number, Member Function ODCIAggregateIterate(self In Out strcat_type,value in varchar2) Return Number, Member Function ODCIAggregateMerge(self In Out strcat_type,ctx2 In Out strcat_type) Return Number, Member Function ODCIAggregateTerminate(self In Out strcat_type,ReturnValue Out varchar2,flags in Number) Return Number ); / --2. 创建类型体 Create Or Replace Type Body Strcat_type Is Static Function ODCIAggregateInitialize( cs_ctx In Out strcat_type )Return Number is Begin cs_ctx := strcat_type( Null ); Return ODCIConst.Success; End; Member Function ODCIAggregateIterate( self In Out strcat_type, value In varchar2 ) Return Number is Begin if self.cat_string is Null or Instr( self.cat_string, value ) = 0 Then self.cat_string := self.cat_string || ','|| value; End if; Return ODCIConst.Success; End; Member Function ODCIAggregateTerminate( self In Out strcat_type, ReturnValue Out varchar2, flags In Number) Return Number is Begin ReturnValue := ltrim(rtrim( self.cat_string,','),',' ); Return ODCIConst.Success; End; Member Function ODCIAggregateMerge( self In Out strcat_type, ctx2 In Out strcat_type) Return Number is Begin if self.cat_string is Null or Instr( self.cat_string, ctx2.cat_string ) = 0 Then self.cat_string := self.cat_string || ',' || ctx2.cat_string; End if; Return ODCIConst.Success; End; End; / --3.创建函数: 使用聚合函数实现 多行合并 Create or Replace Function f_StrCat( as_input Varchar2 ) Return Varchar2 PARALLEL_ENABLE AGGREGATE USING strcat_type; / Grant Execute on f_StrCat To Public; --End of 使用聚合函数实现 多行合并 Create Or Replace Package UTL_INet AS Type VarChar_Type is Table of VarChar2(400) Index By Binary_Integer; Type Number_Type is Table of Number(12,4) Index By Binary_Integer; Type DynamicCursor is ref Cursor; --动态游标 --Purpose : 获得汉字拼音编码 Type ut_PYIndex_191_List is Varray( 191 ) OF Number; Type ut_PYIndex_List is Varray( 10 ) OF ut_PYIndex_191_List; is_OracleDirectory Constant VarChar2(20) := 'ATTACH_DIR'; --内部附件生成目录(Oracle的目录) --Clob叠加比较慢,先用VarChar2叠加到4000个字符后才叠加到Clob字段 --UTL_INet.p_ClobCAT( Procedure p_ClobCAT( ac_HTMLText in Out Clob, as_CatText in Out VarChar2, as_Str in VarChar2 Default Null ); --字符串根据特定分隔符分来 --Select UTL_INet.f_SplitString( 'A,B,C', xx, ',' ) From dual; Function f_SplitString( as_SourStr in out Clob, --输入字符串A,B,C as_Separator in VarChar2 Default '/' --分拆依据的分隔符, )Return VarChar2; --分拆结果A --将Clob内容写入物理文件 --Exec UTL_INet.p_PutClob2File( as_FileName => 'aa.sql', ac_Text => 'test sql' ); Procedure p_PutClob2File( as_SubDir in VarChar2, --目录名 as_FileName in VarChar2, --文件名 ac_Text in Clob, --文件内容 as_Overwrite in VarChar default 'Y', --标志位:Y:覆盖文件内容,N:追加 as_OraVersion in VarChar default 'N' --标志位:Y:写入Oracle版本信息 ); --序号自动递增计算 --e.g.: 输入:HLXU99349021,返回:HLXU99349022 --范例: Select UTL_INet.f_AutoNum( 'HLXU99349021' ), UTL_INet.f_AutoNum( 'ABA', -1 ), UTL_INet.f_AutoNum( 'ABZ' ) from Dual; Function f_AutoNum( as_OldNum in VarChar2, --原字符串 ai_Step in Number Default 1, --步长,默认是递增加1, ai_DigitXXX in Number Default Null --累计序号位数 XXX )Return VarChar2; --字符串加解密,返回一串32位长的字符串 --Select UTL_INet.f_MD5( 'TestPassword' ) From Dual; Function f_MD5( as_SourceStr in Varchar2 --需要加密的字符串 ) Return Varchar2; --将Email地址去头去尾,剩下最简单的Email地址,如"TSI Customer Service" <cs@csdn.com>变成cs@csdn.com Function f_GetNakedEmailAddr( as_DisplayEmail In VarChar2, as_Including in Char Default 'N' --Y: 返回<cs@csdn.com> )Return VarChar2; --测试发送Email的邮箱是否正确 Function f_TestEmailAccount( ac_Connection out Nocopy UTL_SMTP.Connection, as_SMTPHost in VarChar2, --邮件服务器 mail.csdn.com ai_SMTPPort in PLS_Integer Default 25, --邮件服务器端口 as_SMTPAuth in VarChar2 Default 'Y', --发送密码验证 as_Username in VarChar2 Default Null, --邮件用户 as_Password in VarChar2 Default Null, --邮件口令 as_WalletPath in VarChar2 Default Null, as_WalletPwd in VarChar2 Default Null )Return Boolean; ------------------------------------------------ 写邮件头和邮件内容------------------------- Procedure p_WriteRawData( ac_Conn in Out Nocopy UTL_SMTP.Connection, as_Partname in VarChar2, as_Value in VarChar2, as_Splite in VarChar2 Default ':', as_CRLF in VarChar2 Default UTL_TCP.CRLF ); ----------------------------------------------发送附件------------------------------------- Procedure p_MailAttachment( ac_Conn in Out Nocopy UTL_SMTP.Connection, as_Filename in VarChar2, as_Boundary in VarChar2, as_Encode in VarChar2 Default 'base64', as_MimeType in VarChar2 Default 'text/plain', as_ContentID in VarChar2 Default Null, -- ab_Inline in Boolean Default False --True将文本内容直接在邮件内容显示出来,并出现在附件中,False不显示只出现在附件中 ); -----------------自动签名的生成,签名生成显示后还出现此签名文件为附件,尚未解决------------------------------- Procedure p_GetMailSignature( ac_Conn in Out Nocopy UTL_SMTP.Connection, as_Boundary in VarChar2, as_Encode in VarChar2 Default 'base64', as_SignatureLogo in VarChar2 Default Null, as_SignatureText in VarChar2 Default Null ); --发送Email前必须将ewallet.p12拷贝到C:\OracleAttachDir目录 --发送电子邮件 --Exec UTL_INet.p_SendEmail( 'csdn@gmail.com', 'Test 主题Subject', 'Mail body(邮件内容)' ); Procedure p_SendEmail( as_Sender in VarChar2, as_Recipient in VarChar2, as_CC in VarChar2 Default Null, as_BCC in VarChar2 Default Null, as_Subject in VarChar2, ac_Message in Clob, as_AttachLists in VarChar2 Default Null, --多个用逗号,分开 as_SMTPHost in VarChar2, --邮件服务器 ai_SMTPPort in PLS_Integer Default 25, --邮件服务器端口 as_SMTPAuth in VarChar2 Default 'Y', --发送密码验证 as_WalletPath in VarChar2 Default Null, as_WalletPwd in VarChar2 Default Null, as_Username in VarChar2 Default Null, as_Password in VarChar2 Default Null, as_RunResult out VarChar2, --返回信息,OK成功,其他返回错误 as_SignatureLogo in VarChar2 Default Null, as_SignatureText in VarChar2 Default Null, as_Encode in VarChar2 Default 'base64', ai_Priority In Pls_Integer Default Null ); Function f_LoadHTMLFromURL( as_URL in VarChar2, as_CharSet in VarChar2 Default 'UTF-8' )Return Clob; --生成HTML报表表头 --Exec f_HTMLTableHead( 'Tab1', '20:Table Name;20:Records' ); Function f_HTMLTableHead( as_TableID in VarChar2, --表ID as_WidthColumns in VarChar2, --表头内容,用分号;隔开,宽度与标题用冒号:隔开 as_BgColor in VarChar2 Default 'CCCCCC' --标题背景色 )Return VarChar2; --生成HTML报表主体内容 --Exec UTL_INet.f_HTMLTableBody( '' ); Function f_HTMLTableBody( as_BodyText in VarChar2, --主体内容,多个用分号;隔开 as_Align in VarChar2 Default Null --格式(居中,靠左,靠右) )Return VarChar2; --获取汉字拼音字母表 --Select UTL_INet.f_getChineseSpell( '获取汉字拼音' ) from dual; Function f_getChineseSpell( as_CNStr in VarChar2, --中文 as_First in VarChar2 Default Null --空返回完整拼音,其他返回拼音首字母 )Return VarChar2; --二进制转换成十进制函数 --Select UTL_INet.f_Bin2Dec( '10111011' ) From dual; Function f_Bin2Dec( as_Bin in VarChar2 )Return Number; --十进制转换成二进制函数 --Select UTL_INet.f_Dec2Bin( 187 ) From dual; Function f_Dec2Bin( an_Dec in Number )Return VarChar2; --十进制转换成三十二进制函数 --Select UTL_INet.f_Dec2Hex( 187 ) From dual; Function f_Dec2Hex( an_Dec in Number )Return VarChar2; --三十二进制转换成十进制函数 --Select UTL_INet.f_Hex2Dec( '5R' ) From dual; Function f_Hex2Dec( as_Hex in VarChar2 )Return Number; --生成12位随机数 --Select UTL_INet.f_Rand() From dual; Function f_Rand( as_PreFix in VarChar2 Default '00', --未满个数字符补充串 an_Nums in Number Default 12 )Return VarChar2; --繁体字转化成简体字(传入的汉字,若有繁体自动转化为简体) Function f_ft2jt( as_Text in VarChar2 --传入的汉字 )Return VarChar2; --简体字转化成繁体字(传入的汉字,若有简体自动转化为繁体) Function f_jt2ft( as_Text in VarChar2 --传入的汉字 )Return VarChar2; -- -------------------------------------------------------------------------- -- Description : SOAP related Functions for consuming web services. Type t_Request is Record ( Method VarChar2(256), Namespace VarChar2(256), Body VarChar2(32767), EnvelopeTag VarChar2(30) ); Type t_Response is Record ( Doc XMLType, EnvelopeTag VarChar2(30) ); Function f_NewRequest( as_Method in VarChar2, as_Namespace in VarChar2, as_EnvelopeTag in VarChar2 Default 'SOAP-ENV' )Return t_Request; Procedure p_AddParameter( as_Request in out Nocopy t_Request, as_Name in VarChar2, as_Type in VarChar2, as_Value in VarChar2 ); Function f_Invoke( as_Request in out Nocopy t_Request, as_URL in VarChar2, as_Action in VarChar2 )Return t_Response; Function f_GetReturnValue( as_Response in out Nocopy t_Response, as_Name in VarChar2, as_Namespace in VarChar2 )Return VarChar2; --列出当前目录下所有文件清单,可以指定扩展名,是否包含子目录,返回的文件名用|分割开来 Function f_ListDirectory( as_SubDir in VarChar2, as_Ext in VarChar2 Default Null, as_IncludingSubDir in Char Default 'N' )Return Clob; --将数值翻译成中文大写、英文大写 --Select f_Digit2Char( 24822.80, 'EN_Amount' ) From dual; Function f_Digit2Char( an_Amount in Number, --要被翻译的数值 as_Option in VarChar2 --翻译选择项 )Return VarChar2; --发送短信 Function f_SendSMS( as_MobilePhone in VarChar2, --手机号码 as_SMSText in VarChar2, --短信内容 as_SMSURL in VarChar2, as_SMSUserID in VarChar2, as_SMSPasswd in VarChar2 )Return VarChar2; --删除某个指定文件 Procedure p_RemoveFile( as_SubDir in VarChar2, --路径 as_FileName in VarChar2 --多个用逗号,分开 ); --从文件中读内容 Function f_GetTextFromFile( as_SubDir in VarChar2, --目录名 as_FileName in VarChar2, --文件名 as_NewLine in VarChar2 Default UTL_TCP.CRLF --换行符 )Return Clob; END UTL_INet; /
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值