Mostrando las entradas con la etiqueta Excel y correo. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Excel y correo. Mostrar todas las entradas

sábado, 15 de enero de 2022

Microsoft Outlook desde Excel (V): Imagen en el cuerpo del mensaje (Sin errores)

Durante muchos años en internet se han publicado un sinfín de artículos sobre el envío de correo electrónico a través del VBA de Excel. Yo mismo he publicado varias cosas al respecto haciendo uso de Microsoft Outlook o, mejor dicho, a través del objeto Outlook.

En el sentido de lo mencionado en el párrafo anterior, una de las preguntas recurrentes sobre el tema es sobre cómo dar formato a los textos enviados a través del VBA y el mensaje de correo electrónico, sobre todo incluyendo imágenes en el cuerpo del mensaje y/o como firma. Si bien la respuesta inmediata, y que se puede también encontrar en diversas páginas de internet, es usar la propiedad “HTMLBody” y aplicar algo de HTML (Enlace), aunque a muchas personas les ocurre de manera recurrente que la imagen puede hasta llegar como archivo adjunto, pero no se ve en el cuerpo del mensaje o se ve como un marco vacío (no he encontrado personas que les ocurra si se usa en el cuerpo del mensaje una imagen que ya está guardada en alguna url de internet), sobre todo cuando envían a Gmail o Hotmail y más con las nuevas versiones de Office, Windows y los nuevos niveles de seguridad de los servidores.

Buscando, leyendo, indagando, etc., hace un tiempo encontré una solución al dilema mencionado, usando algunas propiedades del objeto Outlook y accediendo a propiedades de la interfaz de programación de aplicaciones de mensajería del servidor a través de los conocidos Schema de Microsoft, lo que hoy compartiré con todos/as.

Comenzaremos declarando cinco variables que son las que vamos a usar; la primera estoy seguro que ya es conocida por ustedes.

Dim outlookApp As Outlook.Application
Luego las siguientes, que dejaré comentadas para que sepan a que nos ayuda cada una:
‘Objeto mensaje de correo 
Dim mCorreo As MailItem   
‘Colección de objetos Attachment 
Dim colecAttach As Outlook.Attachments 
‘Objeto Attachment, que representa lo que vamos a adjuntar 
Dim objAttach As Outlook.Attachment 
‘Permite crear, obtener, establecer y eliminar propiedades en el objeto Outlook 
Dim proOutlook As Outlook.PropertyAccessor 
Dim Ruta$, nImagen$ 

Ahora, vamos a declarar una constante que es equivalente a una de las propiedades canónicas PidTagAttachContentId. Esta contiene el encabezado de identificación de un archivo adjunto de mensaje de extensiones multipropósito de correo de Internet. Vamos a darle el valor de un Schema de Microsoft (Data and Story Library – DASL).

Const PR_ATTACH_CONTENT_ID = "http://schemas.microsoft.com/mapi/proptag/0x3712001F"

Luego daremos valores a las variables:

'Creamos el objeto Outlook 
Set outlookApp = CreateObject("Outlook.Application") 
'Creamos el mensaje 
Set mCorreo = outlookApp.CreateItem(olMailItem) 
'Creamos el adjunto en el mensaje 
Set colecAttach = mCorreo.Attachments 
'Adjuntamos el archivo/Imagen 
Set objAttach = colecAttach.Add("C:\Users\eavj6\Pictures\pez.jpg") 
'Indicamos que haremos uso de una propiedad del adjunto 
Set proOutlook = objAttach.PropertyAccessor 
Ruta = "C:\Users\eavj6\Pictures\" 
nImagen = "pez.jpg" 

Lo que toca ahora es usar el método SetProperty para el nombre del Schema y el valor que nos interesa..

proOutlook.SetProperty PR_ATTACH_CONTENT_ID, "pez.jpg"

Lo que sigue debería entenderse si leyeron mis artículos anteriores jejeje.

With mCorreo
   .Close olSave     
	 .HTMLBody = "<BODY><IMG src=""cid:pez.jpg""> </BODY>" ‘aquí insertamos la imagen adjunta en el cuerpo del mensaje     
	 .Save     
	 .To = "uncorreo@gmail.com"     
	 .Subject = "Prueba"     
	 .Send
End With 

Todo junto podría quedar del siguiente modo:

Option Explicit 
'Todo Sobre Excel 
'Abraham Valencia 
'https://abrahamexcel.blogspot.com/ 
'https://www.facebook.com/TodosobreExcelAV/ 
'https://twitter.com/Todosobre_Excel 
'https://www.youtube.com/channel/UCxEe3aA5uGrtYDdboBT_ptg 
'Lima, Perú 
'Enero del 2022   

Sub ImagenenCuerpo() 

Dim outlookApp As Outlook.Application 
'Objeto mensaje de correo 
Dim mCorreo As MailItem 
'Colección de objetos Attachment 
Dim colecAttach As Outlook.Attachments 
'Objeto Attachment, que representa lo que vamos a adjuntar 
Dim objAttach As Outlook.Attachment 
'Permite crear, obtener, establecer y eliminar propiedades en el objeto Outlook 
Dim proOutlook As Outlook.PropertyAccessor 
Dim Ruta$, nImagen$ 

Const PR_ATTACH_CONTENT_ID = "http://schemas.microsoft.com/mapi/proptag/0x3712001F" 

'Creamos el objeto Outlook 
Set outlookApp = CreateObject("Outlook.Application") 
'Creamos el mensaje 
Set mCorreo = outlookApp.CreateItem(olMailItem) 
'Creamos el adjunto en el mensaje 
Set colecAttach = mCorreo.Attachments 
'Adjuntamos el archivo/Imagen 
Set objAttach = colecAttach.Add("C:\Users\eavj6\Pictures\pez.jpg") 
'Indicamos que haremos uso de una propiedad del adjunto 
Set proOutlook = objAttach.PropertyAccessor 
Ruta = "C:\Users\eavj6\Pictures\" 
nImagen = "pez.jpg" 

proOutlook.SetProperty PR_ATTACH_CONTENT_ID, "pez.jpg" 

With mCorreo     
   .Close olSave     
   .HTMLBody = "<BODY><IMG src=""cid:pez.jpg""> </BODY>" 'aquí insertamos la imagen adjunta en el cuerpo del mensaje     
   .Save     
   .To = "uncorreo@gmail.com@gmail.com"     
   .Subject = "Prueba"     
   .Send 
End With      

MsgBox "Mensaje enviado", vbOKOnly, "Todo Sobre Excel" 

End Subb 

Y listo, eso es todo por hoy. Espero les sea útil. ¡Hasta la próxima!

Abraham Valencia
Lima, Perú

jueves, 30 de agosto de 2018

Microsoft Outlook desde Excel (IV): Enviar hojas y el libro activo por correo

En esta ocasión seguiremos trabajando con Microsoft Outllok pero ahora lo que veremos es como enviar hojas de un libro o incluso el propio libro como archivo adjunto del mensaje de correo. Voy a suponer que ya leyeron este artículo: Enlace, así que solo diré que para enviar el libro de Excel que es el activo en ese momento, bastará agregar una línea para adjuntarlo, además de lo habitual en estos casos. Con dicha línea lo que haremos es usar la propiedad “FullName”, que devuelve el nombre del libro incluyendo la ruta de su ubicación. De ese modo en el correo se adjuntará el archivo (siempre y cuando se haya guardado). Entonces, prueben esto:

Sub EnviarMensajeOutlook()
Dim OutlookApp As Outlook.Application
Dim objItem As MailItem 

Set OutlookApp = CreateObject("Outlook.Application") 
Set objItem = OutlookApp.CreateItem(olMailItem) 

With objItem
     .To = "abraham.valencia@gmail.com" 'Para
     .Subject = "Adjuntando archivo" 'Asunto
     .Body = "Estamos adjuntando un archivo" 'Cuerpo
     .Attachments.Add ActiveWorkbook.FullName
     Application.Wait (Now + TimeValue("00:00:03")) 'Tiempo para adjuntar
     .Send 'Enviar 
End With 

Set OutlookApp = Nothing 
Set objItem = Nothing 

End Sub 

Quizá no sea necesario enviar el libro completo sino solo la hoja activa. De ser así, guardaremos la hoja activa como archivo, lo adjuntaremos y lo eliminaremos de inmediato, en el supuesto de que no lo necesitamos posterior al envío:

Sub EnviarMensajeOutlook() 

Dim OutlookApp As Outlook.Application 
Dim objItem As MailItem 

Set OutlookApp = CreateObject("Outlook.Application") 
Set objItem = OutlookApp.CreateItem(olMailItem) 

ActiveSheet.Copy 
ActiveWorkbook.SaveAs Filename:=ThisWorkbook.Path & "\Temporal.xlsx" 
ActiveWorkbook.Close 

With objItem
     .To = "abraham.valencia@gmail.com" 'Para
     .Subject = "Adjuntando archivo" 'Asunto
     .Body = "Estamos adjuntando un archivo" 'Cuerpo
     .Attachments.Add ThisWorkbook.Path & "\Temporal.xlsx"
     Application.Wait (Now + TimeValue("00:00:03")) 'Tiempo para adjuntar
     .Send 'Enviar 
End With 

Kill ThisWorkbook.Path & "\Temporal.xlsx" 

Set OutlookApp = Nothing 
Set objItem = Nothing 

End Sub 

De no desear que sea la hoja activa la que se envíe, basta indicar, en la línea respectiva, que hoja queremos copiar:

Sheets(“Hoja45”).Copy 

O incluso puede ser un archivo con solo algunas de las hojas del libro:

Sheets(Array("Hoja1", "Hoja4")).Copy 
En el Array pueden ir más hojas, no solo dos, por si acaso. Y eso es todo por hoy. Nos "vemos".

Abraham Valencia

domingo, 4 de febrero de 2018

Microsoft Outlook desde Excel (I)

Muchas veces deseamos que nuestros trabajos en Excel, o en otros programas de Office incluso, se puedan enviar a través de nuestro correo electrónico. Podríamos decir que si tenemos dicho correo configurado en nuestro Microsoft Outlook no será muy difícil lograrlo.

A través de VBA podemos manejar desde Excel nuestro Microsoft Outlook como un objeto y así enviar mensajes adjuntando incluso archivos o nuestra firma digital, si es que la tenemos.

Lo primero que recomiendo hacer es activar la referencia respectiva en el editor de VBA:

En mi caso dice 15.0 por la versión de Office que tengo en la respectiva PC pero se debe activar la que a cada uno le corresponda.

Para continuar, lo que vamos a hacer ahora es crear un objeto “Outlook” y también usaremos el método “CreateItem” con el parámetro del tipo “olMailItem” que creará un nuevo mensaje (objeto “MailItem”):

Dim OutlookApp As Outlook.Application
Dim objItem As MailItem 

Set OutlookApp = CreateObject("Outlook.Application") 
Set objItem = OutlookApp.CreateItem(olMailItem)  
Tal y como cuando enviamos un mensaje desde nuestro correo o desde el propio Microsfot Outlook, el objeto creado tiene propiedades que representan los campos “Para”, “Asunto”, “Cuerpo”, etc:
With objItem 
 .To = "destinatario@ejemplo.com" 'Para
 .CC = "segundodestinatario@ejemplo.com" 'Con copia
 .Subject = "Prueba" 'Asunto
 .Body = "Este es un mensaje de prueba" 'Cuerpo 
End With 

Lo único que faltaría es que usemos el método “Send” para enviar el mensaje:

.Send 

Toda nuestra macro junta podría quedar así:

Sub EnviarMensajeOutlook()
Dim OutlookApp As Outlook.Application
Dim objItem As MailItem

Set OutlookApp = CreateObject("Outlook.Application") 
Set objItem = OutlookApp.CreateItem(olMailItem)  

With objItem 
 .To = "destinatario@ejemplo.com" 'Para
 .CC = "segundodestinatario@ejemplo.com" 'Con copia
 .Subject = "Prueba" 'Asunto
 .Body = "Este es un mensaje de prueba" 'Cuerpo 
 .Send
End With

Set OutlookApp = Nothing 
Set objItem = Nothing 

End Sub 

Si deseamos poder ir cambiando el correo de destino o el texto del cuerpo del mensaje o etc., sin tener que modificar la macro, podemos colocar los datos en celdas o variables:

With objItem
 .To = Range("A1").Value     
 .CC = Range("A2").Value     
 .Subject = Range("A3").Value     
 .Body = Range("A4").Value     
 .Send 
End With 

En este momento ya se deben de haber dado cuenta (o ya sabían) que el cuerpo del mensaje se envía sin formato y quizá lo que queremos es más bien que dicho mensaje tenga formato como ya estamos, casi todos, acostumbrados hoy en día cuando usamos el correo electronico. Para lograr eso ya no debemos usar la propiedad “Body” sino que ahora usaremos la propiedad “HTMLBody” pero tendremos que aplicar algo de “HTML” en nuestro VBA:

.HTMLBody = "<html>" & _ 
"<body><font color=""#FF0000"" size=""6"" face=""Comic Sans MS, cursive""><strong>Hola mi querido y estimado amigo</strong></font>" & _ 
"</body></html>" 
En este caso el mensaje se envía en letra cursiva de color rojo usando “Comic Sans” como fuente. Para ayudarnos con el código "HTML", podemos usar un programa como el “DreamWeaver” o un editor de “HTML” en línea, solo hay que adaptar lo que obtengamos de él para agregarlo a nuestra macro.

Si lo que queremos, además, es adjuntar algún archivo a nuestro mensaje, debemos usar la propiedad “Attachments” y su método “Add”. Podemos agregar más de un archivo del siguiente modo:

.Attachments.Add "D:\Miarchivouno.xlsm" 
.Attachments.Add "D:\MiArchivoNuevo.xlsx" 

Es bueno recordar que también podemos usar un bucle y/o variables para agregar más archivos.

Siguiendo con los adjuntos, probablemente tengamos nuestra firma en formato “JPG” y queremos incluirla en el cuerpo del mensaje; de ser así, lo primero que debemos hacer es adjuntar el archivo:

.Attachments.Add “D:\MiFirma.jpg"

Después incluiremos dicha imagen en el cuerpo del mensaje del siguiente modo y/o similar:

.HTMLBody = "<html>" & _
        "<body>" & _
           "<p>Aqui tu mensaje</p>" & _
            "<br>" & _ 
            "<br>" & _
            "<img src='cid:'" & .Attachments.Item(1).Filename & "'' height=100 width=75>" & _
            "</body>" & _
            "</html>" 
Los archivos adjuntos tienen un índice, si se tiene más archivos adjuntos, considerar el índice adecuado. En este caso he usado el uno (1).

Hasta la próxima.

Abraham Valencia

PD: En realidad cuando se usa el objeto "Outlook", y sobre todo se nota cuando se hacen envíos masivos, lo que ocurre es que se van colocando los mensajes en la "Bandeja de salida" así que es recomendable que se tenga el Microsoft Outlook configurado para el envío automático al abrir/cerrar para que el proceso continúe el envío así se cierre el Excel. Igual si se desea que se haga casi al instante el envío desde la macro, se puede añadir un Application.Wait después del "Send" o tener el Outlook abierto.

Extras:

En ocasiones deseamos enviar un rango de nuestra hoja como parte del cuerpo del mensaje, hay algunas alternativas como convertir el rango en imagen y colocarla en el cuerpo del mensaje, similar a lo que se hace con las firmas pero la mejor alternativa que he visto es usar una “Función Definida por el Usuario” (UDF) que convierte el rango en lenguaje “HTML” y permite incluirlo en el cuerpo del mensaje a través de la propiedad “HTMLBody”. EL autor es Ron de Bruin y la UDF podemos encontrarla aquí:

http://www.rondebruin.nl/win/s1/outlook/bmail2.htm

Cuando tenemos más de un correo configurado en el Outlook, recomiendo usar una UDF (Autor: Antoni - Galicia, España) para poder elegir el correo que queremos usar:

https://ayudaexcel.com/foro/topic/32737-elegir-cuenta-de-correo-de-outlook/

De no elegir alguno de los correos con la UDF, se usará el correo configurado como predeterminado.