1. 程式人生 > >Oracle 儲存過程中傳送郵件,並支援使用者驗證 中文標題和內容

Oracle 儲存過程中傳送郵件,並支援使用者驗證 中文標題和內容

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

 在 Oracle的儲存過程執行中,我們可能希望它本身能完成郵件傳送執行的結果,特別是在捕獲到了異常時。不能總是依賴於呼叫儲存過程的外部程式--呼叫後,根據出口引數,傳送執行結果。這一需求更迫切的表現在非人工參與的 Oracle Job 呼叫儲存過程的情況下。

所幸,Oracle為我們提供了傳送郵件的工具包 UTL_SMTP,它最早出現在 Oracle 8.1.7版本中。下面是我從網路上搜索相關資料後、綜合整理、多處修正、數次除錯、排除萬難而寫出的一個傳送郵件的儲存過程。可支援需使用者驗證的郵件伺服器,中文標題和中文內容無亂碼,只還未支援附件的傳送,相信這方面應用較少,需要的話再 Google 一下,且文後參考中有相應的連結。

view source print ? 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;

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述