Oracle 儲存過程中傳送郵件,並支援使用者驗證 中文標題和內容
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
在 Oracle的儲存過程執行中,我們可能希望它本身能完成郵件傳送執行的結果,特別是在捕獲到了異常時。不能總是依賴於呼叫儲存過程的外部程式--呼叫後,根據出口引數,傳送執行結果。這一需求更迫切的表現在非人工參與的 Oracle Job 呼叫儲存過程的情況下。
所幸,Oracle為我們提供了傳送郵件的工具包 UTL_SMTP,它最早出現在 Oracle 8.1.7版本中。下面是我從網路上搜索相關資料後、綜合整理、多處修正、數次除錯、排除萬難而寫出的一個傳送郵件的儲存過程。可支援需使用者驗證的郵件伺服器,中文標題和中文內容無亂碼,只還未支援附件的傳送,相信這方面應用較少,需要的話再 Google 一下,且文後參考中有相應的連結。
01.
CREATE
OR
REPLACE
PROCEDURE
send_mail(
02.
p_recipient VARCHAR2,
-- 郵件接收人
03.
p_subject VARCHAR2,
-- 郵件標題
04.
p_message VARCHAR2
-- 郵件正文
05.
)
06.
IS
07.
08.
--下面四個變數請根據實際郵件伺服器進行賦值
09.
v_mailhost VARCHAR2(30) :=
'mail.xxx.com'
;
--SMTP伺服器地址
10.
v_user VARCHAR2(30) :=
'user'
;
--登入SMTP伺服器的使用者名稱
11.
v_pass VARCHAR2(20) :=
'pass'
;
--登入SMTP伺服器的密碼
12.
v_sender VARCHAR2(50) :=
'[email protected]'
;
--傳送都郵箱,一般與 ps_user 對應
13.
14.
v_conn UTL_SMTP.
connection
;
--到郵件伺服器的連線
15.
v_msg varchar2(4000);
--郵件內容
16.
17.
BEGIN
18.
19.
v_conn := UTL_SMTP.open_connection(v_mailhost, 25);
20.
UTL_SMTP.ehlo(v_conn, v_mailhost);
--是用 ehlo() 而不是 helo() 函式
21.
--否則會報:ORA-29279: SMTP 永久性錯誤: 503 5.5.2 Send hello first.
22.
23.
UTL_SMTP.command(v_conn,
'AUTH LOGIN'
);
-- smtp伺服器登入校驗
24.
UTL_SMTP.command(v_conn,UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(UTL_RAW.cast_to_raw(v_user))));
25.
UTL_SMTP.command(v_conn,UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(UTL_RAW.cast_to_raw(v_pass))));
26.
27.
UTL_SMTP.mail(v_conn, v_sender);
--設定發件人
28.
UTL_SMTP.rcpt(v_conn, p_recipient);
--設定收件人
29.
30.
-- 建立要傳送的郵件內容 注意報頭資訊和郵件正文之間要空一行
31.
v_msg :=
'Date:'
|| TO_CHAR(SYSDATE,
'dd mon yy hh24:mi:ss'
)
32.
|| UTL_TCP.CRLF ||
'From: '
|| v_sender ||
'<'
|| v_sender ||
'>'
33.
|| UTL_TCP.CRLF ||
'To: '
|| p_recipient ||
'<'
|| p_recipient ||
'>'
34.
|| UTL_TCP.CRLF ||
'Subject: '
|| p_subject
35.
|| UTL_TCP.CRLF || UTL_TCP.CRLF
-- 這前面是報頭資訊
36.
|| p_message;
-- 這個是郵件正文
37.
38.
UTL_SMTP.open_data(v_conn);
--開啟流
39.
UTL_SMTP.write_raw_data(v_conn, UTL_RAW.cast_to_raw(v_msg));
--這樣寫標題和內容都能用中文
40.
UTL_SMTP.close_data(v_conn);
--關閉流
41.
UTL_SMTP.quit(v_conn);
--關閉連線
42.
43.
EXCEPTION
44.
45.
WHEN
OTHERS
THEN
46.
DBMS_OUTPUT.put_line(DBMS_UTILITY.format_error_stack);
47.
DBMS_OUTPUT.put_line(DBMS_UTILITY.format_call_stack);
48.
49.
END
send_mail;
上面程式碼在 Oracle 9.2.0(Solaris 平臺,資料庫字符集是 ZHS16GBK) 中實際執行後通過,在 PL/SQL Developer 的 SQL Window 中用下面程式碼呼叫該儲存過程:
begin
send_mail('[email protected]','中文標題','中文內容');
end;
而且在 PL/SQL Developer 的 Command Windows 或是 SQL *Plus 中執行:
send_mail('[email protected]','中文標題','中文內容');
都能正常傳送,成功收到郵件,並且標題和內容的中文顯示正常。
網路上直接拿下來的例子,多是沒有很好的解決中文文題,有些不能支援郵件伺服器的驗證,當今時代要找個不需要使用者驗證的郵件伺服器太難了。關鍵是有個致命問題是,一執行就報類似如下的錯誤:
ORA-29279: SMTP 永久性錯誤: 503 5.5.2 Send hello first.
----- PL/SQL Call Stack -----
object line object
handle number name
38298bd60 45 procedure TCSM.SEND_MAIL
38a4efa40 2 anonymous block
原因是:若郵件伺服器需要使用者驗證時,對郵件伺服器打招呼的方式不對,不能寫成
UTL_SMTP.helo(v_conn, v_mailhost);
而要寫成:
UTL_SMTP.ehlo(v_conn, v_mailhost);
如果你的郵件中只用英文,那麼上面程式碼中的三行:
UTL_SMTP.open_data(v_conn); --開啟流
UTL_SMTP.write_raw_data(v_conn, UTL_RAW.cast_to_raw(v_msg));
UTL_SMTP.close_data(v_conn); --關閉流
只需要寫成一行就行了,如下:
UTL_SMTP.DATA (mail_conn, v_msg);
也可以把郵件報頭和正文資訊分開來寫入到連線中去,但這樣做恐怕對於標題和正文的中文文題會顧此失彼了。
參考:1. 用utl_smtp傳送郵件時的漢字解決方法
2. 例項講解如何通過Oracle成功傳送郵件
3. 用oracle傳送郵件(功能很全) 介紹了附件的傳送
4. Oracle UTL_SMTP
5. 用telnet發郵件(支援smtp認證)
附註:在 Oracle(8.1.7及以上版本) 中可以用下面語句獲得字串的 base64 編碼,如:
select UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(UTL_RAW.cast_to_raw('user'))) from dual;
select UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(UTL_RAW.cast_to_raw('pass'))) from dual;