Imagina que cada lunes tienes que escribir el mismo correo a una lista de proveedores, cambiar el nombre del archivo adjunto y mandarlo uno a uno. Con una macro de VBA ese trabajo se reduce a pulsar un botón en tu hoja y dejar que Excel haga el resto. En este tutorial aprenderás a enviar correos desde Excel con VBA de dos maneras: usando Outlook cuando lo tienes instalado en el equipo, o por SMTP directo cuando no hay Outlook ni quieres abrirlo. El libro que vamos a construir es una hoja «Campaña» con destinatario, asunto, cuerpo, adjunto y estado del envío; la macro que la recorre y la macro que la dispara se quedan dentro del propio archivo .xlsm para que solo tengas que abrirlo y ejecutar.
Las funciones VBA están disponibles desde Excel 2007 en cualquier versión de escritorio para Windows con la pestaña Programador visible y el libro guardado como .xlsm. Si usas Excel para la web, Excel para Mac o la app de móviles, las macros VBA no se ejecutan: para automatizar correos allí necesitas Scripts de Office, Power Automate o AppleScript, no VBA.
Qué es enviar correo desde Excel con VBA y cuándo tiene sentido
Enviar correo desde Excel con VBA es programar una macro que toma datos de una hoja (destinatarios, asunto, cuerpo, adjuntos) y manda un mensaje por cada fila, sin que tengas que abrir Outlook a mano. La idea es simple: una hoja con los datos del envío en columnas, una macro asociada a un botón y, al pulsar, cada fila se transforma en un correo personalizado.
Este sistema tiene sentido cuando repites envíos periódicos con poca variación: recordatorios de pago, avisos de pedido, certificados, nóminas, comunicados internos. También cuando quieres conservar un registro automático del envío (quién, cuándo y con qué adjunto) sin depender de la bandeja de salida de Outlook. Lo que no tiene sentido es cuando la plantilla cambia casi en cada correo: ahí sigue siendo más rápido escribirlo a mano.
Lo que necesita tu Excel antes de escribir una macro de correo
- Excel de escritorio en Windows, con la pestaña Programador visible. No funciona en Excel para la web ni en Excel para Mac (en Mac las macros VBA requieren una versión reciente con el subsistema compatible).
- Outlook instalado y con un perfil configurado, si vas a usar el Modelo de objetos de Outlook. Sin perfil, VBA pide el perfil en cada ejecución.
- Guardar el archivo como .xlsm (Libro de Excel habilitado para macros); en formato .xlsx las macros desaparecen al guardar.
- Para envíos por SMTP sin Outlook, basta con una cuenta de correo que permita acceso SMTP (Gmail, Outlook.com, el servidor de tu empresa) y la referencia a Microsoft CDO for Windows 2000 Library activada.
- Si vas a adjuntar archivos, una carpeta local accesible desde Excel y la ruta escrita en una celda o en una constante de la macro.
- Permisos de la organización: Outlook corporativo y algunos servidores SMTP bloquean el envío automático cuando lo consideraspam. Confirma con tu departamento de TI antes de programar envíos masivos.
Las dos formas de enviar correo desde VBA y sus piezas
VBA puede mandar correo por dos caminos distintos. El primero es controlar Outlook desde VBA: abres una instancia de Outlook a través del Modelo de objetos, creas un objeto MailItem, le escribes destinatario, asunto, cuerpo y adjuntos, y llamas a .Send para que Outlook se encargue del envío. Es el camino más sencillo cuando Outlook ya está abierto y configurado, porque se aprovecha la misma cuenta, la misma firma y el mismo servidor que usas a diario.
El segundo camino es enviar por SMTP usando CDO (Collaboration Data Objects). Aquí no se abre Outlook: VBA instancia un objeto CDO.Message, rellena sus propiedades (.To, .CC, .BCC, .Subject, .TextBody o .HTMLBody, .AddAttachment), configura los campos del servidor en .Configuration.Fields y llama a .Send. Es el camino cuando no hay Outlook en el equipo, cuando no quieres que aparezca ningún programa de correo o cuando necesitas un servidor SMTP distinto al de Outlook.
En ambos casos los objetos que creas tienen propiedades muy parecidas: destinatario, copia, copia oculta, asunto, cuerpo y adjuntos. La diferencia está en el «envoltorio»: Outlook.Application + MailItem frente a CDO.Message + Configuration.Fields.
Lo que el Modelo de objetos de Outlook pone sobre la mesa
El Modelo de objetos de Outlook expone, entre otros, Outlook.Application (el propio Outlook), NameSpace (para acceder a cuentas y carpetas), MailItem (un mensaje) y Attachments (la colección de adjuntos del mensaje). Para usarlo desde VBA hay que activar la referencia Herramientas > Referencias del editor VBA y marcar Microsoft Outlook XX.X Object Library. Una vez marcada, IntelliSense muestra las propiedades de cada objeto al escribirlas.
El flujo típico es: crear el objeto Application, crear un MailItem con .CreateItem(0) (0 = olMailItem), rellenar sus propiedades y, según lo que necesites, llamar a .Display para previsualizar o a .Send para enviar. Termina liberando memoria con Set objMail = Nothing y, si abriste Outlook desde VBA, con Set objOutlook = Nothing.
Lo que CDO (CDO.Message) añade cuando envías por SMTP
CDO.Message es un objeto que trae VBA para componer y enviar mensajes por SMTP sin pasar por Outlook. Se activa la referencia Microsoft CDO for Windows 2000 Library y se usa el espacio de nombres CDO. Sus campos clave son:
- .Configuration.Fields: aquí se escribe la URL del servidor (http://schemas.microsoft.com/cdo/configuration/sendusing), el servidor smtp (smtpserver), el puerto (smtpserverport: 25 sin cifrar, 465 con SSL, 587 con TLS), el tipo de autenticación (smtpauthenticate) y, si hace falta, usuario (sendusername) y contraseña (sendpassword).
- .To, .CC, .BCC, .Subject, .TextBody, .HTMLBody.
- .AddAttachment para adjuntar.
- .Update tras cambiar .Configuration.Fields y antes de .Send.
La propiedad .Send hace el envío y devuelve el control a la macro en cuanto el mensaje sale del cliente, no cuando llega al destinatario.
Activar la pestaña Programador y abrir el editor de VBA
- Abre Excel y ve a
Archivo > Opciones > Personalizar cinta de opciones. - En la columna de la derecha, marca la casilla
Programadory pulsaAceptar. - La pestaña Programador aparece a la derecha de Vista. Pulsa
Programador > Visual Basico usa el atajo Alt+F11 para abrir el editor de VBA. - En el editor, ve a
Insertar > Módulopara crear un módulo en blanco donde escribirás las macros. - Para volver a la hoja, cierra el editor o usa Alt+F11 de nuevo.
Tu primer macro: enviar un correo con Outlook desde VBA
La primera macro envía un único correo fijo para que veas las piezas. Después la convertiremos en un envío masivo leyendo celdas.
Copia este código en un módulo nuevo y ejecútalo con F5 o desde la hoja con Alt+F8 > Ejecutar. La macro usa primero .Display para que veas la ventana del mensaje, y al final reemplaza por .Send para enviarlo de verdad.
Sub EnviarUnoOutlook()
Dim objOutlook As Object
Dim objMail As Object
Set objOutlook = CreateObject("Outlook.Application")
Set objMail = objOutlook.CreateItem(0)
With objMail
.To = "destinatario@ejemplo.com"
.CC = ""
.BCC = ""
.Subject = "Prueba desde VBA"
.Body = "Hola, este correo se ha enviado desde una macro de Excel." & vbCrLf & _
"Si lo recibes, la macro funciona."
' .Display ' descomenta para ver el correo antes de enviarlo
.Send
End With
Set objMail = Nothing
Set objOutlook = Nothing
End Sub
1. Asegúrate de que Outlook está abierto y tiene un perfil configurado.
2. En el editor VBA (Alt+F11), inserta un módulo nuevo: Insertar > Módulo.
3. Pega el código anterior tal cual.
4. Cambia "destinatario@ejemplo.com" por tu propio correo.
5. Pulsa F5 dentro del módulo para ejecutar la macro.
6. Outlook enviará el mensaje; revisa tu bandeja de entrada.
Leer destinatario, asunto y cuerpo desde celdas
Pasamos de un correo fijo a uno que toma los datos de la hoja. Crea la pestaña Campaña y rellena las celdas:
| A | B | C | D | |
|---|---|---|---|---|
| 1 | Para | Asunto | Cuerpo | Adjunto |
| 2 | juan@ejemplo.com | Recibo de marzo | Hola, adjunto el recibo de este mes. | C:\Recibos\recibo_juan.pdf |
Sub EnviarDesdeCeldas()
Dim objMail As Object
Set objMail = CreateObject("Outlook.Application").CreateItem(0)
With objMail
.To = Worksheets("Campaña").Range("A2").Value
.Subject = Worksheets("Campaña").Range("B2").Value
.Body = Worksheets("Campaña").Range("C2").Value
.Send
End With
Set objMail = Nothing
End Sub
Adjuntar un archivo comprobando antes que existe
Añadimos un adjunto con seguridad: antes de llamar a .Attachments.Add, comprobamos con Dir() que el archivo está donde dice la hoja.
| A | B | C | D | E | |
|---|---|---|---|---|---|
| 1 | Para | Asunto | Cuerpo | Adjunto | Existe |
| 2 | juan@ejemplo.com | Recibo de marzo | Hola, adjunto el recibo. | C:\Recibos\recibo_juan.pdf | =SI(LARGO(DIR(D2))=0;"No";"Sí") |
| 3 | ana@ejemplo.com | Recibo de marzo | Hola, adjunto el recibo. | C:\Recibos\recibo_ana.pdf | =SI(LARGO(DIR(D3))=0;"No";"Sí") |
LARGO se llama LEN en inglés; DIR se llama DIR. LARGO(DIR(D2)) mide la longitud de la cadena que devuelve DIR: si vale 0 es que el archivo no existe.Sub EnviarConAdjunto()
Dim objMail As Object
Dim ruta As String
Set objMail = CreateObject("Outlook.Application").CreateItem(0)
ruta = Worksheets("Campaña").Range("D2").Value
With objMail
.To = Worksheets("Campaña").Range("A2").Value
.Subject = Worksheets("Campaña").Range("B2").Value
.Body = Worksheets("Campaña").Range("C2").Value
If Len(Dir(ruta)) > 0 Then .Attachments.Add ruta
.Send
End With
Set objMail = Nothing
End Sub
Enviar el mismo correo a una lista de destinatarios
Ahora la hoja crece hasta diez destinatarios y la macro los recorre uno a uno. Esto preserva la privacidad: cada MailItem se envía por separado, sin que los destinatarios vean las direcciones de los demás.
| A | B | C | D | E | F | G | |
|---|---|---|---|---|---|---|---|
| 1 | Para | Asunto | Cuerpo | Adjunto | Existe | CC | SendStatus |
| 2 | juan@ejemplo.com | Campaña marzo | Adjunto el documento. | C:\Campana\carta.pdf | Sí | ||
| 3 | ana@ejemplo.com | Campaña marzo | Adjunto el documento. | C:\Campana\carta.pdf | Sí | ||
| 4 | luis@ejemplo.com | Campaña marzo | Adjunto el documento. | C:\Campana\carta.pdf | Sí | ||
| 5 | pedro@ejemplo.com | Campaña marzo | Adjunto el documento. | C:\Campana\carta.pdf | Sí |
Sub EnviarListaOutlook()
Dim objMail As Object
Dim i As Long
Dim ultimo As Long
ultimo = Worksheets("Campaña").Cells(Rows.Count, 1).End(xlUp).Row
Application.ScreenUpdating = False
For i = 2 To ultimo
If Len(Trim(Worksheets("Campaña").Cells(i, 1).Value)) = 0 Then GoTo Siguiente
Set objMail = CreateObject("Outlook.Application").CreateItem(0)
With objMail
.To = Worksheets("Campaña").Cells(i, 1).Value
.Subject = Worksheets("Campaña").Cells(i, 2).Value
.Body = Worksheets("Campaña").Cells(i, 3).Value
If Len(Dir(Worksheets("Campaña").Cells(i, 4).Value)) > 0 Then
.Attachments.Add Worksheets("Campaña").Cells(i, 4).Value
End If
.Send
End With
Worksheets("Campaña").Cells(i, 7).Value = "Enviado"
Set objMail = Nothing
Siguiente:
Next i
Application.ScreenUpdating = True
MsgBox "Envíos terminados: " & ultimo - 1 & " filas procesadas."
End Sub
Una sola copia para todos con CC o CCO
Si no necesitas personalizar el correo por destinatario, puedes enviar un único mensaje con todos en .To o en .CC. Con .BCC (copia oculta) ninguno ve las direcciones de los demás.
Sub EnviarCCOYCCO()
Dim objMail As Object
Dim destinos As String
Dim copia As String
Dim oculto As String
Set objMail = CreateObject("Outlook.Application").CreateItem(0)
destinos = "juan@ejemplo.com;ana@ejemplo.com;luis@ejemplo.com"
copia = "jefe@ejemplo.com"
oculto = "auditoria@ejemplo.com"
With objMail
.To = destinos ' cada destinatario ve el resto del grupo
.CC = copia ' copia visible
.BCC = oculto ' copia oculta: nadie ve esta dirección
.Subject = "Convocatoria de reunión"
.Body = "Nos vemos el jueves a las 10:00."
.Send
End With
Set objMail = Nothing
End Sub
.To o .BCC. Si usas .To = "juan@ejemplo.com,ana@ejemplo.com" con coma, Outlook interpreta solo la primera dirección.Enviar por SMTP con CDO cuando no hay Outlook
Cuando el equipo no tiene Outlook, o cuando necesitas usar un servidor SMTP distinto del corporativo, entra CDO. Esta macro envía un correo por Gmail SMTP; cambia los valores por los de tu servidor.
1. En el editor VBA, abre Herramientas > Referencias y marca "Microsoft CDO for Windows 2000 Library".
2. Inserta un módulo nuevo y pega el código siguiente.
3. Sustituye smtp.gmail.com, el puerto 465 y tu usuario/contraseña por los de tu servidor.
4. Para Gmail usa una "contraseña de aplicación" específica, no la contraseña normal.
5. Ejecuta con F5 y revisa la bandeja del destinatario.
Sub EnviarPorSMTP()
Dim objMsg As Object
Dim objConf As Object
Dim campos As Object
Set objMsg = CreateObject("CDO.Message")
Set objConf = objMsg.Configuration
Set campos = objConf.Fields
With campos
.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "smtp.gmail.com"
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 465
.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1
.Item("http://schemas.microsoft.com/cdo/configuration/sendusername") = "tu_cuenta@gmail.com"
.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "tu_contraseña_de_aplicacion"
.Item("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = True
.Update
End With
With objMsg
.To = "destinatario@ejemplo.com"
.From = "tu_cuenta@gmail.com"
.Subject = "Prueba SMTP desde VBA"
.TextBody = "Hola, este correo llegó por SMTP sin abrir Outlook."
.Send
End With
Set objMsg = Nothing
End Sub
Cuerpo en HTML frente a texto plano en el MailItem
Con Outlook y con CDO puedes enviar dos tipos de cuerpo. .Body envía texto plano; .HTMLBody envía HTML y permite tablas, negritas, enlaces e imágenes inline. En Outlook, además, .HTMLBody arrastra la firma automática del usuario; .Body la pierde.
With objMail
.To = "destinatario@ejemplo.com"
.Subject = "Resumen mensual"
.Body = "Resumen en texto plano."
' Para HTML, comenta la línea anterior y descomenta las siguientes:
.HTMLBody = "<h3>Resumen mensual</h3><table border='1'>" & _
"<tr><td>Producto</td><td>Importe</td></tr>" & _
"<tr><td>Cuadernos</td><td>320,50</td></tr>" & _
"<tr><td>Lápices</td><td>85,00</td></tr>" & _
"</table><p>Saludos.</p>"
.Send
End With
& lt; y & gt; en este artículo; en la macro VBA escríbelas con los símbolos reales menor-que y mayor-que.Errores habituales al enviar correos desde VBA
No tienes perfil de Outlook configurado
La macro se detiene al crear el objeto Outlook.Application y Windows muestra un cuadro pidiendo que elijas un perfil o que crees uno. La causa es que VBA necesita un perfil de Outlook válido para abrir la aplicación. El arreglo: abre Outlook una vez, completa la configuración inicial (cuenta, servidor, contraseña) hasta que veas tu bandeja, guarda y cierra. La próxima vez que la macro ejecute, usará ese perfil sin pedirlo.
Error 1004 "Se ha producido un error definido por la aplicación"
Aparece en la línea objMail.Send o al asignar la propiedad. Las causas más comunes son: la macro escribe una fórmula en una celda con Range.Formula usando nombres en español; la referencia a "Microsoft Outlook XX.X Object Library" no está activada; o Outlook está abierto en modo seguro. El arreglo: usa .FormulaLocal y .FormulaR1C1Local para fórmulas en español con punto y coma, o bien escribe la fórmula en inglés con comas para .Formula y .FormulaR1C1; activa la referencia de Outlook en Herramientas > Referencias; reinicia Outlook en modo normal (sin /safe).
"El servidor rechazó una o varias direcciones"
Outlook muestra este aviso y deja el mensaje en la Bandeja de salida sin enviar. La causa casi siempre es una dirección vacía, mal escrita o con espacios sobrantes. El arreglo: valida el destinatario antes de asignarlo a .To:
Dim dest As String
dest = Worksheets("Campaña").Cells(i, 1).Value
If Len(Trim(dest)) = 0 Or InStr(dest, "@") = 0 Then
Worksheets("Campaña").Cells(i, 7).Value = "Fallo"
GoTo Siguiente
End If
El adjunto no llega al destinatario
La columna SendStatus dice "Enviado" pero el receptor no ve el adjunto. La causa es una ruta mal escrita: barras invertidas sin escapar, carpeta compartida caída o nombre de archivo con tilde que la codificación del adjunto transforma. El arreglo: valida la ruta antes de añadirla:
Dim ruta As String
ruta = Worksheets("Campaña").Cells(i, 4).Value
If Len(Dir(ruta)) = 0 Then
Worksheets("Campaña").Cells(i, 7).Value = "Fallo"
GoTo Siguiente
End If
.Attachments.Add ruta
Las macros están deshabilitadas por seguridad
Al abrir el .xlsm, aparece una barra amarilla que dice "Las macros se han deshabilitado" y la macro no se ejecuta. La causa es que Excel bloquea las macros de archivos descargados de internet o de correo por defecto. El arreglo: abre el archivo en el Explorador de Windows, clic derecho > Propiedades, en la pestaña General marca la casilla "Desbloquear" y acepta; también puedes añadir la carpeta del libro a la zona de confianza desde Archivo > Opciones > Centro de confianza > Configuración del Centro de confianza > Ubinas de confianza.
Lo que VBA no puede hacer al enviar correo y sus alternativas
VBA solo se ejecuta en Excel de escritorio para Windows (y con limitaciones, en Excel para Mac desde versiones recientes). Excel para la web, Excel para iPad y Excel para Android ignoran por completo las macros VBA: si guardas el libro en OneDrive y lo abres desde el navegador, los botones no hacen nada y el editor VBA no existe.
Para esos entornos las alternativas son otras. Excel para la web automatiza con Scripts de Office (JavaScript moderno) y con Power Automate, que de hecho se integra con Excel para la web y puede mandar correos cuando se cumple una condición en una hoja. En Mac sin compatibilidad VBA, AppleScript controla Outlook o Mail.app y dispara envíos desde una hoja abierta. Si tu organización usa Microsoft 365, el siguiente paso natural es combinar tu macro de escritorio con un flujo de Power Automate que ejecute envíos programados sin abrir Excel.
Lo que ya sabes hacer enviando correos desde Excel
- Activar la pestaña Programador, abrir el editor VBA con Alt+F11 y crear módulos para escribir macros.
- Enviar un correo simple con Outlook desde VBA usando
Outlook.Application,MailItem,.To,.Bodyy.Send. - Leer destinatario, asunto, cuerpo y ruta de adjunto desde celdas de una hoja y enviar un correo personalizado por cada fila.
- Adjuntar archivos comprobando antes con
Dir()que el archivo existe, y registrar el estado del envío en una columna SendStatus. - Configurar el envío por SMTP con CDO.Message cuando no hay Outlook, usando
Configuration.Fields, puerto 465/587 y autenticación. - Identificar y arreglar los cinco errores más habituales: perfil de Outlook ausente, error 1004 por referencia o idioma, direcciones rechazadas, adjuntos que no llegan y macros bloqueadas por seguridad.
El siguiente paso lógico es mover los envíos a un flujo programado con Power Automate que dispare tu macro de Outlook a una hora fija cada lunes, o pasarse a Power Query para alimentar la hoja Campaña desde una base de datos y dejar VBA solo para el envío.
Dudas al enviar correos desde Excel con VBA
1. ¿Cómo puedo enviar un correo desde Excel con VBA a varios destinatarios a la vez?
Con Outlook como programa de correo y la instrucción CDO de VBA puedes meter varios destinatarios separados por punto y coma en la variable .To del correo, por ejemplo: .To = "ana@correo.com; luis@correo.com". Si prefieres no listarlos uno a uno, ponlos en una hoja (por ejemplo A2:A10) y recorre el rango con un bucle For Each para enviar un mensaje individual a cada uno sin escribir las direcciones a mano.
Fuentes
- MicrosoftLAMBDA — documentación oficialconsultado el 13/10/2026
- MicrosoftRange.Formula, FormulaLocal, FormulaR1C1 y FormulaR1C1Local — documentación oficialconsultado el 13/10/2026
- MicrosoftEl editor de VBA y la primera macro — documentación oficialconsultado el 13/10/2026
- MicrosoftAtajos que funcionan igual en cualquier idioma — documentación oficialconsultado el 13/10/2026