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;
  • 相关阅读:
    [转] 百万级数据查询优化
    vs生成失败不报错
    C# 编译器错误对应代码详细信息
    使用XSL 样式表无法查看XML 输入。请更正错误然后单击刷新按钮
    vs中release模式调试和错误:CA0503:无法显示额外的代码分析警告或错误
    sp_executesql的用法
    一个for循环根据条件可以递增或递减
    Lc.exe已退出 代码为1
    将所有输出窗口文本重定向到即时窗口
    两步解决《内部服务器错误:500》
  • 原文地址:https://www.cnblogs.com/huminxxl/p/3208437.html
Copyright © 2011-2022 走看看