CREATEORREPLACE PROCEDURE PROCSENDEMAIL(P_TXT VARCHAR2,P_SUB VARCHAR2,P_SENDOR VARCHAR2,P_RECEIVER VARCHAR2,P_SERVER VARCHAR2,P_PORT NUMBERDEFAULT25,P_NEED_SMTP INTDEFAULT0,P_USER VARCHAR2DEFAULTNULL,P_PASS VARCHAR2DEFAULTNULL,P_FILENAME VARCHAR2DEFAULTNULL,P_ENCODE VARCHAR2DEFAULT'bit 7')AUTHID CURRENT_USER IS/*
作用:用oracle发送邮件
主要功能:1、支持多收件人。
2、支持中文
3、支持大于32K的附件
4、支持多行正文
5、支持多附件
6、支持文本附件和二进制附件
7、支持HTML格式
作者:suk
参数说明:
p_txt :邮件正文
p_sub: 邮件标题
p_SendorAddress : 发送人邮件地址
p_ReceiverAddress : 接收地址,可以同时发送到多个地址上,地址之间用","或者";"隔开
p_EmailServer : 邮件服务器地址,可以是域名或者IP
p_Port :邮件服务器端口
p_need_smtp:是否需要smtp认证,0表示不需要,1表示需要
p_user:smtp验证需要的用户名
p_pass:smtp验证需要的密码
p_filename:附件名称,必须包含完整的路径,如"d:\tempa.txt"。
可以有多个附件,附件名称只见用逗号或者分号分隔
p_encode:附件编码转换格式,其中 p_encode='bit 7' 表示文本类型附件
p_encode='base64' 表示二进制类型附件
注意:
1、对于文本类型的附件,不能用base64的方式发送,否则出错
2、对于多个附件只能用同一种格式发送
*/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||'"';/* 以下部分是发送大二进制附件时用到的变量 */L_FIL BFILE;L_FILE_LEN NUMBER;L_MODULO NUMBER;L_PIECES NUMBER;L_FILE_HANDLE UTL_FILE.FILE_TYPE;L_AMT BINARY_INTEGER:=672*3;/* ensures proper format; 2016 */L_FILEPOS PLS_INTEGER:=1;/* pointer for the file */L_CHUNKS NUMBER;L_BUF RAW(2100);L_DATA RAW(2100);L_MAX_LINE_WIDTH NUMBER:=54;L_DIRECTORY_BASE_NAME VARCHAR2(100) :='DIR_FOR_SEND_MAIL';L_LINE VARCHAR2(1000);L_MESG VARCHAR2(32767);/* 以上部分是发送大二进制附件时用到的变量 */TYPE ADDRESS_LIST IS TABLE OF VARCHAR2(100)INDEX BY BINARY_INTEGER;MY_ADDRESS_LIST ADDRESS_LIST;TYPE ACCT_LIST IS TABLE OF VARCHAR2(100)INDEX BY BINARY_INTEGER;MY_ACCT_LIST ACCT_LIST;
-------------------------------------返回附件源文件所在目录或者名称--------------------------------------
FUNCTIONGET_FILE(P_FILE VARCHAR2,P_GET INT) RETURNVARCHAR2 IS--p_get=1 表示返回目录--p_get=2 表示返回文件名
L_FILE VARCHAR2(1000);BEGINIFINSTR(P_FILE,'') >0 THEN--windowsIFP_GET=1 THEN
L_FILE:=SUBSTR(P_FILE,1,INSTR(P_FILE,'', -1) -1);ELSIF P_GET=2 THEN
L_FILE:=SUBSTR(P_FILE, - (LENGTH(P_FILE) -INSTR(P_FILE,'', -1)));ENDIF;ELSIF INSTR(P_FILE,'/') >0 THEN--linux/unixIFP_GET=1 THEN
L_FILE:=SUBSTR(P_FILE,1,INSTR(P_FILE,'/', -1) -1);ELSIF P_GET=2 THEN
L_FILE:=SUBSTR(P_FILE, - (LENGTH(P_FILE) -INSTR(P_FILE,'/', -1)));ENDIF;ENDIF;
RETURNL_FILE;END;
---------------------------------------------删除directory------------------------------------PROCEDURE DROP_DIRECTORY(P_DIRECTORY_NAME VARCHAR2)IS
BEGIN
EXECUTE IMMEDIATE'drop directory '||P_DIRECTORY_NAME;EXCEPTION
WHEN OTHERS THEN
NULL;END;
--------------------------------------------------创建directory-----------------------------------------PROCEDURE CREATE_DIRECTORY(P_DIRECTORY_NAME VARCHAR2,P_DIR VARCHAR2)IS
BEGIN
EXECUTE IMMEDIATE'create directory '||P_DIRECTORY_NAME||' as '''||P_DIR||'''';EXECUTE IMMEDIATE'grant read,write on directory '||P_DIRECTORY_NAME||' to public';EXCEPTION
WHEN OTHERS THEN
RAISE;END;
--------------------------------------------分割邮件地址或者附件地址-----------------------------------PROCEDURE P_SPLITE_STR(P_STR VARCHAR2,P_SPLITE_FLAG INTDEFAULT1)IS
L_ADDR VARCHAR2(254) :='';L_LEN INT;L_STR VARCHAR2(4000);J INT:=0; --表示邮件地址或者附件的个数
BEGIN/*处理接收邮件地址列表,包括去空格、将;转换为,等*/L_STR:=TRIM(RTRIM(REPLACE(REPLACE(P_STR,';',','),' ',''),','));L_LEN:=LENGTH(L_STR);
FORI IN 1..L_LEN LOOPIFSUBSTR(L_STR,I,1) <>','THEN
L_ADDR:=L_ADDR||SUBSTR(L_STR,I,1);
ELSEJ:=J+1;
IFP_SPLITE_FLAG=1 THEN--表示处理邮件地址--前后需要加上'<>',否则很多邮箱将不能发送邮件
L_ADDR:='||L_ADDR||'>';
--调用邮件发送过程
MY_ADDRESS_LIST(J) :=L_ADDR;ELSIF P_SPLITE_FLAG=2 THEN--表示处理附件名称
MY_ACCT_LIST(J) :=L_ADDR;ENDIF;L_ADDR:='';ENDIF;
IFI=L_LEN THEN
J:=J+1;
IFP_SPLITE_FLAG=1 THEN--调用邮件发送过程
L_ADDR:='||L_ADDR||'>';MY_ADDRESS_LIST(J) :=L_ADDR;ELSIF P_SPLITE_FLAG=2 THEN
MY_ACCT_LIST(J) :=L_ADDR;ENDIF;ENDIF;END LOOP;END;
------------------------------------------------写邮件头和邮件内容------------------------------------------PROCEDURE WRITE_DATA(P_CONN IN OUT NOCOPY UTL_SMTP.CONNECTION,P_NAME IN VARCHAR2,P_VALUE IN VARCHAR2,P_SPLITE VARCHAR2DEFAULT':',P_CRLF VARCHAR2DEFAULTL_CRLF)IS
BEGIN/* utl_raw.cast_to_raw 对解决中文乱码问题很重要*/UTL_SMTP.WRITE_RAW_DATA(P_CONN,UTL_RAW.CAST_TO_RAW(CONVERT(P_NAME||P_SPLITE||P_VALUE||P_CRLF,'ZHS16GBK')));END;
----------------------------------------写MIME邮件尾部-----------------------------------------------------PROCEDURE END_BOUNDARY(CONN IN OUT NOCOPY UTL_SMTP.CONNECTION,LAST IN BOOLEANDEFAULTFALSE)IS
BEGIN
UTL_SMTP.WRITE_DATA(CONN,UTL_TCP.CRLF);
IF (LAST)THEN
UTL_SMTP.WRITE_DATA(CONN,LAST_BOUNDARY);ENDIF;END;
----------------------------------------------发送附件----------------------------------------------------PROCEDURE ATTACHMENT(CONN IN OUT NOCOPY UTL_SMTP.CONNECTION,MIME_TYPE IN VARCHAR2DEFAULT'text/plain',INLINE IN BOOLEANDEFAULTTRUE,FILENAME IN VARCHAR2DEFAULT't.txt',TRANSFER_ENC IN VARCHAR2DEFAULT'7 bit',DT_NAME IN VARCHAR2DEFAULT'0')IS
L_FILENAME VARCHAR2(1000);BEGIN--写附件头
UTL_SMTP.WRITE_DATA(CONN,FIRST_BOUNDARY);
--设置附件格式
WRITE_DATA(CONN,'Content-Type',MIME_TYPE);
--如果文件名称非空,表示有附件
DROP_DIRECTORY(DT_NAME);
--创建directory
CREATE_DIRECTORY(DT_NAME,GET_FILE(FILENAME,1));
--得到附件文件名称
L_FILENAME:=GET_FILE(FILENAME,2);
IF (INLINE)THEN
WRITE_DATA(CONN,'Content-Disposition','inline; filename="'||L_FILENAME||'"');
ELSEWRITE_DATA(CONN,'Content-Disposition','attachment; filename="'||L_FILENAME||'"');ENDIF;
--设置附件的转换格式IF (TRANSFER_ENC IS NOT NULL)THEN
WRITE_DATA(CONN,'Content-Transfer-Encoding',TRANSFER_ENC);ENDIF;UTL_SMTP.WRITE_DATA(CONN,UTL_TCP.CRLF);
--begin 贴附件内容IFTRANSFER_ENC='bit 7'THEN--如果是文本类型的附件
BEGIN
L_FILE_HANDLE:=UTL_FILE.FOPEN(DT_NAME,L_FILENAME,'r'); --打开文件--把附件分成多份,这样可以发送超过32K的附件
LOOP
UTL_FILE.GET_LINE(L_FILE_HANDLE,L_LINE);L_MESG:=L_LINE||L_CRLF;WRITE_DATA(CONN,'',L_MESG,'','');END LOOP;UTL_FILE.FCLOSE(L_FILE_HANDLE);END_BOUNDARY(CONN);EXCEPTION
WHEN OTHERS THEN
UTL_FILE.FCLOSE(L_FILE_HANDLE);END_BOUNDARY(CONN);NULL;END; --结束文本类型附件的处理
ELSIF TRANSFER_ENC='base64'THEN--如果是二进制类型的附件
BEGIN--把附件分成多份,这样可以发送超过32K的附件
L_FILEPOS:=1;--重置offset,在发送多个附件时,必须重置
L_FIL:=BFILENAME(DT_NAME,L_FILENAME);L_FILE_LEN:=DBMS_LOB.GETLENGTH(L_FIL);L_MODULO:=MOD(L_FILE_LEN,L_AMT);L_PIECES:=TRUNC(L_FILE_LEN/L_AMT);
IF (L_MODULO<>0)THEN
L_PIECES:=L_PIECES+1;ENDIF;DBMS_LOB.FILEOPEN(L_FIL,DBMS_LOB.FILE_READONLY);DBMS_LOB.READ(L_FIL,L_AMT,L_FILEPOS,L_BUF);L_DATA:=NULL;
FORI IN 1..L_PIECES LOOP
L_FILEPOS:=I*L_AMT+1;L_FILE_LEN:=L_FILE_LEN-L_AMT;L_DATA:=UTL_RAW.CONCAT(L_DATA,L_BUF);L_CHUNKS:=TRUNC(UTL_RAW.LENGTH(L_DATA) /L_MAX_LINE_WIDTH);
IF (I<>L_PIECES)THEN
L_CHUNKS:=L_CHUNKS-1;ENDIF;UTL_SMTP.来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/87010/viewspace-400071/,如需转载,请注明出处,否则将追究法律责任。