miércoles, 18 de abril de 2012

Envío de Correos utilizando UTL_SMTP


Nueva Versión!
Se ha publicado una actualización al procedimiento en el siguiente enlace

Puedes seguir leyendo este post como referencia.

Desde que inicié en el mundo Oracle, me he encontrado con muchas implementaciones que te permiten hacer ciertos procesos desde la BD sin necesidad de hacerlos desde un programa externo. En esta ocasión veremos el envío de correos.

Tanto en la documentación de Oracle como en la web encontrarás muchos ejemplos y documentación, sin embargo ninguno (creo yo aplicado a un entorno real) y sin "partes ocultas".

A continuación mostraré un procedimiento que utiliza el package UTL_SMTP con el cual se pueden enviar correos a múltiples destinatarios en el Para, CC y CCO, así como múltiples adjuntos.

He de mencionar que tiene sus requerimientos.

  1. La lista de destinatarios y de archivos debe estar separadas por punto y coma (;) y sin espacios entre ellos (esta condición la pueden cambiar modificando el fuente), Ejemplo: 'usuario.uno@dominio.com;usuario.dos@dominio.dos.mx;usuario.tres@otrodominio.com'
  2. El procedimiento hace uso de un directorio lógico en donde se alojan los archivos a adjuntar, por lo que es necesario creen el directorio con el nombre que requieran en su BD y ahi coloquen los archivos.
  3. Se debe especificar el tipo de correo, ya sea HTML (en el parametro se coloca 'HTML') o Texto, que es el valor por default.
Ya con esto aclarado y recordandoles que hay comentarios dentro del código, puedo decirles que con este ejemplo pueden basarse para hacer uno sin envío de adjuntos (innecesario para mi gusto, pues con el solo hecho de mandar la cadena vacía, no se manda nada).


create or replace procedure P_SendMailAttach

(

p_DestinatariosPara     VARCHAR2, 

p_DestinatariosCC       VARCHAR2 DEFAULT NULL,

p_DestinatariosBcc      VARCHAR2 DEFAULT NULL,
p_Mensaje               VARCHAR2 DEFAULT 'Haga caso omiso a este mensaje',
p_Remitente             VARCHAR2 DEFAULT 'usuario@midominio',
p_Asunto                VARCHAR2 DEFAULT 'Este correo no tiene asunto',
p_TipoMensaje           VARCHAR2 DEFAULT 'TEXT',
p_Directorio            VARCHAR2 DEFAULT 'ATTACHMENTS', -- Directorio lógico por default
p_ArchivosAdjuntos      VARCHAR2
)
AS

-- ----------------------------------------------------------------------------------------------
-- Nombre            : P_SendMailAttach
-- Autor             : Ing. Rogelio "Wazu" Rodriguez
-- Descripcion       : Envio de correos utilizando el package UTL_SMTP
-- Requerimientos    : UTL_SMTP
-- Restricciones     :
-- Revisiones:
--   Fecha        Desarrollador                 Cambio
--   ===========  ========================      =================================================
--   03-APR-2012  Rogelio Wazu Rodriguez        Creación Inicial
--   30-JUL-2012  Rogelio Wazu Rodriguez        Se modifica en el procedure
                                                file_attach en content transfer
                                                sea después de Disposition
-- ----------------------------------------------------------------------------------------------

c utl_smtp.connection;

--Procedimiento para escritura de Headers
-----------------------------------------------------------------
PROCEDURE send_header(name IN VARCHAR2, header IN VARCHAR2) AS 
BEGIN 
utl_smtp.write_data(c, name || ': ' || header || utl_tcp.CRLF); 
END;
-----------------------------------------------------------------



--Procedimiento para Adición de Destinatarios
-----------------------------------------------------------------------------------------------------------------------------------
PROCEDURE add_rcpt(p_Destinatarios in VARCHAR2) AS
l_Cadena varchar2(500) := p_Destinatarios;
l_LargoCadena number;
l_Comas number;
l_PosicionComa number := 0;
l_Destinatario varchar2(100);
BEGIN

l_LargoCadena := length(l_Cadena);
l_Comas := l_LargoCadena-length(replace(l_Cadena,';'));

--Bloque 1 Asginación del RCPT
    IF l_Comas > 0 THEN
          FOR l_segmento IN 1 .. l_Comas LOOP
            
              l_Destinatario := substr(l_Cadena, l_PosicionComa + 1, instr(l_Cadena,';',1,l_segmento) - (l_PosicionComa + 1));
            
              l_PosicionComa := instr(l_Cadena,';',1,l_Segmento);
              utl_smtp.rcpt(c, l_Destinatario);
              
          END LOOP;
    END IF;
-- Fin de Bloque 1

-- Bloque 2: Para inserción del ultimo recipient solicitado (o el primero, si es unico)
    l_Destinatario := substr(l_Cadena, l_PosicionComa + 1, l_LargoCadena);
    utl_smtp.rcpt(c, l_Destinatario);
-- Fin Bloque 2  

END;
---------------------------------------------------------------------------------------------------------------------------------


-- Procedimiento de adición de cabeceras para destinatarios
---------------------------------------------------------------------------------------------------------------------------------
PROCEDURE add_headers_rcpt(p_Destinatarios IN VARCHAR2, p_Type IN VARCHAR2) AS
l_Cadena varchar2(500) := p_Destinatarios;
l_LargoCadena number;
l_Comas number;
l_PosicionComa number := 0;
l_Destinatario varchar2(100);
BEGIN

l_LargoCadena := length(l_Cadena);
l_Comas := l_LargoCadena-length(replace(l_Cadena,';'));

--Bloque 1 Asginación del Destinatario al header
    IF l_Comas > 0 THEN
          FOR l_segmento IN 1 .. l_Comas LOOP
            
              l_Destinatario := substr(l_Cadena, l_PosicionComa + 1, instr(l_Cadena,';',1,l_segmento) - (l_PosicionComa + 1));
            
              l_PosicionComa := instr(l_Cadena,';',1,l_Segmento);
              
              -- Se generan los encabezados para envio, en caso de Bcc no se agrega el Header
              IF p_Type = 'TO' THEN
                send_header('To', l_Destinatario);
              ELSE
                send_header('Cc', l_Destinatario);
              END IF;
              
          END LOOP;
    END IF;
-- Fin de Bloque 1

-- Bloque 2: Para inserción del ultimo recipient solicitado (o el primero, si es unico)
    l_Destinatario := substr(l_Cadena, l_PosicionComa + 1, l_LargoCadena);
    IF p_Type = 'TO' THEN
       send_header('To', l_Destinatario);
    ELSE
       send_header('Cc', l_Destinatario);
    END IF;
-- Fin Bloque 2  

END;
----------------------------------------------------------------------------------------------------------------------------------------------


-- Procedimiento para adjuntar los archivos al stream del correo
---------------------------------------------------------------------------------------------------------------------
PROCEDURE file_attach(p_Archivo varchar2) AS
-- Variables para el procesamiento de Archivos
 rfile     RAW(57);
 flen      NUMBER;
 bsize     NUMBER;
 src_file  bfile;
 buffer_   integer := 57;
 i         integer := 1;
BEGIN

    -- Escribir cabecera MIME
    utl_smtp.write_data(c,'--MIME.Bound'||utl_tcp.CRLF);
    send_header('Content-Type','application/octet-stream; name="' || p_Archivo || '"');
    send_header('Content-Disposition', 'attachment; filename="' || p_Archivo || '"');
    send_header('Content-Transfer-Encoding', 'base64' );
    utl_smtp.write_data(c, utl_tcp.CRLF);
              
    -- Adición del Archivo 
    src_file := bfilename(p_Directorio, p_Archivo); 
              flen := dbms_lob.getlength(src_file);
              
              dbms_lob.fileopen(src_file, dbms_lob.file_readonly);
              
              while i < flen loop
                    dbms_lob.read( src_file, buffer_, i, rfile );
                    utl_smtp.write_raw_data(c, utl_encode.base64_encode(rfile));
                    utl_smtp.write_data(c, utl_tcp.CRLF);
                    i := i + buffer_;
              end loop while_loop;
              
              dbms_lob.fileclose(src_file);
              utl_smtp.write_data(c, utl_tcp.CRLF||utl_tcp.CRLF);

END;
------------------------------------------------------------------------------------------------------------------------------------


--Procedimiento para separación y Adición de Archivos Adjuntos
------------------------------------------------------------------------------------------------------------------------------------
PROCEDURE add_attachments(p_Adjuntos in VARCHAR2) AS
l_Cadena varchar2(500) := p_Adjuntos;
l_LargoCadena number;
l_Comas number;
l_PosicionComa number := 0;
l_Archivo varchar2(100);

-- Variables para el procesamiento de Archivos
 rfile     RAW(57);
 flen      NUMBER;
 bsize     NUMBER;
 src_file  bfile;
 buffer_   integer := 57;
 i         integer := 1;
BEGIN

l_LargoCadena := length(l_Cadena);
l_Comas := l_LargoCadena-length(replace(l_Cadena,';'));

--Bloque 1 Adición del Archivo
    IF l_Comas > 0 THEN
          FOR l_segmento IN 1 .. l_Comas LOOP
          
              l_Archivo := substr(l_Cadena, l_PosicionComa + 1, instr(l_Cadena,';',1,l_segmento) - (l_PosicionComa + 1));
              file_attach(l_Archivo);
            
              l_PosicionComa := instr(l_Cadena,';',1,l_Segmento);
              
          END LOOP;
    END IF;
-- Fin de Bloque 1

-- Bloque 2: Para inserción del ultimo archivo (o el primero, si es unico)
    l_Archivo := substr(l_Cadena, l_PosicionComa + 1, l_LargoCadena);
    file_attach(l_Archivo);
              
-- Fin Bloque 2  

END;
---------------------------------------------------------------------------------------------------------------------------------


-- Inicio del Programa Core para el correo
BEGIN 

    -- Bloque de Apertura de Conexión
    c := utl_smtp.open_connection('165.254.254.32',25);  --Recuerden que puede ser el nombre NetBios o la IP
    utl_smtp.helo(c, '165.254.254.32'); 
    utl_smtp.mail(c, p_Remitente);-- Remitente 

    -- Bloque de Adición de Destinatarios
    IF p_DestinatariosPara IS NOT NULL THEN
        add_rcpt(p_DestinatariosPara);
    END IF;

    IF p_DestinatariosCC IS NOT NULL THEN
        add_rcpt(p_DestinatariosCC);
    END IF;

    IF p_DestinatariosBcc IS NOT NULL THEN
        add_rcpt(p_DestinatariosBcc);
    END IF;

    --Bloque de Apertura de Datos
    utl_smtp.open_data(c); 

    -- Bloque de Adición de Cabeceras de Mail
    IF p_DestinatariosPara IS NOT NULL THEN
        add_headers_rcpt(p_DestinatariosPara, 'TO');
    END IF;

    IF p_DestinatariosCC IS NOT NULL THEN
        add_headers_rcpt(p_DestinatariosCC, 'CC');
    END IF;

    send_header('Subject', p_Asunto); --Asunto
    send_header('From', p_Remitente); -- De
    send_header('MIME-Version','1.0');
    send_header('Content-Type','multipart/mixed; boundary="MIME.Bound"');
    utl_smtp.write_data(c,'--MIME.Bound'||utl_tcp.CRLF);
    send_header('MIME-Version','1.0');
    
    IF p_Mensaje IS NOT NULL THEN
    
        IF p_TipoMensaje = 'TEXT' THEN
            send_header('MIME-Version','1.0');
            send_header('Content-Type','text/plain; charset=us-ascii');
            send_header('Content-Disposition', 'inline');
        ELSE
            send_header('MIME-Version','1.0');
            send_header('Content-Type', 'text/html;charset=windows-1252');
            send_header('Content-Disposition', 'inline');
            send_header('Content-Transfer_Encoding', '8bit');
        END IF;
    
    END IF;

    -- Bloque de Escritura del Mensaje 
    utl_smtp.write_data(c, utl_tcp.CRLF ||p_Mensaje||utl_tcp.CRLF);
    utl_smtp.write_data(c, utl_tcp.CRLF);
    
    -- Bloque de Envio de Adjuntos
    add_attachments(p_ArchivosAdjuntos);
    utl_smtp.write_data(c, utl_tcp.CRLF||'--MIME.Bound--'||utl_tcp.CRLF);

    -- Bloque de Cierre de Datos y Envio del Mail
    utl_smtp.close_data(c); 

    -- Bloque de Cierre de Conexión
    utl_smtp.quit(c); 

    EXCEPTION
     WHEN utl_smtp.Transient_Error OR utl_smtp.Permanent_Error then
        -- Bloque de Cierre de Conexión
        utl_smtp.quit(c); 
       raise_application_error(-20000, 'Unable to send mail: '||sqlerrm);
     WHEN OTHERS THEN
        -- Bloque de Cierre de Conexión
        utl_smtp.quit(c); 
        raise_application_error(-20000, 'Unable to send mail: '||sqlerrm);
    END;

END;

-- Ejemplo de uso

exec              P_SENDMAILATTACH(p_DestinatariosPara =>'usuario.uno@empresa1.com;usuario.dos@empresa2.com',
                                   p_DestinatariosCC => 'usuario@otraempresa.com',
                                   p_Remitente => 'InformesEmpresa1@empresa1.com',
                                   p_Mensaje =>'<h1> Informe </h1> <p>Cuerpo del Informe</p>',
                                   p_Asunto => 'Envío de Informe Empresa1',
                                   p_ArchivosAdjuntos => 'a6.pdf;a1.csv;A3.xml;A5.PDF;a6.txt',
                                   p_TipoMensaje => 'HTML');


Espero les sea de utilidad el código y les confirmo que funciona al 100%, cualquier pregunta o comentario, pueden dejarlo en este post.



116 comentarios:

  1. Hola Roger lo ejecuto y me genera el siguiente error:
    Oracle database error code ORA-29277 – invalid SMTP operation

    ResponderEliminar
    Respuestas
    1. A me sale el mismo error, cual sera el problema

      Eliminar
    2. Ahi tenemos varias causas, desde que el servidor de correo no te responda (permisos de conexión, puerto o ip errónea), direcciones de email mal escritas o un comando mal enviado... necesitaría revisar como implementaste el código y como lo estás ejecutando. Puedes enviarmelo a mi email por favor.

      Eliminar
  2. Una disculpa por la tardanza en responder, en que línea te marca el error?

    ResponderEliminar
    Respuestas
    1. Buenos días Roger:

      Me parece muy claro y útil el procedimiento y el ejemplo, y aunque aún no lo he implementado para un desarrollo que tengo que hacer en mi trabajo, tengo dos inquietudes: Primero, en la construcción del procedure P_SendMailAttach, se tienen 9 parámetros, mientras que en el ejemplo de ejecución solo hay 7 (falta el parámetro 3 (Bcc), y el 7, Directorio lógico), supongo que el 3 lo debo incluir en NULL si no requiero Bcc, y el 7 con el valor del directorio lógico ( para el caso de su ejemplo,"ATTACHMENTS", cierto? Y la segunda inquietud, es precisamente respecto al directorio lógico, en mi caso, los archivos a adjuntar los tengo guardados en un servidor de WCC (Web Center Content), y el path de ubicación es como "http://gestiondocumental:10300/url .../arch.pdf"
      ese seria el directorio lógico ? o puedeo prescindir de ese parámetro y enviar toda la cadena del path incluyendo el nombre del archivo en el parámetro archivos adjuntos? Agradezco su pronta respuesta, pues me urge este desarrollo, Germán

      Eliminar
    2. Para el caso de tu primera inquietud, el procedimiento maneja valores por default para casi todos los parámetros, si los mandas con valor NULL puede que se presente algún error.

      En el caso del directorio lógico, la Base de Datos espera una referencia a una ubicación de FileSystem, esto lo puedes ver en la documentación de Oracle siguiente: https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_5007.htm

      Ahora, algo que puedes hacer es hacer el llamado HTTP a tu WCC desde un procedimiento almacenado, y que el procedimiento procese el archivo como un BLOB y lo almacene en un directorio de la BD.

      A mi punto de vista, si el archivo ya lo tienes en un BLOB solo tendrías que hacer unos ajustes al procedimiento interno fileattach para que procese ese BLOB y lo adjunte al correo quitando el paso de bajarlo a tu servidor y quede ahí almacenado.

      Eliminar
  3. Hola Roger:

    Agradecerte muy sinceramente tu código; funciona muy, muy bien. Sólo comentarte que hay una pequeña errata en el procedimiento file_attach y es que la línea trasnfer_encodding debe ir tras la linea disposition.

    Un saludo

    ResponderEliminar
    Respuestas
    1. Muchas gracias, haré la corrección del mismo. Sinceramente muy claras las reglas del HTML.

      Eliminar
  4. Hola Roger,
    El procedimiento me genra este error :

    Unable to send mail: ORA-29279: SMTP permanent error: 501 could not parse your mail from command

    Saludos,
    JF

    ResponderEliminar
    Respuestas
    1. En tu caso mi estimado, el problema radica en la sintaxis de la dirección de email, alguna no cumple con el patrón cuenta@dominio.
      Utiliza la función UTL_SMTP.VRFY para validar tus direcciones de email.

      Eliminar
  5. Hola.. tengo el mismo problema

    ORA-20000: Unable to send mail: ORA-29279: SMTP permanent error: 530 5.7.0 Must issue a STARTTLS command first. n20sm10251459anl.19

    Si lo han resuelto por favor escribirme a @n0rf3n en twitter..!!

    GRacias.

    ResponderEliminar
    Respuestas
    1. Aqui el detalle es que para conectarte a tu servidor SMTP debes mandar tus credenciales de usuario para el mismo con el procedimiento UTL_SMTP.COMMAND, estoy buscando como hacer esa comprobación utilizando el protocolo STARTTLS. Si lo encuentro te lo envio, si lo encuentras primero, lo compartes =)

      Eliminar
  6. Hola Roger,

    muchas gracias por el aporte, el procedure funciona perfecto, pero tengo una duda, cuando llega el correo, no llega con el adjunto, sino incrustado en el cuerpo del mensaje y codificado, podrias ayudarme?

    Gracias.
    Suso.

    ResponderEliminar
    Respuestas
    1. Técnicamente asi son los correos con adjuntos, estos van "incrustados"en el mensaje en código ilegible, pero el cliente de correo se encarga de interpretarlo.
      Deberías revisar tu cliente de email o tu server de.correo, ya que por razones de seguridad bloquean cierto contenido.
      Actualmemte tengo este procedimiento en mi entorno productivo y na ha habido detalles con la recepción de adjuntos

      Eliminar
  7. Hola muchas gracias por la ayuda, solo tengo un pequenio problema y es que al enviar el adjunto no me adjunta el archivo sino que manda una cadena asi :
    ssss --MIME.Bound Content-Type: application/octet-stream; name="NOMINA.PDF" Content-Disposition: attachment; filename="NOMINA.PDF" Content-Transfer-Encoding: base64 --MIME.Bound--

    Que puede estar pasando??

    Muchas gracias :)

    ResponderEliminar
  8. Le comentarie estas lineas

    -- Bloque de Escritura del Mensaje
    -- utl_smtp.write_data(c, utl_tcp.CRLF ||p_Mensaje||utl_tcp.CRLF);
    -- utl_smtp.write_data(c, utl_tcp.CRLF);

    y me adjunto el archivo pero al momento de abrirlo ahora me sale que esta daniado.

    :(

    ResponderEliminar
  9. Listo lo solucione comentareando las lineas

    -- Bloque de Escritura del Mensaje
    -- utl_smtp.write_data(c, utl_tcp.CRLF ||p_Mensaje||utl_tcp.CRLF);
    --utl_smtp.write_data(c, utl_tcp.CRLF);

    -- Bloque de Envio de Adjuntos
    add_attachments(p_ArchivosAdjuntos);
    --utl_smtp.write_data(c, utl_tcp.CRLF||'--MIME.Bound--'||utl_tcp.CRLF);

    ResponderEliminar
    Respuestas
    1. Hola Sindy:
      Veo que comentaste unas líneas, sin embargo, observo que quitaste la escritura del mensaje (cuerpo) del correo. Posiblemente en tu caso sobre la línea de inserción del Boundary únicamente.
      En mi caso, utilizamos un servidor Exchange y no se me había presentado ese problema.
      ¿Qué servidor de correo utiliza?
      Gracias por el apoyo :)

      Eliminar
  10. Como decimos en España, eres un máquina, un fiera, o lo más utilizado en Andalucía, un monstruo.

    Saludos y gracias, es de gran utilidad.

    ResponderEliminar
  11. Hola Roger tengo un problemita no con el procedimiento sino la forma en que guardo los archivos a enviar.
    En forms 6i tengo un procedimiento mando a imprimir pero en pdf, no lo manda a la impresora sino que los guarda en una carpeta. Dentro del codigo hago esto:

    Add_Parameter(list_id, 'DESTYPE', TEXT_PARAMETER, 'FILE');
    Add_Parameter(list_id, 'DESNAME', TEXT_PARAMETER, 'Y:\nomarchivo.PDF');
    Add_Parameter(list_id, 'MODE', TEXT_PARAMETER, 'BITMAP');
    Add_Parameter(list_id, 'PRINTJOB', TEXT_PARAMETER, 'NO');
    Add_Parameter(list_id, 'DESFORMAT', TEXT_PARAMETER, 'PDF');

    Run_Product(REPORTS, 'NOM1002.Rep', SYNCHRONOUS,RUNTIME,FILESYSTEM,list_id);
    Destroy_Parameter_List(list_id);

    ENV_EMAIL_ADJUNTO (mail,'NOMINATEAM2','nomarchivo.PDF');

    La forma que contiene este codigo no se ejecuta en el servidor de oracle sino en un cliente y para esto creo una unidad de red "Y" que apunta a la carpeta que utilizo en el procedimiento ENV_EMAIL_ADJUNTO (que ya esta creada logicamente y fisicamente en el servidor). El me funciona perfectamente y envia los correos pero el punto es que no quiero que haya una unida de red en el cliente sino que exista una forma que lo haga sin crear la unidad en la opcion DESNAME. No se si logro explicarme.

    NOMINATEAM2 es el directorio logico.
    y el procedimiento ENV_EMAIL_ADJUNTO es un procedimiento almacenado.

    Muchas gracias!!!


    ResponderEliminar
  12. Hola Roger.

    Para aclarar yo puedo colocarle en desname la ruta en C:\nomarchivo.pdf para q me genere el pdf en el equipo cliente el problema es que en el procedimiento como tu lo indicas debo crear el directorio logico y fisico en el servidor. Pero como hago para que me trabaje como yo quiero si el pdf se me genera es en C del cliente(en el caso que no utilice la unidad de red que si apunta a la carpeta creada en el servidor).

    Gracias!!!!!

    ResponderEliminar
  13. Aqui creo que esta mas explicado mi problema

    1. - A traves de una Forma(Developer) generamos un documento en PDF en el disco local del cliente, pero no lo podemos enviar por correo.
    2. - Desde el servidor de Base de Datos podemos enviar un correo con cualquier adjunto que este en una ruta dada del mismo, pero no logramos generar allí(en el servidor) el adjunto que queremos enviar.
    Ahora bien, lo que se quiere es poder generar este reporte(PDF) en el servidor para poder enviarlo por correo posteriormente, como sabes el usuario final o cliente no podra copiar al servidor por tal motivo el proceso de generar dicha información debe quedar del lado del servidor en un 100%.
    Conoces algún procedimiento almacenado propio de Oracle o alguno desarrollado que me pueda ayudar.
    Gracias por su ayuda y colaboración.

    ResponderEliminar
    Respuestas
    1. Hola Sindy!
      En este caso podrías utilizar el directorio lógico apuntando a una carpeta compartida en la PC cliente, utilizando la nomenclatura de netbios (si tus usuarios usan windows). El detalle aquí, es que tendrías que crear tantos directorios lógicos como usuarios utilicen esa forma.

      Si son pocos usuarios, creo que se solucionaría tu caso. Si esto no es factible y utilizando lo que ya tienes, en vez de crear la unidad mapeada en la máquina del usuario, en tu parámetro DESNAME coloca la ruta netbios de la carpeta compartida, algo así como \\nombredelservidor\carpeta.

      De cualquier modo me llevo tu consulta de tarea por si encuentro otra solución.

      Eliminar
    2. Ignora la primer solución... se nota que estaba dormido ;-)

      Lo factible en lo que investigo si hay otro modo es la segunda.

      Recuerda que debes de apoyarte con el administrador del servidor para aquello de los permisos en la carpeta compartida.

      Eliminar
  14. Sindy:

    Investigué un poco sobre tu caso, y al no encontrar nada que te pueda ayudar de manera directa, analizando un poco lo que ya te había propuesto se me ocurrió algo que te puede servir.

    Requisitos:
    El parámetro de Base de Datos UTL_FILE_DIR debe estar en '*' (se que eso lo ven como una vulnerabilidad de seguridad, para algunos auditores, sin embargo es controlable)

    Crear una tabla en la que se almacene el Username y la ruta de la carpeta compartida en su PC en la forma \\nombrePC\CarpetaCompartida . Si tu usuario cambia de máquina de manera constante, te recomiendo almacenar el nombre de la PC (que puedes obtener desde Forms) y la ruta de la carpeta compartida.

    En la carpeta compartida, el usuario maquina del servidor de Base de Datos (solicita apoyo con el administrador de servidores) debe tener permiso de lectura y escritura sobre dicha carpeta.

    Con estos requisitos previos, modificas tu procedimiento para que reciba como parámetro el Username o el nombre del Equipo según lo que hayas decidido al crear la tabla. Buscas la ruta que tiene registrada y al enviar el correo le indicas dicha ruta para la obtención del archivo adjunto.

    Espero te sirva la propuesta y si realizas otra, no se te olvide compartirla en este espacio.

    ResponderEliminar
  15. Muchas gracias Roger me han servido tus comentarios, ya se que puedo crear un directorio logico apuntando a una carpeta compartida en el equipo del cliente y no en el servidor lo cual no seria necesario crear una unidad de red. Con respecto a la tabla para guardar el equipo y la carpeta compartida esta super voy a intentarlo.

    Muchisimas gracias de nuevo

    ResponderEliminar
  16. Hola Roger, muchas gracias por el código; por favor si me puedes indicar que hacer para el siguiente error al probar el procedure...

    ORA-29278: SMTP transient error: 421 Service not available
    ORA-06512: at "SYS.UTL_SMTP", line 21
    ORA-06512: at "SYS.UTL_SMTP", line 97
    ORA-06512: at "SYS.UTL_SMTP", line 399
    ORA-06512: at "BBRAUN.P_SENDMAILATTACH", line 332
    ORA-29278: SMTP transient error: 421 Service not available
    ORA-06512: at line 1

    Slds
    Wilson

    ResponderEliminar
    Respuestas
    1. Tarde pero seguro!
      En tu caso mi estimado, no se está estableciendo una conexión con tu servidor SMTP, ya sea por bloqueo o que el servicio no esté disponible (apagado, dado de baja...)

      Eliminar
  17. Perfecto , funcionó en el primer intento , muchas gracias

    ResponderEliminar
  18. Hola roger tengo una duda he hecho de todo para este proceso pero tengo un error y no se que es, ya verifique permisos y todo pero no se que es para que por favor me puedas colaborar..

    ORA-29277: invalid SMTP operation
    ORA-06512: at "SYS.UTL_SMTP", line 44
    ORA-06512: at "SYS.UTL_SMTP", line 150
    ORA-06512: at "SYS.UTL_SMTP", line 383
    ORA-06512: at "SYS.UTL_SMTP", line 399
    ORA-06512: at "CO.P_SENDMAILATTACH", line 281
    ORA-22285: non-existent directory or file for GETLENGTH operation
    ORA-06512: at line 1

    ResponderEliminar
    Respuestas
    1. Disculpa que me intrometa, los errores que te marca son de que el archivo al que estas intentando acceder fue denegado por el servidor o no existe, comprueba que tu directorio sea valido y que tengas los permisos para acceder a el y a los archivos. Puedes crear un procedimiento para crear un archivo remoto, luego para escribirlo y leerlo y asi comprobaras los permisos para acceder al directorio. Suerte

      Eliminar
  19. Muchísimas gracias por tu trabajo, llevaba buscando un código que hiciera esto mismo desde hace mucho tiempo y el tuyo es perfecto para lo que necesito.
    Un abrazo muy fuerte y gracias por compartir tus conocimientos.

    ResponderEliminar
  20. Buenas tardes, a todos, a los que han logrado la implementacion los que aun no (me incluyo), las siguientes dudas:

    1- Funciona para la version 10gR2.
    2- Debo de crear los procedures en la base de datos? o puede ser desde una forma.
    3- Roger, podrias crear un video tutorial en youtube, a veces es mas fácil visualizar procedimientos.

    Saludos.

    ResponderEliminar
    Respuestas
    1. Rodrigo:
      Una disculpa por la tardanza en contestar, pero por razones laborales no he podido entrar a ver comentarios ni actualizar entradas en mi blog.

      Las respuestas a tus preguntas son las siguientes:
      1.- Si, funciona para 11g, de hecho el código es funcional (probado) con versión 9i, 10g y 11g (que es donde lo tengo implementado actualmente)

      2.- En efecto, el procedimiento es para crearse como Stored Procedure en la BD y ya si lo necesitas, lo mandas a llamar desde una forma.

      3.- Si la agenda me lo permite, lo colgaré aquí mismo.

      Eliminar
  21. Muchas gracias amigo solo me faltaba agregarle el envio de adjuntos ademas me esta costando un poco integrarlo ya que para el envio de correos en mi procedimiento coloco banderas y excepciones de un proceso que corro antes que este, es decir si en el otro hay errores no debe enviar correo, y si no hay q enviarlo y cambiar banderas, en fin de todas formas muchisimas gracias!

    ResponderEliminar
  22. No funciona desde Forms, manda el siguiente mensaje error 29277

    ResponderEliminar
    Respuestas
    1. Hola Carlos!
      Necesitaría conocer como estás implementando el procedimiento y tu entorno (versión de Forms, Servidor de mail).
      Yo lo he probado con Forms 6i y 10g y no me ha dado problema alguno.

      Eliminar
  23. Buena Tarde Roger, he implementado el Procedimiento y me genera un error
    ORA-20000: Unable to send mail: ORA-29279: SMTP permanent error: 503 5.5.1 Error: send HELO/EHLO first
    ORA-06512: at "P_SENDMAILATTACH", line 279
    ORA-06512: at line 23

    espero me puedas ayudar.

    Muchas Gracias.

    ResponderEliminar
    Respuestas
    1. Al parecer omitiste la línea utl_smtp.helo, o revisa la IP que estás pasando como parámetro.
      Si el problema persiste, envíame tu implemetación para revisarla

      Eliminar
  24. Al parecer omitiste la línea utl_smtp.helo, o revisa la IP que estás pasando como parámetro.
    Si el problema persiste, envíame tu implemetación para revisarla

    ResponderEliminar
  25. Buenas tardes, has utilizado la funcion utl_smtp.vrfy?

    Estoy tratando de implementar pero me regresa un codigo 252, 2.1.5 Cannot VRFY user
    He leido en unos lugares(blog) que es por que el servidor SMTP no es compatible o algo asi, el servidor es un exchage que utilizo, verifico cuentas de hotmail, gmail, live, outlook, y del propio dominio y me sale el mismo codigo

    ResponderEliminar
  26. Buena Tarde Roger la linea no fue omitida la tengo en el lugar donde tu la tienes,

    c := utl_smtp.open_connection('10.18.117.200',25);
    utl_smtp.command( c, 'AUTH LOGIN');
    utl_smtp.helo(c, '10.18.117.200');
    utl_smtp.mail(c, p_Remitente);

    realice una prueba con otro procedimiento que no tiene datos adjuntos para mirar si era la ip pero el correo salio sin inconveniente, el error aun persiste, la ejecución que estoy haciendo es la siguiente:

    DECLARE
    P_DESTINATARIOSPARA VARCHAR2(32767);
    P_DESTINATARIOSCC VARCHAR2(32767);
    P_DESTINATARIOSBCC VARCHAR2(32767);
    P_MENSAJE VARCHAR2(32767);
    P_REMITENTE VARCHAR2(32767);
    P_ASUNTO VARCHAR2(32767);
    P_TIPOMENSAJE VARCHAR2(32767);
    P_DIRECTORIO VARCHAR2(32767);
    P_ARCHIVOSADJUNTOS VARCHAR2(32767);

    BEGIN
    P_DESTINATARIOSPARA := 'misama20@gmail.com';
    P_DESTINATARIOSCC := NULL;
    P_DESTINATARIOSBCC := NULL;
    P_MENSAJE := 'Haga caso omiso a este mensaje';
    P_REMITENTE := 'usuario@midominio.com';
    P_ASUNTO := 'Este correo no tiene asunto';
    P_TIPOMENSAJE := 'Prueba';
    P_DIRECTORIO := '/orabackup/expSRH_dat061713.log';
    P_ARCHIVOSADJUNTOS := '/orabackup/expSRH_dat061713.log';

    HR.P_SENDMAILATTACH ( P_DESTINATARIOSPARA, P_DESTINATARIOSCC, P_DESTINATARIOSBCC, P_MENSAJE, P_REMITENTE, P_ASUNTO, P_TIPOMENSAJE, P_DIRECTORIO, P_ARCHIVOSADJUNTOS );
    COMMIT;
    END;

    lo he intentado con las variables
    P_DIRECTORIO := NULL;
    P_ARCHIVOSADJUNTOS :=NULL;

    Y aun asi me genera el mismo error.

    ORA-20000: Unable to send mail: ORA-29279: SMTP permanent error: 503 5.5.1 Error: send HELO/EHLO first
    ORA-06512: at "HR.P_SENDMAILATTACH", line 279
    ORA-06512: at line 23

    Espero me puedas colaborar muchas Gracias.

    ResponderEliminar
    Respuestas
    1. Buenas noches milton, no se si te pueda ayudar, pero puedes realizar un cambio en tu codigo: debes tener primero la conexion, despues el helo y despues el resto del codigo, veo que utilizas autenticacion con el server, pero no veo el codigo del usuario y pass, no se si asi el codigo se ejecute correctamente, puedes verificar si jala correctamente o no....

      c := utl_smtp.open_connection('10.18.117.200',25);
      utl_smtp.helo(c, '10.18.117.200');
      utl_smtp.command( c, 'AUTH LOGIN');
      utl_smtp.mail(c, p_Remitente);

      Eliminar
    2. Milton, como menciona el compañero Anónimo y recordando como es el proceso del protocolo SMTP (ver http://es.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#Resumen_simple_del_funcionamiento_del_protocolo_SMTP) tiene razón en el orden que menciona. Podrías intentarlo por favor y comunicarnos el resultado obtenido.
      Anónimo, muchas gracias por el apoyo!

      Eliminar
  27. Buenas tardes, has utilizado la funcion utl_smtp.vrfy?

    Estoy tratando de implementar pero me regresa un codigo 252, 2.1.5 Cannot VRFY user
    He leido en unos lugares(blog) que es por que el servidor SMTP no es compatible o algo asi, el servidor es un exchage que utilizo, verifico cuentas de hotmail, gmail, live, outlook, y del propio dominio y me sale el mismo codigo
    Att: Anonimo.

    ResponderEliminar
    Respuestas
    1. Según la documentación de Oracle dicha función es para validar direcciones de correo electrónico con el servidor SMTP, sin embargo considero que por seguridad no deben permitir que una dirección externa o no administrativa realice tal validación.

      Eliminar
  28. Roger DBA gracias por tu codigo de envio de email con archivos atachados, una pregunta que tiempo demora en enviar el precedimiento el email con el archivo atachado? gracias, saludos jose

    ResponderEliminar
    Respuestas
    1. Si consideramos que tu servidor SMTP y Base de Datos están sobre una LAN y el tamaño de los archivos es de hasta 1024K, el tiempo de envío es mínimo (del orden de >1 a 10 segundos), si tu servidor SMTP o de Base de Datos se encuentran conectados en una MAN o WAN, considera el tiempo de transferencia del archivo a tu servidor de SMTP para poder enviarse (algo así como cuando envías un correo con adjuntos a traves de un webmail).
      Si estás en una LAN y notas que el procedimiento se tarda, deberás revisar tu base de datos si no está sobrecargada (la lectura de archivos y su envío implican consumo de recursos), después tu servidor SMTP y por último la red de comunicación entre ellos.

      Eliminar
    2. Roger DBA, gracias por la respuesta.
      Te comento que probe el procedimiento y me sale este error,ORA-29279 por favor me puedes ayudar con el error? gracias.
      Te comento que la base de datos esta instalado sobre Linux.
      En la pc que estoy ejecutando tiene windows xp y ya intale el IIS (Servicio de INternet de informacion server).
      Gracias.
      Saludos.

      Eliminar
    3. Roger DBA buenos dias, solucione el problema ORA-29279, ahora me sale el error ORA-29277 , por favor si me puedes ayudar. Gracias. Jose.

      Eliminar
    4. Roger ya encontre el problema, el procedimiento se ejecuta bien, cuando comento la linea de envio de arcvhivos, y se cae en el procedimiento file_attach en la linea --> flen := dbms_lob.getlength(src_file);
      gracias por la respuesta.

      Eliminar
    5. José, sería necesario revises exactamente en que punto está generándose el error para poder ayudarte.
      Realiza un debug del procedimiento ejecutándolo con los valores que te generen error.
      Te recomiendo el uso de SQL Developer para esta actividad, además de que le digas a tu DBA te de privilegios de DEBUG en tu sesión y el procedimiento.

      Eliminar
    6. Si está fallando en esa línea es por que la base de datos no tiene permisos de lectura sobre el archivo o este no existe en la ruta especificada.

      Revisa ese punto y me comentas.

      Eliminar
    7. Roger ya esta, ya envia email con archivos atachados, el problema era que no habia un directorio virtual , se creo, se almaceno los archivos que deseo envia y salio. Esta de la puta madre el procedimiento!! Gracias.

      Eliminar
    8. Que bueno que te haya servido y gracias a ti por la paciencia en la respuesta a tus preguntas.

      Eliminar
    9. Roger DBA, buenos dias, una consulta,
      Desde la forma (oracle developer 10g), el usuario genera un archivo texto, y lo guarda en su disco C, luego deseo , ese archivo de texto, deseo guardarlo en el disco duro del servidor de base de datos o directorio virtual de oracle, para luego coger ese archivo de texto y enviarlo como archivo atachado, el problema es que , cuando deseo llevar el archivo de texto al servidor virtual no lo hace, para luego ese mismo archivo enviarlo por forms, conoces alguna herramienta que me ayude a gestionar el caso expuesto??, hey probado PSCP (transferencia de archivos, lo hago mediante archivo bath) y no me funciona. Gracias por la respuesta. saludos.

      Eliminar
    10. Buenos días:

      Primero hay que revisar por que no puedes enviar el archivo a la carpeta de tu server de base de datos. ¿Tienes acceso a la carpeta por medio de alguna ruta compartida? ¿Tiene el usuario permisos para escribir sobre esa carpeta?

      Eliminar
  29. Gracias por la respuesta. Para la primera interrogante si hay acceso a la ruta compartida, para la segunda interrogante: el usuario puede escribir.
    Adicionalmente se menciona que ya existe otro archivo .BAT que usa el comando copy y funciona correctamente, claro que este archivo solo hace copias dentro del mismo servidor.

    Nota: Ambos archivos .BAT estan contenidos en la misma carpeta.

    ResponderEliminar
    Respuestas
    1. No me queda muy claro el escenario, puedes pasarme una dirección de email para escribirte y apoyarte ya que tu problema siento que es más de privilegios y configuraciones a nivel SO que de Base de Datos.

      Eliminar
    2. Roger DBA, gracias, ya esta resuelto el tema, otra pregunta, como puedo obtener la clave del SYS , si me hey olvidado la clave de ese esquema.Gracias.

      Eliminar
    3. No puedes saber la contraseña ni recuperarla, la única opción que tienes es ingresar con otro usuario que tenga permisos de SYSDBA, DBA o de ALTER USER y asignarle una nueva contraseña al usuario SYS. Si esto te funciona, como consejo, coloca una contraseña que te sea fácil no olvidar pero que a la vez sea compleja.

      Eliminar
    4. Gracias Roger DBA.

      Eliminar
  30. Hola Roger DBA, muy buen script, funciona correctamente, sabes de alguna manera de comprimir los archivos antes de que estos se adjunten al correo.

    Saludos

    ResponderEliminar
    Respuestas
    1. Una opción es que crees un procedimiento almacenado java para ejecutar la compresión en .zip
      Otra opción es el uso del package dbms_pipe, que según la documentación sirve para ejecutar comandos UNIX, en lo personal no lo he utilizado.
      De igual forma si me describes tu escenario, puede que tenga una mejor respuesta o solución a tu necesidad.
      Saludos

      Eliminar
    2. Roger gracias por tu respuesta, lo que hacemos es enviar correos con reportes semanales todos los viernes a la media noche, estos reportes ahora pasan los 1.5MB y ya no llegan a pasar por correo.
      Esto lo hacemos desde un oracle express ya que solo tenemos acceso de lectura al server principal y segun lei no se puede ejecutar java desde oracle express, es cierto eso?

      intentare hacer algo con el package dbms_pipe que indicas y te comento.

      Saludos

      Eliminar
    3. Sobre la limitante de Oracle Express Edition es cierta, no puedes crear o compilar procedimientos java (aquí esta la tabla de características http://docs.oracle.com/cd/E17781_01/license.112/e18068/toc.htm#XELIC118).
      Si lo de dbms_pipe no te funciona te recomendaría, para efectos prácticos, sea una aplicación (hasta en consola si quieres) que se encargue de extraer la información, generar el reporte, comprimirlo y enviarlo por correo. Puedes crear procedimientos en la base para la extracción de Info y el envío del correo si así lo deseas o dejarle todo el trabajo a la aplicación.

      Saludos!

      Eliminar
  31. Roger DBA buenas noches, tu procedimiento como te comente dias atraz, funciona bien, la consulta que te queria hacer es, que hay momentos que envia bien el email con archivos atachados y otros momentos que envia el email con archivo atachado y sale lleno de codigo US7ASCII (codigo ascii 7 bits) el cuerpo del email enviado? porque sera? , gracias por la respuesta. saludos jose.

    ResponderEliminar
    Respuestas
    1. Una pregunta, cuando en el mail se muestra código ASCII ¿Qué tipo de archivos son? ¿Todo tipo? ¿TXT, PDF, etc?
      Saludos!

      Eliminar
    2. Roger DBA buenas tardes, estoy haciendo mis pruebas con archivos PDF, gracias.

      Eliminar
    3. Roger por favor si puedes responderme.

      Eliminar
    4. Revisando lo mencionado, en el procedimiento que adjunta el archivo está la línea
      send_header('Content-Type','application/octet-stream; name="' || p_Archivo || '"');
      Ese tipo de Conten-Type es genérico para admitir cualquier tipo de archivos, pero no es interpretado de la misma manera por todos los clientes de correo.
      En esta página vienen los códigos MIME para cada extensión de archivo http://en.wikipedia.org/wiki/Internet_media_type que en el caso de archivos PDF corresponde a application/pdf.

      Por lo tanto la línea antes mencionada quedaría de la siguiente forma:
      send_header('Content-Type','application/pdf; name="' || p_Archivo || '"');

      Considera que si vas a enviar otro tipo de extensiones de archivo, deberás colocar el MIME Type correspondiente

      Saludos!

      Eliminar
    5. Roger DBA, ya corregi lo que me dices, send_header('Content-Type','application/pdf; name="' || p_Archivo || '"'); , pero hey realizado la prueba y de cada 15 envios 4 se caen (envia con codigo ascii), que falta por corregir por favor?...saludos

      Eliminar
    6. Roger DBA, lo que pasa, es cuando lo decodifica los archivos en el proceso file_attach y los archicos son pesados, te envia cel email con codigo ascii, cual puede ser el error?

      Eliminar
    7. El procedimiento no tiene límite para el tamaño de envío de adjuntos, aquí he enviado archivos de hasta 10MB sin problema.

      Sin embargo pueden ser otras las causas de que el archivo se trunque y por eso te salga código ASCII.

      En los correos erróneos revisa en modo texto el archivo (con el notepad u otro editor) y ve si se completa el boundary de fin del archivo, si el proceso se trunca deberás realizar un debug del procedimiento para ver como está trabajando.

      Otro punto a revisar es que el tamaño del archivo a adjuntar esté dentro de los límites permitidos por el servidor de correo saliente de tu empresa.

      Eliminar
    8. Roger BDA, buenos dias, realice un estudio en donde se cae y el correo envia con codigo ascci , se cae en la parte :

      IF p_Mensaje IS NOT NULL THEN

      IF p_TipoMensaje = 'TEXT' THEN
      send_header('MIME-Version', '1.0');
      send_header('Content-Type', 'text/plain; charset=us-ascii');
      send_header('Content-Disposition', 'inline');
      ELSE
      send_header('MIME-Version', '1.0');
      send_header('Content-Type', 'text/html;charset=windows-1252');
      send_header('Content-Disposition', 'inline');
      send_header('Content-Transfer_Encoding', '8bit');
      END IF;

      END IF;

      Si yo comento la parte del codigo , mostrado lineas arriba, todos los correos enviados con archivos atacachados me SALE MUY BIEN (los crorreo se envian sin ningun mensaje en el cuerpo del email), y si vuelvo a colocar la parte de codigo mostrado arriba, de 15 envios , 5 envia con codigo ascii y 10 envia bien y asi sucesivamente.Que puede estar fallando ,.....Gracias por la respuesta. Jose.

      Eliminar
  32. Honestamente al día de hoy no me ha pasado nada similar, lo que me sorprende es que la muestra de exito y error es constante. Lo que puedes hacer es cambiar esta línea send_header('Content-Type', 'text/plain; charset=us-ascii'); por send_header('Content-Type', 'text/plain; charset=ISO-8859-1'); y también revisar que los boundary estén completos.

    ResponderEliminar
    Respuestas
    1. Gracias voy a hacer lo que me dices.

      Eliminar
    2. Voy a subir más tarde una actualización al Procedimiento, sucede que el día de hoy se realizaron pruebas con un nuevo servidor SMTP en la empresa donde laboro y en mi caso el 100% de correos con adjuntos presentan el síntoma que describes (no me pasó el de unos sí y otros no).

      Hice pruebas enviando el correo con UTL_MAIL y ahí si se envió el adjunto correctamente.

      Revisé el contenido de los mensajes con un editor de texto y ahí pude observar que no se interpreta del mismo modo el como yo estructuro los encabezados y mensaje del correo a enviar.

      Ya realicé las modificaciones pertinentes y lo subiré en un nuevo post para que este quede tal cual está y puedan observar el cambio en la implementación.

      Espero esto poder realizarlo a más tardar mañana, para por favor seas paciente.

      Saludos!

      Eliminar
    3. Gracias Roger DBA, saludos. Queria hacerte otra pregunta, conoces de algun procedimiento, que realize la accion, desde la pc del usuario se seleccione un archivo pdf (que esta en directorio virtual del servidor de base de datos)y lo lleve a la pc del usuario, (al disco C), gracias. Jose.

      Eliminar
    4. José:
      Considero que puedes realizar un procedimiento o función que retorne un LOB, sin embargo, la aplicación o programa de donde lo llames deberá soportar recibir este tipo de dato como salida.

      De igual forma, como te he pedido en otras ocasiones, si me explicas mas detalladamente el contexto de lo que requieres hacer, puedo apoyarte con una mejor respuesta.

      Saludos!

      Eliminar
    5. Gracias por la respuesta, se realizo el envio del archivo mediante DOS desde forms y con la ayuda de un programa que hace ese transporte se realizo, lo llamas lo ejecutas y hace el transporte del archivo.GRacias,
      Te queria hacer una consulta, deseo migrar programas de oracle forms de 6i a version oracle 10g , uno de los metodos es utilizando el Java Design-time API (JDAPI), mi preguntas es , si haz realizado migracion de oracle forms 6i a forms 10g? que metodo utilizastes y si tienes algun manual tecnico para que me ayude a configurar el Java Design-time API (JDAPI) y poder realizar la migracion masivamente, Gracias por la respuesta.

      Eliminar
    6. Hola José!

      Que bueno que hayas encontrado solución a tu caso. ¡Felicidades!

      Sobre la migración de Forms 6i a 10g con JDAPI, te comento que no he migrado ninguna forma con tal herramienta, leí un poco y te puedo decir que JDAPI no es un programa, es una librería que tienes que cargar en un IDE para Java (Eclipse, JDeveloper [preferentemente]) con la cual construyes programas Java que realizan cambios en las formas. Este link te puede ayudar http://blog.avanttic.com/2010/02/12/jdapi-nos-ayuda-a-migrar-aplicaciones-forms/

      En su momento, hice migración de formas de manera manual, abriendo el fuente 6i en Forms Developer 10g, pero todo, lógicamente, lo tienes que hacer uno a uno.

      Otro comentario que quiero hacerte es que Oracle tengo entendido va a descontinuar Forms y Reports (actualmente en su versión 11g) y todo apunta a ADF. No sé si tu compañía esté interesada en dar ese salto o la decisión definitiva es pasar a 10g.

      Saludos!

      Eliminar
    7. Gracias Roger, por la respuesta, la empresa donde estoy solo desea migrar a 10g, el link que me distes ya le hize una consulta pero no responde, tienes otro link para consultar o manual para hacer migracion de 6i a 10g masivamente?...gracias. saludos jose.

      Eliminar
    8. Hola Roger !!
      Gracias por la ayuda en este 2014, feliz navidad y feliz año!! saludos.
      Jose.

      Eliminar
    9. Gracias por las felicitaciones, y de igual forma, espero la hayas pasado bien en estas fechas con la familia y seres queridos.

      Sobre el link, acabo de entrar en mi navegador y funciona correctamente, intenta de nuevo.

      Saludos!

      Eliminar
    10. Hola Roger, gracias por la respuesta.
      Una pregunta, queria preguntarte si haz tenido experiencia o desarrollas en EBS de oracle, deseo iniciarme en EBS y deseo conseguir tutoriales y links de los principales modulos. Gracias por la respuesta. Saludos!! Jose.

      Eliminar
    11. Este comentario ha sido eliminado por el autor.

      Eliminar
    12. Este comentario ha sido eliminado por el autor.

      Eliminar
    13. Roger buenos dias, por favor te deseo hacer una consulta, sobre report:
      - En mi PC tengo usuario adminitrador y otros usuarios, cuando ingreso con usuario adminustrador ,entro al menu y realizo cualquier reporte de oracle reporte sale bien y envio dicho reporte por email (la opcion de enviar nativo desde el oracle report) y envia bien.
      - Cuando hago la misma operacion con otro usuaruio (diferente a administrador) , sale bien el reporte, pero cuando envio dicho reporte por email, me sale un error, el cual me menciona que no puede atachar los archivos, dicho error hace mencion, QUE NO PUEDE LEER LA CARPETA DESDE DONDE COGE EL ARCHIVO Y POR ESO SALE ERROR, ya hey dado permiso a dicho usuario, para que tenga acceso a todo el disco C , pero sigue slaiendo el mismo error.GRACIAS POR CONTESTAR LA PREGUNTA.

      Eliminar
    14. Que versión de Reports tienes?

      Eliminar
    15. Hola Roger,

      La version de report es Oracle Developer 2000. Gracias.

      Eliminar
    16. Bueno, hace mucho que no uso Reports, y esta es la primera vez que oigo del uso de envío de reporte por email desde el mismo reports.

      Dado tu síntoma, observo que tiene que ver con el manejo de directorios lógicos desde la Base de Datos. Dentro de la BD se pueden crear "directorios" que apuntan a un path de sistema Operativo. Por ejemplo yo tengo uno que se llama 'Reportes' y este apunta al path C:\DatabaseShared\Reportes. Ahora, cuando creas un directorio lógico, el usuario administrador tiene permisos sobre él, si necesitas que un usuario no administrador pueda leer o escribir en dicho directorio lógico debes de dar los permisos necesarios.
      Las instrucciones son GRANT READ ON DIRECTORY [DIRECTORIO] TO [USUARIO] y GRANT WRITE ON DIRECTORY [DIRECTORIO] TO [USUARIO]. Solo tienes que investigar el nombre del directorio lógico al que apunta el reporte (o Reports). Puedes revisar los directorios lógicos existentes en tu Base de Datos consultando la vista DBA_DIRECTORIES

      Eliminar
    17. hola roger, gracias por la respuesta.

      Eliminar
  33. Hola Roger, he estado implementado lo de los correos todo anda bien en cuanto a los html, etc. pero con los atach tengo problemas, al parecer no encuentra el directorio. Si fue creado en el Linux.

    22285. 00000 - "non-existent directory or file for %s operation"
    *Cause: Attempted to access a directory that does not exist, or attempted
    to access a file in a directory that does not exist.
    *Action: Ensure that a system object corresponding to the specified
    directory exists in the database dictionary, or
    make sure the name is correct.

    ResponderEliminar
  34. Hola wsoto!

    Los procedimientos de attach buscan un directorio lógico creado en la base de datos, en el caso del procedimiento que puse de ejemplo se crea de la siguiente manera:
    CREATE DIRECTORY ATTACHMENTS AS '/tudirectorio/enLinux';

    y después de las permisos al usuario o esquema donde radica el procedimiento
    GRANT READ, WRITE ON DIRECTORY ATTACHMENTS TO [USUARIO]

    Espero te sirva la información!

    ResponderEliminar
    Respuestas
    1. Gracias, ya corre el proceso, solo que el adjunto realmente lo que hace es agregar con un monton de caracteres en el cuerpo del correo.

      --MIME.Bound Content-Type: application/pdf; name="Prueba.PDF" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="Prueba.PDF" JVBERi0xLjENCjEgMCBvYmoNCjw8DQ

      muchas gracias, seguire revizando que esta malo para que haga el attach.

      Eliminar
    2. Compañero, ese detalle fué arreglado en la versión 2 del procedimiento que puedes consultar en el siguiente post http://oracledbamex.blogspot.mx/2014/10/envio-de-correos-utilizando-utlsmtp-12.html

      Eliminar
    3. Ok gracias voy a revisarlo.

      Eliminar
  35. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  36. Hola Roger, deseo hacerte una pregunta.Deseo programar en EBS de oracle y queria preguntarte si tienes manuales de los Modulos de EBS de oracle, por favor si me puedes enviar links de dichos modulos o enviar dichos manuales a mi correo. Gracias por la respuesta. Saludos. Jose.

    ResponderEliminar
  37. Hola roger, primero felicitarte por el código, mi duda es si esto lo puedo utilizar en oracle 10g XE porque cuando le implemente me sale el ERROR ORA - 29278 error transitorio de SMTP: 421 estoy intentando conectar a un servidor en la nube de goddady que compre tengo la ip y el puerto pero me sale error... es por la versión de la base de datos o hay algo mas que agregar en el codigo algún permiso quisas.

    gracias

    ResponderEliminar
  38. Hola roger, logre solucionar el error anterior "ORA 29278" pero me salio otro error que es "error permanente de SMTP: 550 Access denied - Invalid HELO name (see RFC2821 4.1.3)" gracias por el apoyo. saludos Jhon

    ResponderEliminar
    Respuestas
    1. Jhon: Revisa las opciones de seguridad, en mi caso, puedo enviar correo de manera anónima, en el tuyo puede que sea necesario un usuario y contraseña enviandola antes del HELO

      Eliminar
  39. Hay algún camino para poder envíar a un grupo de personas por Oracle 11g?
    Lo que pretendo es poner los alias de grupos que tengo en OUTLOOK, y colocarlos en mi JOB de Oracle para evitar que me salgan todos los correos en el mensaje que envío.

    ResponderEliminar
    Respuestas
    1. Para realizar lo que quieres hacer el grupo debe estar dado de alta en el servidor de Correo o Directorio Activo, ya que el procedimiento no toma las direcciones de correo que tienes registradas de manera local en OUTLOOK

      Eliminar
  40. Este comentario ha sido eliminado por un administrador del blog.

    ResponderEliminar
  41. Que tal Roger tengo el siguiente error si me podes ayudar.
    ORA-29278: SMTP transient error: 421 Service not available
    ORA-06512: at "SYS.UTL_SMTP", line 54
    ORA-06512: at "SYS.UTL_SMTP", line 138
    ORA-06512: at "SYS.UTL_SMTP", line 699
    ORA-06512: at "SOFTTEN.P_SENDMAILATTACH", line 324
    ORA-24247: network access denied by access control list (ACL)
    ORA-06512: at line 2

    Saludos

    ResponderEliminar
    Respuestas
    1. A partir de la versión 11g, Oracle incluyó las listas de control de acceso (ACL) con la cual se restringe el uso de servicios externos (como los de servidores HTTP, FTP, POP, IMAP, SMTP, etc) a los procedimientos almacenados en los esquemas de la Base de Datos.

      Deberás crear la lista ACL, después agregar los servicios a los que se va a tener acceso y, al final, asignar el permiso a los esquemas dueños de los procedimientos almacenados para que consuman dichos servicios.

      Puedes consultar la siguiente URL de documentación de Oracle para ver un ejemplo
      https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_networkacl_adm.htm

      Si necesitas ayuda, agrega un comentario.

      Saludos

      Roger

      Eliminar
  42. compañero Roger, me salen estos errores cuando uso en XE.

    Error que empieza en la línea 123 del comando:
    BEGIN
    DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE
    (
    host => '192.168.1.*',
    lower_port => null,
    upper_port => null,
    ace => xs$ace_type(privilege_list => xs$name_list('jdwp'), principal_name => 'JOSE_CUENTAS', principal_type => xs_acl.ptype_db)
    );
    END;
    Informe de error:
    ORA-06550: line 7, column 9:
    PLS-00201: identifier 'XS$ACE_TYPE' must be declared
    ORA-06550: line 2, column 2:
    PL/SQL: Statement ignored
    06550. 00000 - "line %s, column %s:\n%s"
    *Cause: Usually a PL/SQL compilation error.
    *Action:

    Informe de error:
    ORA-24247: network access denied by access control list (ACL)
    ORA-06512: at "SYS.UTL_TCP", line 17
    ORA-06512: at "SYS.UTL_TCP", line 267
    ORA-06512: at "SYS.UTL_SMTP", line 161
    ORA-06512: at "SYS.UTL_SMTP", line 197
    ORA-06512: at "SYSTEM.CORREO_SMTP", line 9
    ORA-06512: at line 2

    ResponderEliminar
  43. Leyendo los errores de abajo hacia arriba.

    [ORA-06512: at "SYSTEM.CORREO_SMTP", line 9]
    No puedes enviar correos por que no está el permiso en la Lista de Control de Acceso o esta no existe. Esto lo indica el error "ORA-24247: network access denied by access control list (ACL)"

    [PLS-00201: identifier 'XS$ACE_TYPE' must be declared]
    El procedimiento que estás utilizando para crear la Lista de Control de Acceso no corresponde a la versión de Base de Datos que tienes (la última versión de Oracle Database XE es 11gR2).
    Te agrego dos enlaces, uno con una explicación y ejemplos
    https://oracle-base.com/articles/11g/fine-grained-access-to-network-services-11gr1

    y otro con la documentación de Oracle para esa versión
    http://docs.oracle.com/cd/E11882_01/appdev.112/e40758/d_networkacl_adm.htm#ARPLS148

    NOTA: La lista de control de Acceso debe ser creada de manera previa a la ejecución del procedimiento de envío de correo.

    Espero te sea de utilidad la respuesta.

    ResponderEliminar
    Respuestas
    1. hola Roger. tengo un procedure que envia mail desde oracle
      y no me muestra en el mail el destinatario y el remitente, pero envia al destino que lo indicas... ayuda

      Eliminar
    2. Revisa si tu procedimiento envía los headers en el mail, cuando el cliente no muestra esos datos, es por que no están definidos dentro del cuerpo del correo.

      Eliminar
    3. CREATE OR REPLACE PROCEDURE send_mail (p_to IN VARCHAR2 ,
      p_from IN VARCHAR2 ,
      p_message IN VARCHAR2,
      p_smtp_host IN VARCHAR2,
      p_smtp_port IN NUMBER DEFAULT 25)
      AS
      l_mail_conn UTL_SMTP.connection;
      BEGIN
      l_mail_conn := UTL_SMTP.open_connection(p_smtp_host, p_smtp_port);
      UTL_SMTP.helo(l_mail_conn, p_smtp_host);
      UTL_SMTP.mail(l_mail_conn, p_from);
      UTL_SMTP.rcpt(l_mail_conn, p_to);
      UTL_SMTP.data(l_mail_conn, p_message || UTL_TCP.crlf || UTL_TCP.crlf);
      UTL_SMTP.quit(l_mail_conn);
      END;

      Eliminar
  44. Cómo hago para que el archivo adjunto sea leído desde un directorio en el servidor de aplicaciones y no desde la base de datos.

    ResponderEliminar
    Respuestas
    1. Una manera es que el directorio del servidor de aplicaciones esté como un recurso compartido visible por el servidor de base de datos. Como una carpeta compartida o un recurso NFS

      Eliminar

Deja tu comentario aquí