对DBA而言,尽管在os级别下发送邮件是轻而易举的事情,然而很多时候我们也需要在PL/SQL中来发送邮件,比如监控job的执行状况等。本文根据网友(源作者未考证)的代码将其改装并封装到了package,感谢这位网友的无私奉献。文章首先给出演示调用该包发送邮件的情形后面给出了完整的代码。经测试Oracle 10g,Oracle 11g下均可用。关于os下发送邮件可参考:不可或缺的 sendEmail
1、调用SENDMAIL_PKG来发送邮件
gx_admin@SYBO2SZ> set serveroutput on; gx_admin@SYBO2SZ> DECLARE 2 P_RECEIVER VARCHAR2(32767); 3 P_SUB VARCHAR2(32767); 4 P_TXT VARCHAR2(32767); 5 ERR_NUM NUMBER; 6 ERR_MSG VARCHAR2(32767); 7 8 BEGIN 9 P_RECEIVER := 'robinson.chen@12306.com'; 10 P_SUB := 'Test mail'; 11 P_TXT := 'This is a test mail.'; 12 ERR_NUM := NULL; 13 ERR_MSG := NULL; 14 15 SENDMAIL_PKG.SENDMAIL ( P_RECEIVER, P_SUB, P_TXT, ERR_NUM, ERR_MSG ); 16 17 DBMS_OUTPUT.Put_Line('ERR_NUM = ' || TO_CHAR(ERR_NUM)); 18 DBMS_OUTPUT.Put_Line('ERR_MSG = ' || ERR_MSG); 19 20 DBMS_OUTPUT.Put_Line(''); 21 22 COMMIT; 23 END; 24 / ERR_NUM = 0 ERR_MSG = PL/SQL procedure successfully completed.

3、原代码
--specification section
CREATE OR REPLACE PACKAGE "SENDMAIL_PKG"
IS
PROCEDURE sendmail (p_receiver VARCHAR2,
p_sub VARCHAR2,
p_txt VARCHAR2,
err_num OUT NUMBER,
err_msg OUT VARCHAR2);
END;
/
--body section
CREATE OR REPLACE PACKAGE BODY "SENDMAIL_PKG"
IS
PROCEDURE sendmail (p_receiver VARCHAR2,
p_sub VARCHAR2,
p_txt VARCHAR2,
err_num OUT NUMBER,
err_msg OUT VARCHAR2)
IS
/* p_receiver => receiver
p_sub => mail subject
p_txt => mail content
*/
p_user VARCHAR2 (30) := NULL;
p_pass VARCHAR2 (30) := NULL;
p_sendor VARCHAR2 (40) := 'DBA@gotrade.com';
p_server VARCHAR2 (20)
-- := system_pkg.get_sys_para_value ('TC_SMTP_IP'); --'192.168.7.65';
:='192.168.7.65';
p_port NUMBER := 25;
p_need_smtp NUMBER := 0;
p_subject VARCHAR2 (4000);
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 || '"' ;
TYPE address_list IS TABLE OF VARCHAR2 (100)
INDEX BY BINARY_INTEGER;
my_address_list address_list;
---------------------------------------split mail address----------------------------------------------
PROCEDURE p_splite_str (p_str VARCHAR2, p_splite_flag INT DEFAULT 1)
IS
l_addr VARCHAR2 (254) := '';
l_len INT;
l_str VARCHAR2 (4000);
j INT := 0;
BEGIN
/*Handle recieve mail address, such like blank, semicolon*/
l_str :=
TRIM (RTRIM (REPLACE (REPLACE (p_str, ';', ','), ' ', ''), ','));
l_len := LENGTH (l_str);
FOR i IN 1 .. l_len
LOOP
IF SUBSTR (l_str, i, 1) <> ','
THEN
l_addr := l_addr || SUBSTR (l_str, i, 1);
ELSE
j := j + 1;
IF p_splite_flag = 1
THEN
--Add symbol '<>' for each mail address. else could not send to many reciever
l_addr := '<' || l_addr || '>';
my_address_list (j) := l_addr;
END IF;
l_addr := '';
END IF;
IF i = l_len
THEN
j := j + 1;
IF p_splite_flag = 1
THEN
l_addr := '<' || l_addr || '>';
my_address_list (j) := l_addr;
END IF;
END IF;
END LOOP;
END;
-----------------------------------write mail header and mail content----------------------------------
PROCEDURE write_data (p_conn IN OUT NOCOPY UTL_SMTP.connection,
p_name IN VARCHAR2,
p_value IN VAR