存档的别人的资料,共享:------------------------------------------------写邮件头和邮件内容------------------------------------------ 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 对解决中文乱码问题很重要*/ 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 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; ----------------------------------------------发送附件---------------------------------------------------- PROCEDURE ATTACHMENT(CONN IN OUT NOCOPY UTL_SMTP.CONNECTION, MIME_TYPE IN VARCHAR2 DEFAULT 'text/plain', INLINE IN BOOLEAN DEFAULT TRUE, FILENAME IN VARCHAR2 DEFAULT 't.txt', TRANSFER_ENC IN VARCHAR2 DEFAULT '7 bit', DT_NAME IN VARCHAR2 DEFAULT '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 || '"'); ELSE WRITE_DATA(CONN, 'Content-Disposition', 'attachment; filename="' || L_FILENAME || '"'); END IF; --设置附件的转换格式 IF (TRANSFER_ENC IS NOT NULL) THEN WRITE_DATA(CONN, 'Content-Transfer-Encoding', TRANSFER_ENC); END IF;
UTL_SMTP.WRITE_DATA(CONN, UTL_TCP.CRLF);
--begin 贴附件内容 IF TRANSFER_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; END IF; DBMS_LOB.FILEOPEN(L_FIL, DBMS_LOB.FILE_READONLY); DBMS_LOB.READ(L_FIL, L_AMT, L_FILEPOS, L_BUF); L_DATA := NULL; FOR I 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; END IF; UTL_SMTP.WRITE_RAW_DATA(CONN, UTL_ENCODE.BASE64_ENCODE(L_DATA)); L_DATA := NULL; IF (L_FILE_LEN < L_AMT AND L_FILE_LEN > 0) THEN L_AMT := L_FILE_LEN; END IF; DBMS_LOB.READ(L_FIL, L_AMT, L_FILEPOS, L_BUF); END LOOP; DBMS_LOB.FILECLOSE(L_FIL); END_BOUNDARY(CONN); EXCEPTION WHEN OTHERS THEN DBMS_LOB.FILECLOSE(L_FIL); END_BOUNDARY(CONN); RAISE; END; --结束处理二进制附件
END IF; --结束处理附件内容 DROP_DIRECTORY(DT_NAME); END; --结束过程ATTACHMENT ---------------------------------------------真正发送邮件的过程-------------------------------------------- PROCEDURE P_EMAIL(P_SENDORADDRESS2 VARCHAR2, --发送地址 P_RECEIVERADDRESS2 VARCHAR2) --接受地址 IS L_CONN UTL_SMTP.CONNECTION; --定义连接 BEGIN /*初始化邮件服务器信息,连接邮件服务器*/ L_CONN := UTL_SMTP.OPEN_CONNECTION(P_SERVER, P_PORT); UTL_SMTP.HELO(L_CONN, P_SERVER); /* smtp服务器登录校验 */ 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;
--如果文件名称不为空,则发送附件 IF (P_FILENAME IS NOT NULL) THEN --根据逗号或者分号拆分附件地址 P_SPLITE_STR(P_FILENAME, 2); --循环发送附件(在同一个邮件中) FOR K IN 1 .. MY_ACCT_LIST.COUNT LOOP ATTACHMENT(CONN => L_CONN, FILENAME => MY_ACCT_LIST(K), TRANSFER_ENC => P_ENCODE, DT_NAME => L_DIRECTORY_BASE_NAME || TO_CHAR(K)); END LOOP; END IF;
END; ---------------------------------------------------主过程-----------------------------------------------------BEGIN L_SENDORADDRESS := '<' || P_SENDOR || '>'; P_SPLITE_STR(P_RECEIVER);--处理邮件地址 FOR K IN 1 .. MY_ADDRESS_LIST.COUNT LOOP P_EMAIL(L_SENDORADDRESS, MY_ADDRESS_LIST(K)); END LOOP; /*处理邮件地址,根据逗号分割邮件*/EXCEPTION WHEN OTHERS THEN RAISE; END;--使用实例:代码:--------------------------------------------------------------------------------set serverout on exec PROCSENDEMAIL('邮件内容','邮件标题','对方邮件名','抄送邮件名,你的邮件名','202.108.5.85',25,1,'用户名','密码','附件路径(支持图片)','base64');PL/SQL procedure successfully completed.
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 对解决中文乱码问题很重要*/
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 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; ----------------------------------------------发送附件---------------------------------------------------- PROCEDURE ATTACHMENT(CONN IN OUT NOCOPY UTL_SMTP.CONNECTION,
MIME_TYPE IN VARCHAR2 DEFAULT 'text/plain',
INLINE IN BOOLEAN DEFAULT TRUE,
FILENAME IN VARCHAR2 DEFAULT 't.txt',
TRANSFER_ENC IN VARCHAR2 DEFAULT '7 bit',
DT_NAME IN VARCHAR2 DEFAULT '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 || '"');
ELSE
WRITE_DATA(CONN, 'Content-Disposition', 'attachment; filename="' ||
L_FILENAME || '"');
END IF; --设置附件的转换格式
IF (TRANSFER_ENC IS NOT NULL) THEN
WRITE_DATA(CONN, 'Content-Transfer-Encoding', TRANSFER_ENC);
END IF;
UTL_SMTP.WRITE_DATA(CONN, UTL_TCP.CRLF);
--begin 贴附件内容
IF TRANSFER_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;
END IF;
DBMS_LOB.FILEOPEN(L_FIL, DBMS_LOB.FILE_READONLY);
DBMS_LOB.READ(L_FIL, L_AMT, L_FILEPOS, L_BUF);
L_DATA := NULL;
FOR I 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;
END IF;
UTL_SMTP.WRITE_RAW_DATA(CONN, UTL_ENCODE.BASE64_ENCODE(L_DATA));
L_DATA := NULL;
IF (L_FILE_LEN < L_AMT AND L_FILE_LEN > 0) THEN
L_AMT := L_FILE_LEN;
END IF;
DBMS_LOB.READ(L_FIL, L_AMT, L_FILEPOS, L_BUF);
END LOOP;
DBMS_LOB.FILECLOSE(L_FIL);
END_BOUNDARY(CONN);
EXCEPTION
WHEN OTHERS THEN
DBMS_LOB.FILECLOSE(L_FIL);
END_BOUNDARY(CONN);
RAISE;
END; --结束处理二进制附件
END IF; --结束处理附件内容
DROP_DIRECTORY(DT_NAME);
END; --结束过程ATTACHMENT ---------------------------------------------真正发送邮件的过程--------------------------------------------
PROCEDURE P_EMAIL(P_SENDORADDRESS2 VARCHAR2, --发送地址
P_RECEIVERADDRESS2 VARCHAR2) --接受地址
IS
L_CONN UTL_SMTP.CONNECTION; --定义连接
BEGIN
/*初始化邮件服务器信息,连接邮件服务器*/
L_CONN := UTL_SMTP.OPEN_CONNECTION(P_SERVER, P_PORT);
UTL_SMTP.HELO(L_CONN, P_SERVER);
/* smtp服务器登录校验 */
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;
/*设置发送地址和接收地址*/
UTL_SMTP.MAIL(L_CONN, P_SENDORADDRESS2);
UTL_SMTP.RCPT(L_CONN, P_RECEIVERADDRESS2);
/*设置邮件头*/
UTL_SMTP.OPEN_DATA(L_CONN);
WRITE_DATA(L_CONN, 'Date', TO_CHAR(SYSDATE, 'yyyy-mm-dd hh24:mi:ss'));
/*设置发送人*/
WRITE_DATA(L_CONN, 'From', P_SENDOR);
/*设置接收人*/
WRITE_DATA(L_CONN, 'To', P_RECEIVER);
/*设置邮件主题*/
WRITE_DATA(L_CONN, 'Subject', P_SUB);
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/plain;charset=gb2312');
--单独空一行,否则,正文内容不显示
UTL_SMTP.WRITE_DATA(L_CONN, UTL_TCP.CRLF);
/* 设置邮件正文
把分隔符还原成chr(10)。这主要是为了shell中调用该过程,如果有多行,则先把多行的内容合并成一行,并用 l_splite分隔
然后用 l_crlf替换chr(10)。这一步是必须的,否则将不能发送邮件正文有多行的邮件
*/
WRITE_DATA(L_CONN, '', REPLACE(REPLACE(P_TXT, L_SPLITE, CHR(10)), CHR(10), L_CRLF), '', '');
END_BOUNDARY(L_CONN);
--如果文件名称不为空,则发送附件
IF (P_FILENAME IS NOT NULL) THEN
--根据逗号或者分号拆分附件地址
P_SPLITE_STR(P_FILENAME, 2);
--循环发送附件(在同一个邮件中)
FOR K IN 1 .. MY_ACCT_LIST.COUNT LOOP
ATTACHMENT(CONN => L_CONN, FILENAME => MY_ACCT_LIST(K), TRANSFER_ENC => P_ENCODE, DT_NAME => L_DIRECTORY_BASE_NAME ||
TO_CHAR(K));
END LOOP;
END IF;
/*关闭数据写入*/
UTL_SMTP.CLOSE_DATA(L_CONN);
/*关闭连接*/
UTL_SMTP.QUIT(L_CONN);
/*异常处理*/
EXCEPTION
WHEN OTHERS THEN
NULL;
RAISE;
END; ---------------------------------------------------主过程-----------------------------------------------------BEGIN
L_SENDORADDRESS := '<' || P_SENDOR || '>';
P_SPLITE_STR(P_RECEIVER);--处理邮件地址
FOR K IN 1 .. MY_ADDRESS_LIST.COUNT LOOP
P_EMAIL(L_SENDORADDRESS, MY_ADDRESS_LIST(K));
END LOOP;
/*处理邮件地址,根据逗号分割邮件*/EXCEPTION
WHEN OTHERS THEN
RAISE;
END;--使用实例:代码:--------------------------------------------------------------------------------set serverout on
exec PROCSENDEMAIL('邮件内容','邮件标题','对方邮件名','抄送邮件名,你的邮件名','202.108.5.85',25,1,'用户名','密码','附件路径(支持图片)','base64');PL/SQL procedure successfully completed.