Hola,
1. Soy un poco vago para programar, asi que cualquier mejora que veas posteala por aqui.
2. El paquete no tiene mucha funcionalidad, por ejemplo no se puede enviar adjuntos, pero cubre las necesidades que tenia.
3. El parser de direcciones de correo de destino puede que tenga algun bug, ahora no me acuerdo.
4. El tamaño maximo del body, creo, es menor al permitido para varchar2 en PL/SQL.
5. El manejo de exception es malo, puedes mejorarlo tranquilamente.
6. El codigo esta adaptado para este post, algunas cosas quite o renombre, puede que tenga algun error, testealo bien.
Definicion del Paquete.
Código:
CREATE OR REPLACE PACKAGE smtpMail
IS
--Información para el envío de correo
smtp_to VARCHAR2(900) := '';
smtp_from VARCHAR2(900) := '';
smtp_server VARCHAR2(256) := '';
smtp_to_cc VARCHAR2(900) := '';
smtp_to_bcc VARCHAR2(900) := '';
smtp_subject VARCHAR2(900) := '';
smtp_port NUMBER(4) := 25;
--Autenticación SMTP
smtp_auth BOOLEAN NOT NULL := FALSE;
smtp_user VARCHAR2(64) := '';
smtp_pass VARCHAR2(64) := '';
procedure smMailSend(lsz_body VARCHAR2);
END;
Cuerpo del paquete.
Código:
CREATE OR REPLACE PACKAGE BODY smtpMail
IS
TYPE IList IS TABLE OF VARCHAR2(300);
FUNCTION smMailList (
lsz_data VARCHAR2,
lsz_add_list OUT smtpMail.IList,
lsz_add_str OUT VARCHAR2
)
RETURN NUMBER
IS
i NUMBER(10) := 1;
sz_data VARCHAR2(900) := NULL;
sz_address VARCHAR2(300) := NULL;
sz_cb CONSTANT CHAR(1) := CHR(60);
sz_ce CONSTANT CHAR(1) := CHR(62);
BEGIN
sz_data := lsz_data;
lsz_add_list := smtpMail.IList();
WHILE ( LENGTH(sz_data) > 0 ) LOOP
sz_address := SUBSTR(
sz_data,
1,
CASE
WHEN INSTR(sz_data,',',1,1) = 0 THEN LENGTH(sz_data)
ELSE INSTR(sz_data,',',1,1) - 1
END
);
sz_data := REPLACE(sz_data, sz_address || ',', NULL);
sz_data := REPLACE(sz_data, sz_address, NULL);
lsz_add_list.extend(1);
lsz_add_list(i) := sz_address;
lsz_add_str := lsz_add_str || sz_cb || sz_address || sz_ce || ',';
i := i + 1;
END LOOP;
lsz_add_str := SUBSTR(lsz_add_str,1,LENGTH(lsz_add_str) - 1);
RETURN 0;
EXCEPTION
WHEN OTHERS THEN
RETURN SQLCODE;
END;
PROCEDURE smMailSend (lsz_body VARCHAR2)
IS
sz_to VARCHAR2(900) := NULL;
sz_from VARCHAR2(900) := NULL;
sz_server VARCHAR2(256) := NULL;
sz_to_cc VARCHAR2(900) := NULL;
sz_to_bcc VARCHAR2(900) := NULL;
sz_subject VARCHAR2(900) := NULL;
b_auth BOOLEAN := NULL;
sz_user VARCHAR2(64) := NULL;
sz_pass VARCHAR2(64) := NULL;
nv_port NUMBER(4) := 25;
sz_header VARCHAR2(3000) := NULL;
crlf VARCHAR2(2) := CHR( 13 ) || CHR( 10 );
--Listas de direcciones
sz_to_list smtpMail.IList := Ilist();
sz_to_cc_list smtpMail.IList := Ilist();
sz_to_bcc_list smtpMail.IList := Ilist();
sz_to_list_str VARCHAR2(900) := NULL;
sz_to_cc_list_str VARCHAR2(900) := NULL;
sz_to_bcc_list_str VARCHAR2(900) := NULL;
--connection and replay smtp
c UTL_SMTP.CONNECTION;
r UTL_SMTP.REPLY;
--support
i NUMBER(10) := 1;
nv_result NUMBER(10) := NULL;
BEGIN
--obligatorias
sz_to := TRIM(smtpMail.smtp_to);
sz_from := TRIM(smtpMail.smtp_from);
sz_server := TRIM(smtpMail.smtp_server);
--opcionales
sz_to_cc := TRIM(smtpMail.smtp_to_cc);
sz_to_bcc := TRIM(smtpMail.smtp_to_bcc);
sz_subject := TRIM(smtpMail.smtp_subject);
--autenticacion
b_auth := smtpMail.smtp_auth;
sz_user := TRIM(smtpMail.smtp_user);
sz_pass := TRIM(smtpMail.smtp_pass);
--puerto smtp
nv_port := NVL(smtpMail.smtp_port,25);
IF (sz_to IS NOT NULL AND sz_from IS NOT NULL AND sz_server IS NOT NULL) THEN
BEGIN
--Conexión y handshake con el servidor de correo
c := UTL_SMTP.OPEN_CONNECTION(sz_server, nv_port);
r := UTL_SMTP.HELO(c, sz_server);
--Dirección de Origen
r := UTL_SMTP.MAIL(c, sz_from);
--Autenticacion SMTP
IF ( b_auth ) THEN
r := UTL_SMTP.COMMAND(c, 'AUTH LOGIN');
IF ( r.code != 334 ) THEN
dbms_output.put_line('Autenticación Básica SMTP (auth login) no esta soportada por el servidor de correo');
END IF;
r := UTL_SMTP.COMMAND(c, UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(sz_user))));
r := UTL_SMTP.COMMAND(c, UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(sz_pass))));
END IF;
--Dirección de Destino - To
i := 1;
nv_result := smMailList(sz_to, sz_to_list, sz_to_list_str);
IF ( nv_result = 0 ) THEN
WHILE ( i <= sz_to_list.COUNT ) LOOP
r := UTL_SMTP.RCPT(c, sz_to_list(i));
i := i + 1;
END LOOP;
ELSE
DBMS_OUTPUT.put_line('Error en Direcciones To');
dbms_output.put_line(SQLERRM(nv_result));
END IF;
--Dirección de Destino con Copia - CC
i := 1;
nv_result := smMailList(sz_to_cc, sz_to_cc_list, sz_to_cc_list_str);
IF ( nv_result = 0 ) THEN
WHILE ( i <= sz_to_cc_list.COUNT ) LOOP
r := UTL_SMTP.RCPT(c, sz_to_cc_list(i));
i := i + 1;
END LOOP;
ELSE
DBMS_OUTPUT.put_line('Error en Direcciones Cc');
DBMS_OUTPUT.put_line(SQLERRM(nv_result));
END IF;
--Dirección de Destino con Copia Oculta - BCC
i := 1;
nv_result := smMailList(sz_to_bcc, sz_to_bcc_list, sz_to_bcc_list_str);
IF ( nv_result = 0 ) THEN
WHILE ( i <= sz_to_bcc_list.COUNT ) LOOP
r := UTL_SMTP.RCPT(c, sz_to_bcc_list(i));
i := i + 1;
END LOOP;
ELSE
DBMS_OUTPUT.put_line('Error en Direcciones Bcc');
dbms_output.put_line(SQLERRM(nv_result));
END IF;
--Header del mensaje - RFC 822
sz_header :='Date: ' || TO_CHAR( SYSDATE, 'dd Mon yy hh24:mi:ss' ) || crlf ||
'From: '|| sz_from || crlf ||
'Subject: ' || sz_subject || crlf ||
'To: ' || sz_to_list_str || crlf ;
IF ( LENGTH(sz_to_cc_list_str) > 0 ) THEN
sz_header := sz_header ||
'Cc: ' || sz_to_cc_list_str || crlf;
END IF;
IF ( LENGTH(sz_to_bcc_list_str) > 0 ) THEN
sz_header := sz_header ||
'Bcc: ' || sz_to_bcc_list_str || crlf;
END IF;
--Body del mensaje: lsz_body
--Envío de datos al servidor de correo y cierre de la conexión
r := UTL_SMTP.DATA(c, sz_header || lsz_body);
r := UTL_SMTP.QUIT(c);
dbms_output.put_line('');
dbms_output.put_line('Mensaje Enviado');
dbms_output.put_line(sz_header);
EXCEPTION
WHEN UTL_SMTP.INVALID_OPERATION THEN
dbms_output.put_line(SQLERRM);
r := UTL_SMTP.QUIT(c);
WHEN UTL_SMTP.TRANSIENT_ERROR THEN
dbms_output.put_line(SQLERRM);
r := UTL_SMTP.QUIT(c);
WHEN UTL_SMTP.PERMANENT_ERROR THEN
dbms_output.put_line(SQLERRM);
r := UTL_SMTP.QUIT(c);
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
r := UTL_SMTP.QUIT(c);
END;
ELSE
dbms_output.put_line('Error en la configuración de correo: ');
dbms_output.put_line(' Servidor SMTP : ' || CHR(39) || sz_server || CHR(39) );
dbms_output.put_line(' Puerto SMTP : ' || CHR(39) || TO_CHAR(nv_port) || CHR(39) );
dbms_output.put_line(' Cuenta Destino (TO) : ' || CHR(39) || sz_to || CHR(39) );
dbms_output.put_line(' Cuenta Origen (FROM) : ' || CHR(39) || sz_from || CHR(39) );
END IF;
END;
END;
Un ejemplo de la llamada puede ser.
Código:
set serveroutput on size 10000
BEGIN
smtpMail.smtp_to := '[email protected],[email protected]';
smtpMail.smtp_subject := 'Prueba';
smtpMail.smtp_from := '[email protected]';
smtpMail.smtp_server := 'server.dominio.es';
smtpMail.smtp_port := 25;
smtpMail.smtp_auth := FALSE;
smtpMail.smtp_user := 'User';
smtpMail.smtp_pass := 'Pass';
smtpMail.smMailSend('Hola Mundo!');
END;
/
Saludos