Ver Mensaje Individual
  #8 (permalink)  
Antiguo 11/02/2008, 09:19
Avatar de matanga
matanga
 
Fecha de Ingreso: octubre-2007
Ubicación: España
Mensajes: 1.091
Antigüedad: 17 años
Puntos: 85
Re: Ayuda con UTL_SMTP

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