zoukankan      html  css  js  c++  java
  • Oracle邮件推送函数

      1 CREATE OR REPLACE PROCEDURE PROCSENDEMAIL (
      2     P_TXT VARCHAR2,
      3     P_SUB VARCHAR2,
      4     P_SENDOR VARCHAR2,
      5     P_RECEIVER VARCHAR2,
      6     P_SERVER VARCHAR2,
      7     P_PORT NUMBER DEFAULT 25 ,
      8     P_NEED_SMTP INT DEFAULT 0 ,
      9     P_USER VARCHAR2 DEFAULT NULL ,
     10     P_PASS VARCHAR2 DEFAULT NULL ,
     11     P_FILENAME VARCHAR2 DEFAULT NULL ,
     12     P_ENCODE VARCHAR2 DEFAULT 'bit 7'
     13     )
     14     AUTHID CURRENT_USER
     15     IS
     16     /*
     17     作用:用oracle发送邮件
     18     主要功能:1、支持多收件人。
     19     2、支持中文
     20     3、支持抄送人
     21     4、支持大于32K的附件
     22     5、支持多行正文
     23     6、支持多附件
     24     7、支持文本附件和二进制附件
     25     8、支持HTML格式
     26     8、支持
     27     作者:suk
     28     参数说明:
     29     p_txt :邮件正文
     30     p_sub: 邮件标题
     31     p_SendorAddress : 发送人邮件地址
     32     p_ReceiverAddress : 接收地址,可以同时发送到多个地址上,地址之间用","或者";"隔开
     33     p_EmailServer : 邮件服务器地址,可以是域名或者IP
     34     p_Port :邮件服务器端口
     35     p_need_smtp:是否需要smtp认证,0表示不需要,1表示需要
     36     p_user:smtp验证需要的用户名
     37     p_pass:smtp验证需要的密码
     38     p_filename:附件名称,必须包含完整的路径,如"d:	empa.txt"。
     39     可以有多个附件,附件名称只见用逗号或者分号分隔
     40     p_encode:附件编码转换格式,其中 p_encode='bit 7' 表示文本类型附件
     41     p_encode='base64' 表示二进制类型附件
     42     注意:
     43     1、对于文本类型的附件,不能用base64的方式发送,否则出错
     44     2、对于多个附件只能用同一种格式发送
     45     测试
     46     PROCSENDEMAIL('中文测试邮件','中文主题','xiaoxiaolin_jack@163.com','258202898@qq.com,jack@adm-soft.com','smtp.163.com',25,1,'xiaoxiaolin_jack@163.com','xxl121','d:	est.txt','bit 7');
     47     PROCSENDEMAIL('中文测试邮件','中文主题','xiaoxiaolin_jack@163.com','258202898@qq.com,jack@adm-soft.com','smtp.163.com',25,1,'xiaoxiaolin_jack@163.com','xxl121','d:pic.jpg,d:	est.txt','base64');
     48     PROCSENDEMAIL('中文测试邮件','中文主题','xiaoxiaolin_jack@163.com','258202898@qq.com,jack@adm-soft.com','smtp.163.com',25,1,'xiaoxiaolin_jack@163.com','xxl121','d:unload.txt,d:pic.jpg,d:unload.xls','base64');
     49     --使用‘bit 7’能够正常执行
     50     */
     51     L_CRLF VARCHAR2 (2) := UTL_TCP.CRLF;
     52     L_SENDORADDRESS VARCHAR2 (4000);
     53     L_SPLITE VARCHAR2 (10) := '++';
     54     BOUNDARY CONSTANT VARCHAR2 (256) := '-----BYSUK';
     55     FIRST_BOUNDARY CONSTANT VARCHAR2 (256) := '--' || BOUNDARY || L_CRLF;
     56     LAST_BOUNDARY CONSTANT VARCHAR2 (256)
     57     := '--' || BOUNDARY || '--' || L_CRLF ;
     58     MULTIPART_MIME_TYPE CONSTANT VARCHAR2 (256)
     59     := 'multipart/mixed; boundary="' || BOUNDARY || '"' ;
     60     /* 以下部分是发送大二进制附件时用到的变量 */
     61     L_FIL BFILE;
     62     L_FILE_LEN NUMBER;
     63     L_MODULO NUMBER;
     64     L_PIECES NUMBER;
     65     L_FILE_HANDLE UTL_FILE.FILE_TYPE;
     66     L_AMT BINARY_INTEGER := 672 * 3; /* ensures proper format; 2016 */
     67     L_FILEPOS PLS_INTEGER := 1; /* pointer for the file */
     68     L_CHUNKS NUMBER;
     69     L_BUF RAW (2100);
     70     L_DATA RAW (2100);
     71     L_MAX_LINE_WIDTH NUMBER := 54;
     72     L_DIRECTORY_BASE_NAME VARCHAR2 (100) := 'DIR_FOR_SEND_MAIL';
     73     L_LINE VARCHAR2 (1000);
     74     L_MESG VARCHAR2 (32767);
     75     /* 以上部分是发送大二进制附件时用到的变量 */
     76     TYPE ADDRESS_LIST
     77     IS
     78     TABLE OF VARCHAR2 (100)
     79     INDEX BY BINARY_INTEGER;
     80     MY_ADDRESS_LIST ADDRESS_LIST;
     81     TYPE ACCT_LIST
     82     IS
     83     TABLE OF VARCHAR2 (100)
     84     INDEX BY BINARY_INTEGER;
     85     MY_ACCT_LIST ACCT_LIST;
     86      -------------------------------------返回附件源文件所在目录或者名称-----------------------
     87     FUNCTION GET_FILE (P_FILE VARCHAR2, P_GET INT)
     88     RETURN VARCHAR2
     89     IS
     90     --p_get=1 表示返回目录
     91     --p_get=2 表示返回文件名
     92     L_FILE VARCHAR2 (1000);
     93     BEGIN
     94     IF INSTR (P_FILE, '') > 0
     95     THEN
     96     --windows
     97     IF P_GET = 1
     98     THEN
     99     L_FILE := SUBSTR (P_FILE, 1, INSTR (P_FILE, '', -1) - 1);
    100     ELSIF P_GET = 2
    101     THEN
    102     L_FILE :=
    103     SUBSTR (P_FILE, - (LENGTH (P_FILE) - INSTR (P_FILE, '', -1)));
    104     END IF;
    105     ELSIF INSTR (P_FILE, '/') > 0
    106     THEN
    107     --linux/unix
    108     IF P_GET = 1
    109     THEN
    110     L_FILE := SUBSTR (P_FILE, 1, INSTR (P_FILE, '/', -1) - 1);
    111     ELSIF P_GET = 2
    112     THEN
    113     L_FILE :=
    114     SUBSTR (P_FILE, - (LENGTH (P_FILE) - INSTR (P_FILE, '/', -1)));
    115     END IF;
    116     END IF;
    117     RETURN L_FILE;
    118     END;
    119     ---------------------------------------------删除directory------------------------------------
    120     PROCEDURE DROP_DIRECTORY (P_DIRECTORY_NAME VARCHAR2)
    121     IS
    122     BEGIN
    123     EXECUTE IMMEDIATE 'drop directory ' || P_DIRECTORY_NAME;
    124     EXCEPTION
    125     WHEN OTHERS
    126     THEN
    127     NULL;
    128     END;
    129     --------------------------------------------------创建directory-----------------------------------------
    130     PROCEDURE CREATE_DIRECTORY (P_DIRECTORY_NAME VARCHAR2, P_DIR VARCHAR2)
    131     IS
    132     BEGIN
    133     EXECUTE IMMEDIATE 'create directory '
    134     || P_DIRECTORY_NAME
    135     || ' as '''
    136     || P_DIR
    137     || '''';
    138     EXECUTE IMMEDIATE 'grant read,write on directory '
    139     || P_DIRECTORY_NAME
    140     || ' to public';
    141     EXCEPTION
    142     WHEN OTHERS
    143     THEN
    144     RAISE;
    145     END;
    146     --------------------------------------------分割邮件地址或者附件地址--------------------
    147     PROCEDURE P_SPLITE_STR (P_STR VARCHAR2, P_SPLITE_FLAG INT DEFAULT 1 )
    148     IS
    149     L_ADDR VARCHAR2 (254) := '';
    150     L_LEN INT;
    151     L_STR VARCHAR2 (4000);
    152     J INT := 0; --表示邮件地址或者附件的个数
    153     BEGIN
    154     /*处理接收邮件地址列表,包括去空格、将;转换为,等*/
    155     L_STR :=
    156     TRIM (RTRIM (REPLACE (REPLACE (P_STR, ';', ','), ' ', ''), ','));
    157     L_LEN := LENGTH (L_STR);
    158     FOR I IN 1 .. L_LEN
    159     LOOP
    160     IF SUBSTR (L_STR, I, 1) <> ','
    161     THEN
    162     L_ADDR := L_ADDR || SUBSTR (L_STR, I, 1);
    163     ELSE
    164     J := J + 1;
    165     IF P_SPLITE_FLAG = 1
    166     THEN --表示处理邮件地址
    167     --前后需要加上'<>',否则很多邮箱将不能发送邮件
    168     L_ADDR := '<' || L_ADDR || '>';
    169     --调用邮件发送过程
    170     MY_ADDRESS_LIST (J) := L_ADDR;
    171     ELSIF P_SPLITE_FLAG = 2
    172     THEN --表示处理附件名称
    173     MY_ACCT_LIST (J) := L_ADDR;
    174     END IF;
    175     L_ADDR := '';
    176     END IF;
    177     IF I = L_LEN
    178     THEN
    179     J := J + 1;
    180     IF P_SPLITE_FLAG = 1
    181     THEN
    182     --调用邮件发送过程
    183     L_ADDR := '<' || L_ADDR || '>';
    184     MY_ADDRESS_LIST (J) := L_ADDR;
    185     ELSIF P_SPLITE_FLAG = 2
    186     THEN
    187     MY_ACCT_LIST (J) := L_ADDR;
    188     END IF;
    189     END IF;
    190     END LOOP;
    191     END;
    192     ------------------------------------------------写邮件头和邮件内容------------------------------------------
    193     PROCEDURE WRITE_DATA (P_CONN IN OUT NOCOPY UTL_SMTP.CONNECTION,
    194     P_NAME IN VARCHAR2,
    195     P_VALUE IN VARCHAR2,
    196     P_SPLITE VARCHAR2 DEFAULT ':' ,
    197     P_CRLF VARCHAR2 DEFAULT L_CRLF )
    198     IS
    199     BEGIN
    200     /* utl_raw.cast_to_raw 对解决中文乱码问题很重要*/
    201     UTL_SMTP.WRITE_RAW_DATA (
    202     P_CONN,
    203     UTL_RAW.CAST_TO_RAW (
    204     CONVERT (P_NAME || P_SPLITE || P_VALUE || P_CRLF, 'ZHS16GBK')
    205     )
    206     );
    207     END;
    208     ----------------------------------------写MIME邮件尾部-----------------------------------------------------
    209     PROCEDURE END_BOUNDARY (CONN IN OUT NOCOPY UTL_SMTP.CONNECTION,
    210     LAST IN BOOLEAN DEFAULT FALSE )
    211     IS
    212     BEGIN
    213     UTL_SMTP.WRITE_DATA (CONN, UTL_TCP.CRLF);
    214     IF (LAST)
    215     THEN
    216     UTL_SMTP.WRITE_DATA (CONN, LAST_BOUNDARY);
    217     END IF;
    218     END;
    219     ----------------------------------------------发送附件----------------------------------------------------
    220     PROCEDURE ATTACHMENT (
    221     CONN IN OUT NOCOPY UTL_SMTP.CONNECTION,
    222     MIME_TYPE IN VARCHAR2 DEFAULT 'text/plain' ,
    223     INLINE IN BOOLEAN DEFAULT TRUE ,
    224     FILENAME IN VARCHAR2 DEFAULT 't.txt' ,
    225     TRANSFER_ENC IN VARCHAR2 DEFAULT '7 bit' ,
    226     DT_NAME IN VARCHAR2 DEFAULT '0'
    227     )
    228     IS
    229     L_FILENAME VARCHAR2 (1000);
    230     BEGIN
    231     --写附件头
    232     UTL_SMTP.WRITE_DATA (CONN, FIRST_BOUNDARY);
    233     --设置附件格式
    234     WRITE_DATA (CONN, 'Content-Type', MIME_TYPE);
    235     --如果文件名称非空,表示有附件
    236     DROP_DIRECTORY (DT_NAME);
    237     --创建directory
    238     CREATE_DIRECTORY (DT_NAME, GET_FILE (FILENAME, 1));
    239     --得到附件文件名称
    240     L_FILENAME := GET_FILE (FILENAME, 2);
    241     IF (INLINE)
    242     THEN
    243     WRITE_DATA (CONN,
    244     'Content-Disposition',
    245     'inline; filename="' || L_FILENAME || '"');
    246     ELSE
    247     WRITE_DATA (CONN,
    248     'Content-Disposition',
    249     'attachment; filename="' || L_FILENAME || '"');
    250     END IF;
    251     --设置附件的转换格式
    252     IF (TRANSFER_ENC IS NOT NULL)
    253     THEN
    254     WRITE_DATA (CONN, 'Content-Transfer-Encoding', TRANSFER_ENC);
    255     END IF;
    256     UTL_SMTP.WRITE_DATA (CONN, UTL_TCP.CRLF);
    257     --begin 贴附件内容
    258     IF TRANSFER_ENC = 'bit 7'
    259     THEN
    260     --如果是文本类型的附件
    261     BEGIN
    262     L_FILE_HANDLE := UTL_FILE.FOPEN (DT_NAME, L_FILENAME, 'r'); --打开文件
    263     --把附件分成多份,这样可以发送超过32K的附件
    264     LOOP
    265     UTL_FILE.GET_LINE (L_FILE_HANDLE, L_LINE);
    266     L_MESG := L_LINE || L_CRLF;
    267     WRITE_DATA (CONN,
    268     '',
    269     L_MESG,
    270     '',
    271     '');
    272     END LOOP;
    273     UTL_FILE.FCLOSE (L_FILE_HANDLE);
    274     END_BOUNDARY (CONN);
    275     EXCEPTION
    276     WHEN OTHERS
    277     THEN
    278     UTL_FILE.FCLOSE (L_FILE_HANDLE);
    279     END_BOUNDARY (CONN);
    280     NULL;
    281     END; --结束文本类型附件的处理
    282     ELSIF TRANSFER_ENC = 'base64'
    283     THEN
    284     --如果是二进制类型的附件
    285     BEGIN
    286     --把附件分成多份,这样可以发送超过32K的附件
    287     L_FILEPOS := 1; --重置offset,在发送多个附件时,必须重置
    288     L_FIL := BFILENAME (DT_NAME, L_FILENAME);
    289     L_FILE_LEN := DBMS_LOB.GETLENGTH (L_FIL);
    290     L_MODULO := MOD (L_FILE_LEN, L_AMT);
    291     L_PIECES := TRUNC (L_FILE_LEN / L_AMT);
    292     IF (L_MODULO <> 0)
    293     THEN
    294     L_PIECES := L_PIECES + 1;
    295     END IF;
    296     DBMS_LOB.FILEOPEN (L_FIL, DBMS_LOB.FILE_READONLY);
    297     DBMS_LOB.READ (L_FIL,
    298     L_AMT,
    299     L_FILEPOS,
    300     L_BUF);
    301     L_DATA := NULL;
    302     FOR I IN 1 .. L_PIECES
    303     LOOP
    304     L_FILEPOS := I * L_AMT + 1;
    305     L_FILE_LEN := L_FILE_LEN - L_AMT;
    306     L_DATA := UTL_RAW.CONCAT (L_DATA, L_BUF);
    307     L_CHUNKS := TRUNC (UTL_RAW.LENGTH (L_DATA) / L_MAX_LINE_WIDTH);
    308     IF (I <> L_PIECES)
    309     THEN
    310     L_CHUNKS := L_CHUNKS - 1;
    311     END IF;
    312     UTL_SMTP.WRITE_RAW_DATA (CONN,
    313     UTL_ENCODE.BASE64_ENCODE (L_DATA));
    314     L_DATA := NULL;
    315     IF (L_FILE_LEN < L_AMT AND L_FILE_LEN > 0)
    316     THEN
    317     L_AMT := L_FILE_LEN;
    318     END IF;
    319     DBMS_LOB.READ (L_FIL,
    320     L_AMT,
    321     L_FILEPOS,
    322     L_BUF);
    323     END LOOP;
    324     DBMS_LOB.FILECLOSE (L_FIL);
    325     END_BOUNDARY (CONN);
    326     EXCEPTION
    327     WHEN OTHERS
    328     THEN
    329     DBMS_LOB.FILECLOSE (L_FIL);
    330     END_BOUNDARY (CONN);
    331     RAISE;
    332     END; --结束处理二进制附件
    333     END IF; --结束处理附件内容
    334     DROP_DIRECTORY (DT_NAME);
    335     END; --结束过程ATTACHMENT
    336     ---------------------------------------------真正发送邮件的过程--------------------------------------------
    337     PROCEDURE P_EMAIL (P_SENDORADDRESS2 VARCHAR2, --发送地址
    338     P_RECEIVERADDRESS2 VARCHAR2) --接受地址
    339     IS
    340     L_CONN UTL_SMTP.CONNECTION; --定义连接
    341     BEGIN
    342     /*初始化邮件服务器信息,连接邮件服务器*/
    343     L_CONN := UTL_SMTP.OPEN_CONNECTION (P_SERVER, P_PORT);
    344     UTL_SMTP.HELO (L_CONN, P_SERVER);
    345     /* smtp服务器登录校验 */
    346     IF P_NEED_SMTP = 1
    347     THEN
    348     UTL_SMTP.COMMAND (L_CONN, 'AUTH LOGIN', '');
    349     UTL_SMTP.COMMAND (
    350     L_CONN,
    351     UTL_RAW.CAST_TO_VARCHAR2 (
    352     UTL_ENCODE.BASE64_ENCODE (UTL_RAW.CAST_TO_RAW (P_USER))
    353     )
    354     );
    355     UTL_SMTP.COMMAND (
    356     L_CONN,
    357     UTL_RAW.CAST_TO_VARCHAR2 (
    358     UTL_ENCODE.BASE64_ENCODE (UTL_RAW.CAST_TO_RAW (P_PASS))
    359     )
    360     );
    361     END IF;
    362     /*设置发送地址和接收地址*/
    363     UTL_SMTP.MAIL (L_CONN, P_SENDORADDRESS2);
    364     UTL_SMTP.RCPT (L_CONN, P_RECEIVERADDRESS2);
    365     /*设置邮件头*/
    366     UTL_SMTP.OPEN_DATA (L_CONN);
    367     WRITE_DATA (L_CONN, 'Date', TO_CHAR (SYSDATE, 'yyyy-mm-dd hh24:mi:ss'));
    368     /*设置发送人*/
    369     WRITE_DATA (L_CONN, 'From', P_SENDOR);
    370     /*设置接收人*/
    371     WRITE_DATA (L_CONN, 'To', P_RECEIVER);
    372     /*设置邮件主题*/
    373     WRITE_DATA (L_CONN, 'Subject', P_SUB);
    374     WRITE_DATA (L_CONN, 'Content-Type', MULTIPART_MIME_TYPE);
    375     UTL_SMTP.WRITE_DATA (L_CONN, UTL_TCP.CRLF);
    376     UTL_SMTP.WRITE_DATA (L_CONN, FIRST_BOUNDARY);
    377     WRITE_DATA (L_CONN, 'Content-Type', 'text/plain;charset=gb2312');
    378     --单独空一行,否则,正文内容不显示
    379     UTL_SMTP.WRITE_DATA (L_CONN, UTL_TCP.CRLF);
    380     /* 设置邮件正文
    381     把分隔符还原成chr(10)。这主要是为了shell中调用该过程,如果有多行,则先把多行的内容合并成一行,并用 l_splite分隔
    382     然后用 l_crlf替换chr(10)。这一步是必须的,否则将不能发送邮件正文有多行的邮件
    383     */
    384     WRITE_DATA (
    385     L_CONN,
    386     '',
    387     REPLACE (REPLACE (P_TXT, L_SPLITE, CHR (10)), CHR (10), L_CRLF),
    388     '',
    389     ''
    390     );
    391     END_BOUNDARY (L_CONN);
    392     --如果文件名称不为空,则发送附件
    393     IF (P_FILENAME IS NOT NULL)
    394     THEN
    395     --根据逗号或者分号拆分附件地址
    396     P_SPLITE_STR (P_FILENAME, 2);
    397     --循环发送附件(在同一个邮件中)
    398     FOR K IN 1 .. MY_ACCT_LIST.COUNT
    399     LOOP
    400     ATTACHMENT (
    401     CONN => L_CONN,
    402     FILENAME => MY_ACCT_LIST (K),
    403     TRANSFER_ENC => P_ENCODE,
    404     DT_NAME => L_DIRECTORY_BASE_NAME || TO_CHAR (K)
    405     );
    406     END LOOP;
    407     END IF;
    408     /*关闭数据写入*/
    409     UTL_SMTP.CLOSE_DATA (L_CONN);
    410     /*关闭连接*/
    411     UTL_SMTP.QUIT (L_CONN);
    412     /*异常处理*/
    413     EXCEPTION
    414     WHEN OTHERS
    415     THEN
    416     NULL;
    417     RAISE;
    418     END;
    419     ---------------------------------------------------主过程-----------------------------------------------------
    420     BEGIN
    421     L_SENDORADDRESS := '<' || P_SENDOR || '>';
    422     P_SPLITE_STR (P_RECEIVER); --处理邮件地址
    423     FOR K IN 1 .. MY_ADDRESS_LIST.COUNT
    424     LOOP
    425     P_EMAIL (L_SENDORADDRESS, MY_ADDRESS_LIST (K));
    426     END LOOP;
    427     /*处理邮件地址,根据逗号分割邮件*/
    428     EXCEPTION
    429     WHEN OTHERS
    430     THEN
    431     RAISE;
    432     --RAISE_APPLICATION_ERROR(-20000,'PROCSENDEMAIL异常中止');
    433     END;
  • 相关阅读:
    Angular Universal 学习笔记
    SAP Spartacus 如何获得当前渲染页面的 CMS 元数据
    Angular 服务器端渲染的学习笔记(二)
    Angular 服务器端渲染的学习笔记(一)
    第三方外部 Saas提供商如何跟使用 SAP 系统的客户进行对接接口集成
    如何从 SAP Spartacus Product Detail 页面,找到其 Angular 实现 Component 的位置
    具备自动刷新功能的 SAP ABAP ALV 报表
    C++学习目录
    c--条件编译
    c--文件读写--二进制
  • 原文地址:https://www.cnblogs.com/huminxxl/p/3208437.html
Copyright © 2011-2022 走看看