码迷,mamicode.com
首页 > 数据库 > 详细

oracle发送邮件

时间:2015-08-07 23:43:07      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:

  1 CREATE OR REPLACE PROCEDURE PROCSENDEMAIL(P_TXT       VARCHAR2,
  2                                           P_SUB       VARCHAR2,
  3                                           P_SENDOR    VARCHAR2,
  4                                           P_RECEIVER  VARCHAR2,
  5                                           P_SERVER    VARCHAR2,
  6                                           P_PORT      NUMBER DEFAULT 25,
  7                                           P_NEED_SMTP INT DEFAULT 0,
  8                                           P_USER      VARCHAR2 DEFAULT NULL,
  9                                           P_PASS      VARCHAR2 DEFAULT NULL,
 10                                           P_FILENAME  VARCHAR2 DEFAULT NULL,
 11                                           P_ENCODE    VARCHAR2 DEFAULT bit 7)
 12   AUTHID CURRENT_USER IS
 13   /*
 14   作用:用oracle发送邮件
 15   主要功能:1、支持多收件人。
 16             2、支持中文
 17             3、支持抄送人
 18             4、支持大于32K的附件
 19             5、支持多行正文
 20             6、支持多附件
 21             7、支持文本附件和二进制附件
 22             8、支持HTML格式
 23             8、支持
 24   作者:suk
 25   参数说明:
 26             p_txt :邮件正文
 27             p_sub: 邮件标题
 28             p_SendorAddress : 发送人邮件地址
 29             p_ReceiverAddress : 接收地址,可以同时发送到多个地址上,地址之间用","或者";"隔开
 30             p_EmailServer : 邮件服务器地址,可以是域名或者IP
 31             p_Port :邮件服务器端口
 32             p_need_smtp:是否需要smtp认证,0表示不需要,1表示需要
 33             p_user:smtp验证需要的用户名
 34             p_pass:smtp验证需要的密码
 35             p_filename:附件名称,必须包含完整的路径,如"d:\temp\a.txt"。
 36                         可以有多个附件,附件名称只见用逗号或者分号分隔
 37             p_encode:附件编码转换格式,其中 p_encode=‘bit 7‘ 表示文本类型附件
 38                                              p_encode=‘base64‘ 表示二进制类型附件
 39   注意:
 40         1、对于文本类型的附件,不能用base64的方式发送,否则出错
 41         2、对于多个附件只能用同一种格式发送
 42   */
 43 
 44   L_CRLF VARCHAR2(2) := UTL_TCP.CRLF;
 45   L_SENDORADDRESS VARCHAR2(4000);
 46   L_SPLITE        VARCHAR2(10) := ++;
 47   BOUNDARY            CONSTANT VARCHAR2(256) := -----BYSUK;
 48   FIRST_BOUNDARY      CONSTANT VARCHAR2(256) := -- || BOUNDARY || L_CRLF;
 49   LAST_BOUNDARY       CONSTANT VARCHAR2(256) := -- || BOUNDARY || -- ||
 50                                                 L_CRLF;
 51   MULTIPART_MIME_TYPE CONSTANT VARCHAR2(256) := multipart/mixed; boundary=" ||
 52                                                 BOUNDARY || ";
 53   /* 以下部分是发送大二进制附件时用到的变量 */
 54   L_FIL                 BFILE;
 55   L_FILE_LEN            NUMBER;
 56   L_MODULO              NUMBER;
 57   L_PIECES              NUMBER;
 58   L_FILE_HANDLE         UTL_FILE.FILE_TYPE;
 59   L_AMT                 BINARY_INTEGER := 672 * 3; /* ensures proper format;  2016 */
 60   L_FILEPOS             PLS_INTEGER := 1; /* pointer for the file */
 61   L_CHUNKS              NUMBER;
 62   L_BUF                 RAW(2100);
 63   L_DATA                RAW(2100);
 64   L_MAX_LINE_WIDTH      NUMBER := 54;
 65   L_DIRECTORY_BASE_NAME VARCHAR2(100) := DIR_FOR_SEND_MAIL;
 66   L_LINE                VARCHAR2(1000);
 67   L_MESG                VARCHAR2(32767);
 68   /* 以上部分是发送大二进制附件时用到的变量 */
 69 
 70   TYPE ADDRESS_LIST IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;
 71   MY_ADDRESS_LIST ADDRESS_LIST;
 72   TYPE ACCT_LIST IS TABLE OF VARCHAR2(100) INDEX BY BINARY_INTEGER;
 73   MY_ACCT_LIST ACCT_LIST;
 74   -------------------------------------返回附件源文件所在目录或者名称--------------------------------------
 75   FUNCTION GET_FILE(P_FILE VARCHAR2,
 76                     P_GET  INT) RETURN VARCHAR2 IS
 77     --p_get=1 表示返回目录
 78     --p_get=2 表示返回文件名
 79     L_FILE VARCHAR2(1000);
 80   BEGIN
 81       IF P_GET = 1 THEN
 82         L_FILE := SUBSTR(P_FILE, 1, INSTR(P_FILE, \, -1) - 1);
 83       ELSIF P_GET = 2 THEN
 84         L_FILE := SUBSTR(P_FILE, - (LENGTH(P_FILE) - INSTR(P_FILE, \, -1)));
 85       END IF;
 86     /*
 87      IF INSTR(P_FILE, ‘\‘) > 0 THEN
 88       --windows
 89       IF P_GET = 1 THEN
 90         L_FILE := SUBSTR(P_FILE, 1, INSTR(P_FILE, ‘\‘, -1) - 1);
 91       ELSIF P_GET = 2 THEN
 92         L_FILE := SUBSTR(P_FILE, - (LENGTH(P_FILE) - INSTR(P_FILE, ‘\‘, -1)));
 93       END IF;
 94     ELSIF INSTR(P_FILE, ‘/‘) > 0 THEN
 95       --linux/unix
 96       IF P_GET = 1 THEN
 97         L_FILE := SUBSTR(P_FILE, 1, INSTR(P_FILE, ‘/‘, -1) - 1);
 98       ELSIF P_GET = 2 THEN
 99         L_FILE := SUBSTR(P_FILE, - (LENGTH(P_FILE) - INSTR(P_FILE, ‘/‘, -1)));
100       END IF;
101     END IF;
102     */
103 
104     RETURN L_FILE;
105   END;
106   ---------------------------------------------删除directory------------------------------------
107   PROCEDURE DROP_DIRECTORY(P_DIRECTORY_NAME VARCHAR2) IS
108   BEGIN
109     EXECUTE IMMEDIATE drop directory  || P_DIRECTORY_NAME;
110   EXCEPTION
111     WHEN OTHERS THEN
112       NULL;
113   END;
114   --------------------------------------------------创建directory-----------------------------------------
115   PROCEDURE CREATE_DIRECTORY(P_DIRECTORY_NAME VARCHAR2,
116                              P_DIR            VARCHAR2) IS
117   BEGIN
118     EXECUTE IMMEDIATE create directory  || P_DIRECTORY_NAME ||  as ‘‘‘ ||
119                       P_DIR || ‘‘‘‘;
120     EXECUTE IMMEDIATE grant read,write on directory  || P_DIRECTORY_NAME ||
121                        to public;
122     EXCEPTION
123     WHEN OTHERS THEN
124       RAISE;
125   END;
126   --------------------------------------------分割邮件地址或者附件地址-----------------------------------
127   PROCEDURE P_SPLITE_STR(P_STR         VARCHAR2,
128                          P_SPLITE_FLAG INT DEFAULT 1) IS
129     L_ADDR VARCHAR2(254) := ‘‘;
130     L_LEN  INT;
131     L_STR  VARCHAR2(4000);
132     J      INT := 0; --表示邮件地址或者附件的个数
133   BEGIN
134     /*处理接收邮件地址列表,包括去空格、将;转换为,等*/
135     L_STR := TRIM(RTRIM(REPLACE(REPLACE(P_STR, ;, ,),  , ‘‘), ,));
136     L_LEN := LENGTH(L_STR);
137     FOR I IN 1 .. L_LEN LOOP
138       IF SUBSTR(L_STR, I, 1) <> , THEN
139         L_ADDR := L_ADDR || SUBSTR(L_STR, I, 1);
140       ELSE
141         J := J + 1;
142         IF P_SPLITE_FLAG = 1 THEN --表示处理邮件地址
143           --前后需要加上‘<>‘,否则很多邮箱将不能发送邮件
144           L_ADDR := < || L_ADDR || >;
145           --调用邮件发送过程
146           MY_ADDRESS_LIST(J) := L_ADDR;
147         ELSIF P_SPLITE_FLAG = 2 THEN --表示处理附件名称
148           MY_ACCT_LIST(J) := L_ADDR;
149         END IF;
150         L_ADDR := ‘‘;
151       END IF;
152       IF I = L_LEN THEN
153         J := J + 1;
154         IF P_SPLITE_FLAG = 1 THEN
155           --调用邮件发送过程
156           L_ADDR := < || L_ADDR || >;
157           MY_ADDRESS_LIST(J) := L_ADDR;
158         ELSIF P_SPLITE_FLAG = 2 THEN
159           MY_ACCT_LIST(J) := L_ADDR;
160         END IF;
161       END IF;
162     END LOOP;
163   END;
164   ------------------------------------------------写邮件头和邮件内容------------------------------------------
165   PROCEDURE WRITE_DATA(P_CONN   IN OUT NOCOPY UTL_SMTP.CONNECTION,
166                        P_NAME   IN VARCHAR2,
167                        P_VALUE  IN VARCHAR2,
168                        P_SPLITE VARCHAR2 DEFAULT :,
169                        P_CRLF   VARCHAR2 DEFAULT L_CRLF) IS
170   BEGIN
171     /* utl_raw.cast_to_raw 对解决中文乱码问题很重要*/
172     UTL_SMTP.WRITE_RAW_DATA(P_CONN, UTL_RAW.CAST_TO_RAW(CONVERT(P_NAME ||
173                                                          P_SPLITE ||
174                                                          P_VALUE ||
175                                                          P_CRLF, ZHS16GBK)));
176   END;
177   ----------------------------------------写MIME邮件尾部-----------------------------------------------------
178 
179   PROCEDURE END_BOUNDARY(CONN IN OUT NOCOPY UTL_SMTP.CONNECTION,
180                          LAST IN BOOLEAN DEFAULT FALSE) IS
181   BEGIN
182     UTL_SMTP.WRITE_DATA(CONN, UTL_TCP.CRLF);
183     IF (LAST) THEN
184       UTL_SMTP.WRITE_DATA(CONN, LAST_BOUNDARY);
185     END IF;
186   END;
187 
188   ----------------------------------------------发送附件----------------------------------------------------
189 
190   PROCEDURE ATTACHMENT(CONN         IN OUT NOCOPY UTL_SMTP.CONNECTION,
191                        MIME_TYPE    IN VARCHAR2 DEFAULT text/plain,
192                        INLINE       IN BOOLEAN DEFAULT TRUE,
193                        FILENAME     IN VARCHAR2 DEFAULT t.txt,
194                        TRANSFER_ENC IN VARCHAR2 DEFAULT 7 bit,
195                        DT_NAME      IN VARCHAR2 DEFAULT 0) IS
196 
197     L_FILENAME VARCHAR2(1000);
198   BEGIN
199     --写附件头
200     UTL_SMTP.WRITE_DATA(CONN, FIRST_BOUNDARY);
201     --设置附件格式
202     WRITE_DATA(CONN, Content-Type, MIME_TYPE);
203     --如果文件名称非空,表示有附件
204     DROP_DIRECTORY(DT_NAME);
205     --创建directory
206     CREATE_DIRECTORY(DT_NAME, GET_FILE(FILENAME, 1));
207     --得到附件文件名称
208     L_FILENAME := GET_FILE(FILENAME, 2);
209     IF (INLINE) THEN
210       --WRITE_DATA(CONN, ‘Content-Disposition‘, ‘inline; filename="‘ ||
211       WRITE_DATA(CONN, Content-Disposition, inline; filename=" ||
212                   L_FILENAME || ");
213     ELSE
214       WRITE_DATA(CONN, Content-Disposition, attachment; filename=" ||
215                   L_FILENAME || ");
216     END IF;
217 
218     --设置附件的转换格式
219     IF (TRANSFER_ENC IS NOT NULL) THEN
220       WRITE_DATA(CONN, Content-Transfer-Encoding, TRANSFER_ENC);
221     END IF;
222 
223     UTL_SMTP.WRITE_DATA(CONN, UTL_TCP.CRLF);
224 
225     --begin 贴附件内容
226     IF TRANSFER_ENC = bit 7 THEN
227       --如果是文本类型的附件
228       BEGIN
229         L_FILE_HANDLE := UTL_FILE.FOPEN(DT_NAME, L_FILENAME, r); --打开文件
230         --把附件分成多份,这样可以发送超过32K的附件
231         LOOP
232           UTL_FILE.GET_LINE(L_FILE_HANDLE, L_LINE);
233           L_MESG := L_LINE || L_CRLF;
234           WRITE_DATA(CONN, ‘‘, L_MESG, ‘‘, ‘‘);
235         END LOOP;
236         UTL_FILE.FCLOSE(L_FILE_HANDLE);
237         END_BOUNDARY(CONN);
238       EXCEPTION
239         WHEN OTHERS THEN
240           UTL_FILE.FCLOSE(L_FILE_HANDLE);
241           END_BOUNDARY(CONN);
242           NULL;
243       END; --结束文本类型附件的处理
244 
245     ELSIF TRANSFER_ENC = base64 THEN
246       --如果是二进制类型的附件
247       BEGIN
248         --把附件分成多份,这样可以发送超过32K的附件
249         L_FILEPOS  := 1;--重置offset,在发送多个附件时,必须重置
250         L_FIL      := BFILENAME(DT_NAME, L_FILENAME);
251         L_FILE_LEN := DBMS_LOB.GETLENGTH(L_FIL);
252         L_MODULO   := MOD(L_FILE_LEN, L_AMT);
253         L_PIECES   := TRUNC(L_FILE_LEN / L_AMT);
254         IF (L_MODULO <> 0) THEN
255           L_PIECES := L_PIECES + 1;
256         END IF;
257         DBMS_LOB.FILEOPEN(L_FIL, DBMS_LOB.FILE_READONLY);
258         DBMS_LOB.READ(L_FIL, L_AMT, L_FILEPOS, L_BUF);
259         L_DATA := NULL;
260         FOR I IN 1 .. L_PIECES LOOP
261           L_FILEPOS  := I * L_AMT + 1;
262           L_FILE_LEN := L_FILE_LEN - L_AMT;
263           L_DATA     := UTL_RAW.CONCAT(L_DATA, L_BUF);
264           L_CHUNKS   := TRUNC(UTL_RAW.LENGTH(L_DATA) / L_MAX_LINE_WIDTH);
265           IF (I <> L_PIECES) THEN
266             L_CHUNKS := L_CHUNKS - 1;
267           END IF;
268           UTL_SMTP.WRITE_RAW_DATA(CONN, UTL_ENCODE.BASE64_ENCODE(L_DATA));
269           L_DATA := NULL;
270           IF (L_FILE_LEN < L_AMT AND L_FILE_LEN > 0) THEN
271             L_AMT := L_FILE_LEN;
272           END IF;
273           DBMS_LOB.READ(L_FIL, L_AMT, L_FILEPOS, L_BUF);
274         END LOOP;
275         DBMS_LOB.FILECLOSE(L_FIL);
276         END_BOUNDARY(CONN);
277       EXCEPTION
278         WHEN OTHERS THEN
279           DBMS_LOB.FILECLOSE(L_FIL);
280           END_BOUNDARY(CONN);
281           RAISE;
282       END; --结束处理二进制附件
283 
284     END IF; --结束处理附件内容
285     DROP_DIRECTORY(DT_NAME);
286   END; --结束过程ATTACHMENT
287 
288   ---------------------------------------------真正发送邮件的过程--------------------------------------------
289   PROCEDURE P_EMAIL(P_SENDORADDRESS2   VARCHAR2, --发送地址
290                     P_RECEIVERADDRESS2 VARCHAR2) --接受地址
291    IS
292     L_CONN UTL_SMTP.CONNECTION; --定义连接
293   BEGIN
294     /*初始化邮件服务器信息,连接邮件服务器*/
295     L_CONN := UTL_SMTP.OPEN_CONNECTION(P_SERVER, P_PORT);
296     UTL_SMTP.HELO(L_CONN, P_SERVER);
297     /* smtp服务器登录校验 */
298     IF P_NEED_SMTP = 1 THEN
299       UTL_SMTP.COMMAND(L_CONN, AUTH LOGIN, ‘‘);
300       UTL_SMTP.COMMAND(L_CONN, UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(P_USER))));
301       UTL_SMTP.COMMAND(L_CONN, UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(P_PASS))));
302     END IF;
303 
304     /*设置发送地址和接收地址*/
305     UTL_SMTP.MAIL(L_CONN, P_SENDORADDRESS2);
306     UTL_SMTP.RCPT(L_CONN, P_RECEIVERADDRESS2);
307 
308     /*设置邮件头*/
309     UTL_SMTP.OPEN_DATA(L_CONN);
310 
311     WRITE_DATA(L_CONN, Date, TO_CHAR(SYSDATE, yyyy-mm-dd hh24:mi:ss));
312     /*设置发送人*/
313     WRITE_DATA(L_CONN, From, P_SENDOR);
314     /*设置接收人*/
315     WRITE_DATA(L_CONN, To, P_RECEIVER);
316     /*设置邮件主题*/
317     WRITE_DATA(L_CONN, Subject, P_SUB);
318 
319     WRITE_DATA(L_CONN, Content-Type, MULTIPART_MIME_TYPE);
320     UTL_SMTP.WRITE_DATA(L_CONN, UTL_TCP.CRLF);
321     UTL_SMTP.WRITE_DATA(L_CONN, FIRST_BOUNDARY);
322     WRITE_DATA(L_CONN, Content-Type, text/plain;charset=gb2312);
323     --单独空一行,否则,正文内容不显示
324     UTL_SMTP.WRITE_DATA(L_CONN, UTL_TCP.CRLF);
325     /* 设置邮件正文
326       把分隔符还原成chr(10)。这主要是为了shell中调用该过程,如果有多行,则先把多行的内容合并成一行,并用 l_splite分隔
327       然后用 l_crlf替换chr(10)。这一步是必须的,否则将不能发送邮件正文有多行的邮件
328     */
329     WRITE_DATA(L_CONN, ‘‘, REPLACE(REPLACE(P_TXT, L_SPLITE, CHR(10)), CHR(10), L_CRLF), ‘‘, ‘‘);
330     END_BOUNDARY(L_CONN);
331 
332   --如果文件名称不为空,则发送附件
333     IF (P_FILENAME IS NOT NULL) THEN
334       --根据逗号或者分号拆分附件地址
335       P_SPLITE_STR(P_FILENAME, 2);
336       --循环发送附件(在同一个邮件中)
337       FOR K IN 1 .. MY_ACCT_LIST.COUNT LOOP
338         ATTACHMENT(CONN => L_CONN, FILENAME => MY_ACCT_LIST(K), TRANSFER_ENC => P_ENCODE, DT_NAME => L_DIRECTORY_BASE_NAME ||
339                                TO_CHAR(K));
340       END LOOP;
341     END IF;
342 
343     /*关闭数据写入*/
344     UTL_SMTP.CLOSE_DATA(L_CONN);
345     /*关闭连接*/
346     UTL_SMTP.QUIT(L_CONN);
347 
348     /*异常处理*/
349   EXCEPTION
350     WHEN OTHERS THEN
351       NULL;
352       RAISE;
353 
354   END;
355 
356   ---------------------------------------------------主过程-----------------------------------------------------
357 
358 BEGIN
359   L_SENDORADDRESS := < || P_SENDOR || >;
360   P_SPLITE_STR(P_RECEIVER);--处理邮件地址
361   FOR K IN 1 .. MY_ADDRESS_LIST.COUNT LOOP
362     P_EMAIL(L_SENDORADDRESS, MY_ADDRESS_LIST(K));
363   END LOOP;
364   /*处理邮件地址,根据逗号分割邮件*/
365 
366 EXCEPTION
367   WHEN OTHERS THEN
368     RAISE;
369 END;

注:需要相应的用户有相应的ACL权限,否则会报错

oracle发送邮件

标签:

原文地址:http://www.cnblogs.com/daisywong/p/4712210.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!