1 PACKAGE utl_smtp AUTHID CURRENT_USER AS
2
3 /*******************************************************************
4 * OVERVIEW
5 *
6 * This package provides SMTP client-side access functionality in PL/SQL.
7 * With this package, a PL/SQL program can send electronic mails via SMTP.
8 * This package does not allow the PL/SQL program to receive e-mails via
9 * SMTP. The user of this package should be familiar with the SMTP protocol
10 * as defined in RFC 821 and RFC 1869.
11 *
12 * This package is meant to provide an API to SMTP protocol directly. Users
13 * may find it useful to define additional helper routines to encapsulate
14 * the interaction with a SMTP server.
15 *
16 * USES
17 *
18 * A SMTP connection is initiated by a call to open_connection, which
19 * returns a SMTP connection. After a connection is established, the
20 * following calls are required to send a mail:
21 *
22 * helo() - identify the domain of the sender
23 * mail() - start a mail, specify the sender
24 * rcpt() - specify the recipient
25 * open_data() - start the mail body
26 * write_data() - write the mail body (multiple calls allowed)
27 * close_data() - close the mail body and send the mail
28 *
29 * The SMTP connection is closed by calling quit().
30 *
31 * A note on API style and raising PL/SQL exception:
32 *
33 * Most of the API has a function form and a procedure form. The function
34 * form returns the reply message after the command is sent, in the form
35 * of "XXX <an optional reply message>", where XXX is the reply code.
36 * The procedure form of the same API calls the function form of the API,
37 * checks the reply code and raises transient_error or permanent_error
38 * exception if the reply code is in 400 or 500 range. The function form
39 * of the API does not raise either of the 2 exceptions.
40 *
41 * All API may raise invalid_operation exception if it is called in either
42 * of the situations:
43 *
44 * 1. calling API other than write_data(), write_raw_data() or close_data()
45 * after open_data(0 is called, or
46 * 2. calling write_data(), write_raw_data() or close_data() without
47 * first calling open_data()
48 *
49 * EXAMPLES
50 * Retrieve the home page from http://www.acme.com/
51 *
52 * DECLARE
53 * c utl_smtp.connection;
54 *
55 * PROCEDURE send_header(name IN VARCHAR2, header IN VARCHAR2) AS
56 * BEGIN
57 * utl_smtp.write_data(c, name || ': ' || header || utl_tcp.CRLF);
58 * END;
59 *
60 * BEGIN
61 * c := utl_smtp.open_connection('smtp-server.acme.com');
62 * utl_smtp.helo(c, 'foo.com');
63 * utl_smtp.mail(c, '[email protected]');
64 * utl_smtp.rcpt(c, '[email protected]');
65 * utl_smtp.open_data(c);
66 * send_header('From', '"Sender" [email protected]>');
67 * send_header('To', '"Recipient" [email protected]>');
68 * send_header('Subject', 'Hello');
69 * utl_smtp.write_data(c, utl_tcp.CRLF || 'Hello, world!');
70 * utl_smtp.close_data(c);
71 * utl_smtp.quit(c);
72 * EXCEPTION
73 * WHEN utl_smtp.transient_error OR utl_smtp.permanent_error THEN
74 * BEGIN
75 * utl_smtp.quit(c);
76 * EXCEPTION
77 * WHEN utl_smtp.transient_error OR utl_smtp.permanent_error THEN
78 * NULL; -- When the SMTP server is down or unavailable, we don't
79 * -- have a connection to the server. The quit call will
80 * -- raise an exception that we can ignore.
81 * END;
82 * raise_application_error(-20000,
83 * 'Failed to send mail due to the following error: ' || sqlerrm);
84 * END;
85 */
86
87 /*
88 * SMTP connection type
89 */
90 TYPE connection IS RECORD (
91 host VARCHAR2(255), -- Host name of SMTP server
92 port PLS_INTEGER, -- Port number of SMTP server
93 tx_timeout PLS_INTEGER, -- Transfer time-out (in seconds)
94 private_tcp_con utl_tcp.connection, -- For internal use only
95 private_state PLS_INTEGER -- For internal use only
96 );
97
98 /*
99 * SMTP reply structure
100 */
101 TYPE reply IS RECORD (
102 code PLS_INTEGER, -- 3-digit reply code
103 text VARCHAR2(508) -- reply text
104 );
105 -- multiple reply lines
106 TYPE replies IS TABLE OF reply INDEX BY BINARY_INTEGER;
107
108 /*
109 * Exceptions
110 */
111 invalid_operation EXCEPTION; -- Operation is invalid
112 transient_error EXCEPTION; -- Transient server error in 400 range
113 permanent_error EXCEPTION; -- Permanent server error in 500 range
114 unsupported_scheme EXCEPTION; -- Unsupported authentication scheme
115 no_supported_scheme EXCEPTION; -- No supported authentication scheme
116 invalid_operation_errcode CONSTANT PLS_INTEGER:= -29277;
117 transient_error_errcode CONSTANT PLS_INTEGER:= -29278;
118 permanent_error_errcode CONSTANT PLS_INTEGER:= -29279;
119 unsupported_scheme_errcode CONSTANT PLS_INTEGER:= -24249;
120 no_supported_scheme_errcode CONSTANT PLS_INTEGER:= -24250;
121 PRAGMA EXCEPTION_INIT(invalid_operation, -29277);
122 PRAGMA EXCEPTION_INIT(transient_error, -29278);
123 PRAGMA EXCEPTION_INIT(permanent_error, -29279);
124 PRAGMA EXCEPTION_INIT(unsupported_scheme, -24249);
125 PRAGMA EXCEPTION_INIT(no_supported_scheme, -24250);
126
127 /*
128 * SMTP authentication schemes for use with the AUTH API.
129 *
130 * UTL_SMTP may support additional authentication schemes in the future and
131 * these strings will change accordingly.
132 */
133
134 /* The list of all authentication schemes that UTL_SMTP supports, in the
135 * order of their relative security strength. This list contains some
136 * schemes in which cleartext passwords are sent over SMTP. They should be
137 * used only in SMTP connections that are secured by Secure Scoket Layer /
138 * Transport Layer Security (SSL/TLS).
139 */
140 ALL_SCHEMES CONSTANT VARCHAR2(80) := 'CRAM-MD5 PLAIN LOGIN';
141
142 /* The list of authentication schemes that UTL_SMTP supports and in which
143 * no cleartext passwords are sent over SMTP. They may be used in SMTP
144 * connections that are not secured by SSL/TLS. Note that these schemes
145 * may still be weak when used in an insecure SMTP connection.
146 */
147 NON_CLEARTEXT_PASSWORD_SCHEMES CONSTANT VARCHAR2(80) := 'CRAM-MD5';
148
149 /**
150 * Opens a SMTP connection to a SMTP server. When connection is made
151 * succesfully, the SMTP host name and port number will be stored in
152 * the connection.
153 *
154 * Communication with the SMTP server may be secured using Secure Socket
155 * Layer / Transport Layer Security (SSL/TLS). To start SSL/TLS in the
156 * connection, the user must specify an Oracle wallet when opening the
157 * connection. The wallet must contain the trusted certificate of the
158 * certificate authority who signs the remote server's certificate for
159 * UTL_SMTP to validate the remote server's certificate.
160 *
161 * There are two ways SSL/TLS may be started in SMTP. In the first way,
162 * SSL/TLS is started before any SMTP communication. To connect to a SMTP
163 * server port configured this way (port 465 by convention), set
164 * secure_connection_before_smtp to TRUE.
165 *
166 * In the second way, initial SMTP handshake is done in an insecure
167 * connection and SSL/TLS is started by the STARTTLS command. To connect to
168 * a SMTP server port configured this way (port 25 or 587 by convention),
169 * set secure_connection_before_smtp to FALSE and call the STARTTLS
170 * function/procedure. See STARTTLS for details.
171 *
172 * UTL_SMTP supports client authentication over SSL/TLS using the client
173 * certificate in the wallet. The client certificate will be sent to the
174 * remote server if it is present in the wallet and if the caller has the
175 * "use-client-certificates" ACL privilege on the wallet.
176 *
177 * For more information on Oracle wallets, see Oracle Wallet Manager
178 * documentation.
179 *
180 * PARAMETERS
181 * host SMTP host name to connect to
182 * port port number of the SMTP server to connect to
183 * c SMTP connection (OUT)
184 * tx_timeout a time in seconds this package should wait before
185 * giving up in a read or write operation in this
186 * connection. In read operations, this package will give
187 * up if no data is available for reading immediately.
188 * In write operations, this package will give if the
189 * output buffer is full and no data be sent in the
190 * network without being blocked. 0 indicates not to wait
191 * at all. NULL indicates to wait forever.
192 * wallet_path the directory path that contains the Oracle wallet for
193 * SSL/TLS. The format is "file:<directory-path>".
194 * wallet_password the password to open the wallet. When the wallet is
195 * auto-login enabled, the password may be set to NULL.
196 * secure_connection_before_smtp if TRUE, secure the connection with
197 * SSL/TLS before SMTP communication, else not.
198 * RETURN
199 * SMTP connection when connection is established, or
200 * the SMTP reply (welcome) message
201 * EXCEPTIONS
202 * transient_error - transient server error
203 * permanent_error - permanent server error
204 * invalid_operation - invalid operation
205 * NOTES
206 * Time-out on write operations is not supported in the current release
207 * of this package.
208 */
209 FUNCTION open_connection(host IN VARCHAR2,
210 port IN PLS_INTEGER DEFAULT 25,
211 c OUT connection,
212 tx_timeout IN PLS_INTEGER DEFAULT NULL,
213 wallet_path IN VARCHAR2 DEFAULT NULL,
214 wallet_password IN VARCHAR2 DEFAULT NULL,
215 secure_connection_before_smtp IN BOOLEAN
216 DEFAULT FALSE)
217 RETURN reply;
218 FUNCTION open_connection(host IN VARCHAR2,
219 port IN PLS_INTEGER DEFAULT 25,
220 tx_timeout IN PLS_INTEGER DEFAULT NULL,
221 wallet_path IN VARCHAR2 DEFAULT NULL,
222 wallet_password IN VARCHAR2 DEFAULT NULL,
223 secure_connection_before_smtp IN BOOLEAN
224 DEFAULT FALSE)
225 RETURN connection;
226
227 /**
228 * Sends a generic SMTP command and retrieves a single reply line. If
229 * multiple reply lines are returned from the SMTP server, the last reply
230 * line is returned.
231 *
232 * PARAMETERS
233 * c SMTP connection
234 * cmd SMTP command
235 * arg optional argument to the SMTP command
236 * RETURN
237 * the SMTP reply
238 * EXCEPTIONS
239 * transient_error - transient server error
240 * permanent_error - permanent server error
241 * invalid_operation - invalid operation
242 */
243 FUNCTION command(c IN OUT NOCOPY connection,
244 cmd IN VARCHAR2,
245 arg IN VARCHAR2 DEFAULT NULL)
246 RETURN reply;
247 PROCEDURE command(c IN OUT NOCOPY connection,
248 cmd IN VARCHAR2,
249 arg IN VARCHAR2 DEFAULT NULL);
250
251 /**
252 * Sends a generic SMTP command and retrieves multiple reply lines.
253 *
254 * PARAMETERS
255 * c SMTP connection
256 * cmd SMTP command
257 * arg optional argument to the SMTP command
258 * RETURN
259 * the SMTP reply
260 * EXCEPTIONS
261 * invalid_operation - invalid operation
262 */
263 FUNCTION command_replies(c IN OUT NOCOPY connection,
264 cmd IN VARCHAR2,
265 arg IN VARCHAR2 DEFAULT NULL)
266 RETURN replies;
267
268 /**
269 * Sends HELO command.
270 *
271 * PARAMETERS
272 * c SMTP connection
273 * domain domain of the sender
274 * RETURN
275 * the SMTP reply
276 * EXCEPTIONS
277 * transient_error - transient server error
278 * permanent_error - permanent server error
279 * invalid_operation - invalid operation
280 */
281 FUNCTION helo(c IN OUT NOCOPY connection,
282 domain IN VARCHAR2) RETURN reply;
283 PROCEDURE helo(c IN OUT NOCOPY connection,
284 domain IN VARCHAR2);
285
286 /**
287 * Sends EHLO command.
288 *
289 * PARAMETERS
290 * c SMTP connection
291 * domain domain of the sender
292 * RETURN
293 * the SMTP reply
294 * EXCEPTIONS
295 * transient_error - transient server error
296 * permanent_error - permanent server error
297 * invalid_operation - invalid operation
298 */
299 FUNCTION ehlo(c IN OUT NOCOPY connection,
300 domain IN VARCHAR2) RETURN replies;
301 PROCEDURE ehlo(c IN OUT NOCOPY connection,
302 domain IN VARCHAR2);
303
304 /**
305 * Sends STARTTLS command to secure the SMTP connection using SSL/TLS.
306 * SSL/TLS requires an Oracle wallet which should be specified when the
307 * connection was opened by the open_connection function.
308 *
309 * PARAMETERS
310 * c SMTP connection
311 * RETURN
312 * the SMTP reply
313 * EXCEPTIONS
314 * transient_error - transient server error
315 * permanent_error - permanent server error
316 * invalid_operation - invalid operation
317 */
318 FUNCTION starttls(c IN OUT NOCOPY connection) RETURN reply;
319 PROCEDURE starttls(c IN OUT NOCOPY connection);
320
321 /**
322 * Sends AUTH command to authenticate to the SMTP server. The UTL_SMTP
323 * package will go through the user's choices of authentication schemes,
324 * skip any that is not supported by the SMTP server and use the first one
325 * supported. To determine the schemes the SMTP server supports from its
326 * EHLO reply, the user must call the EHLO function/procedure first.
327 * Otherwise, UTL_SMTP will use the first scheme in the list.
328 *
329 * PARAMETERS
330 * c SMTP connection
331 * username the username
332 * password the password
333 * schemes the list of space-separated authentication schemes to use
334 * in the preferred order. See the ALL_SCHEMES and
335 * NON_CLEARTEXT_PASSWORD_SCHEMES constants for suggestions.
336 * RETURN
337 * the SMTP reply
338 * EXCEPTIONS
339 * transient_error - transient server error
340 * permanent_error - permanent server error
341 * invalid_operation - invalid operation
342 * bad_argument - no supported authentication scheme found
343 * NOTES
344 * Currently only PLAIN, LOGIN and CRAM-MD5 authentication schemes are
345 * supported by UTL_SMTP.
346 * Since the SMTP server may change the authentication schemes it supports
347 * after the SMTP connection is secured by SSL/TLS after the STARTTLS command
348 * (for example, adding PLAIN and LOGIN), the caller should call the EHLO
349 * function/procedure again for UTL_SMTP to update the list after the
350 * STARTTLS function/procedure is called.
351 */
352 FUNCTION auth(c IN OUT NOCOPY connection,
353 username IN VARCHAR2,
354 password IN VARCHAR2,
355 schemes IN VARCHAR2
356 DEFAULT NON_CLEARTEXT_PASSWORD_SCHEMES)
357 RETURN reply;
358 PROCEDURE auth(c IN OUT NOCOPY connection,
359 username IN VARCHAR2,
360 password IN VARCHAR2,
361 schemes IN VARCHAR2
362 DEFAULT NON_CLEARTEXT_PASSWORD_SCHEMES);
363 /**
364 * Sends MAIL command.
365 *
366 * PARAMETERS
367 * c SMTP connection
368 * sender the sender
369 * parameters the optional parameters to MAIL command
370 * RETURN
371 * the SMTP reply
372 * EXCEPTIONS
373 * transient_error - transient server error
374 * permanent_error - permanent server error
375 * invalid_operation - invalid operation
376 */
377 FUNCTION mail(c IN OUT NOCOPY connection,
378 sender IN VARCHAR2,
379 parameters IN VARCHAR2 DEFAULT NULL) RETURN reply;
380 PROCEDURE mail(c IN OUT NOCOPY connection,
381 sender IN VARCHAR2,
382 parameters IN VARCHAR2 DEFAULT NULL);
383
384 /**
385 * Sends RCPT command.
386 *
387 * PARAMETERS
388 * c SMTP connection
389 * recipient the recipient
390 * parameters the optional parameters to RCPT command
391 * RETURN
392 * the SMTP reply
393 * EXCEPTIONS
394 * transient_error - transient server error
395 * permanent_error - permanent server error
396 * invalid_operation - invalid operation
397 */
398 FUNCTION rcpt(c IN OUT NOCOPY connection,
399 recipient IN VARCHAR2,
400 parameters IN VARCHAR2 DEFAULT NULL) RETURN reply;
401 PROCEDURE rcpt(c IN OUT NOCOPY connection,
402 recipient IN VARCHAR2,
403 parameters IN VARCHAR2 DEFAULT NULL);
404
405 /**
406 * Sends DATA command. The data will be closed by the sequence
407 * <CR><LF>.<CR><LF>
408 *
409 * PARAMETERS
410 * c SMTP connection
411 * body the data body
412 * RETURN
413 * the SMTP reply after the sequence <CR><LF>.<CR><LF> is sent
414 * EXCEPTIONS
415 * transient_error - transient server error
416 * permanent_error - permanent server error
417 * invalid_operation - invalid operation
418 */
419 FUNCTION data(c IN OUT NOCOPY connection,
420 body IN VARCHAR2 CHARACTER SET ANY_CS)
421 RETURN reply;
422 PROCEDURE data(c IN OUT NOCOPY connection,
423 body IN VARCHAR2 CHARACTER SET ANY_CS);
424
425 /**
426 * Sends DATA command. This call opens the data session that the
427 * caller make subsequent write_data() calls to write large piece of
428 * data, following by close_data() to close the data session.
429 *
430 * PARAMETERS
431 * c SMTP connection
432 * RETURN
433 * the SMTP reply
434 * EXCEPTIONS
435 * transient_error - transient server error
436 * permanent_error - permanent server error
437 * invalid_operation - invalid operation
438 */
439 FUNCTION open_data(c IN OUT NOCOPY connection) RETURN reply;
440 PROCEDURE open_data(c IN OUT NOCOPY connection);
441
442 /**
443 * Sends data. This call must be preceeded by the call open_data().
444 *
445 * PARAMETERS
446 * c SMTP connection
447 * data the data body
448 * RETURN
449 * None
450 * EXCEPTIONS
451 * invalid_operation - invalid operation
452 */
453 PROCEDURE write_data(c IN OUT NOCOPY connection,
454 data IN VARCHAR2 CHARACTER SET ANY_CS);
455 PROCEDURE write_raw_data(c IN OUT NOCOPY connection,
456 data IN RAW);
457
458 /**
459 * Sends DATA command. This call opens the data session that the
460 * caller make subsequent write_data() calls to write large piece of
461 * data, following by close_data() to close the data session.
462 *
463 * PARAMETERS
464 * c SMTP connection
465 * RETURN
466 * the SMTP reply
467 * EXCEPTIONS
468 * transient_error - transient server error
469 * permanent_error - permanent server error
470 * invalid_operation - invalid operation
471 */
472 FUNCTION close_data(c IN OUT NOCOPY connection) RETURN reply;
473 PROCEDURE close_data(c IN OUT NOCOPY connection);
474
475 /**
476 * Sends RSET command.
477 *
478 * PARAMETERS
479 * c SMTP connection
480 * RETURN
481 * the SMTP reply
482 * EXCEPTIONS
483 * transient_error - transient server error
484 * permanent_error - permanent server error
485 * invalid_operation - invalid operation
486 */
487 FUNCTION rset(c IN OUT NOCOPY connection) RETURN reply;
488 PROCEDURE rset(c IN OUT NOCOPY connection);
489
490 /**
491 * Sends VRFY command.
492 *
493 * PARAMETERS
494 * c SMTP connection
495 * recipient the reccipient to verify
496 * RETURN
497 * the SMTP reply
498 * EXCEPTIONS
499 * invalid_operation - invalid operation
500 */
501 FUNCTION vrfy(c IN OUT NOCOPY connection,
502 recipient IN VARCHAR2) RETURN reply;
503
504 /**
505 * Sends HELP command.
506 *
507 * PARAMETERS
508 * c SMTP connection
509 * command the command to get help message
510 * RETURN
511 * the SMTP reply
512 * EXCEPTIONS
513 * invalid_operation - invalid operation
514 */
515 FUNCTION help(c IN OUT NOCOPY connection,
516 command IN VARCHAR2 DEFAULT NULL) RETURN replies;
517
518 /**
519 * Sends NOOP command.
520 *
521 * PARAMETERS
522 * c SMTP connection
523 * RETURN
524 * the SMTP reply
525 * EXCEPTIONS
526 * transient_error - transient server error
527 * permanent_error - permanent server error
528 * invalid_operation - invalid operation
529 */
530 FUNCTION noop(c IN OUT NOCOPY connection) RETURN reply;
531 PROCEDURE noop(c IN OUT NOCOPY connection);
532
533 /**
534 * Sends QUIT command and closes the SMTP connection.
535 *
536 * PARAMETERS
537 * c SMTP connection
538 * RETURN
539 * the SMTP reply
540 * EXCEPTIONS
541 * transient_error - transient server error
542 * permanent_error - permanent server error
543 * invalid_operation - invalid operation
544 */
545 FUNCTION quit(c IN OUT NOCOPY connection) RETURN reply;
546 PROCEDURE quit(c IN OUT NOCOPY connection);
547
548 /**
549 * Closes the SMTP connection. It will cause the current SMTP operation to
550 * be aborted. Use this procedure only to abort an email in the middle of
551 * the data session. To end the SMTP connection properly, use the quit() API
552 * instead.
553 *
554 * PARAMETERS
555 * c SMTP connection
556 * RETURN
557 * None
558 * EXCEPTIONS
559 * None
560 */
561 PROCEDURE close_connection(c IN OUT NOCOPY connection);
562
563 END;