Sub EnviarCorreosMasivos()
' ==========================================================
' CONFIGURACIÓN GENERAL (Personaliza aquí)
' ==========================================================
' ModoPrueba: True para previsualizar / False para enviar directamente.
Dim ModoPrueba As Boolean: ModoPrueba = True
' TextoEstado: Lo que aparecerá en la columna "Estado" al terminar.
Dim TextoEstado As String: TextoEstado = "Enviado: " & Format(Now, "dd/mm hh:mm")
' AsuntoPredeterminado: Se usará si no existe la columna "Asunto".
Dim AsuntoPredeterminado As String: AsuntoPredeterminado = "Notificación de Pago Pendiente"
' Plantilla: Cuerpo del mensaje. Usa {NombreColumna} para datos dinámicos.
Dim Plantilla As String
Plantilla = "Estimado(a) {Nombre},
" & _
"Le informamos que el pago para el apartamento {Apartamento} " & _
"presenta un saldo de {Monto}.
" & _
"Cordialmente,
Dostin Hurtado."
' ==========================================================
' MOTOR LÓGICO (No requiere edición)
' ==========================================================
ProcesarEnvioTablas ModoPrueba, TextoEstado, Plantilla, AsuntoPredeterminado
End Sub
' --- SUBRUTINAS TÉCNICAS (PRIVADAS) ---
Private Sub ProcesarEnvioTablas(Prueba As Boolean, MsgEstado As String, PlantillaBase As String, AsuntoDef As String)
Dim Tabla As ListObject: Set Tabla = ActiveCell.ListObject
Dim AplicacionOutlook As Object, CorreoElectronico As Object
Dim FilaSeleccionada As Range, FilaDatos As Range
Dim CuerpoFinal As String, Columna As ListColumn
Dim Exitos As Integer, Fallidos As Integer, TotalSeleccionado As Integer
Dim AsuntoFinal As String, RutaAdjunto As String, CorreoDestino As String
Dim RangoVisible As Range
' Validación de Tabla
If Tabla Is Nothing Then
MsgBox "Para ejecutar el proceso, haga clic dentro de una tabla (Ctrl + T).", vbInformation, "Sistema de Envío"
Exit Sub
End If
' Capturar solo las celdas visibles de la selección actual
On Error Resume Next
Set RangoVisible = Selection.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If RangoVisible Is Nothing Then
MsgBox "No hay celdas visibles seleccionadas.", vbExclamation, "Atención"
Exit Sub
End If
' 1. CONTEO PREVENTIVO (Solo visibles y dentro de la tabla)
Exitos = 0: Fallidos = 0: TotalSeleccionado = 0
For Each FilaSeleccionada In RangoVisible.Rows
Set FilaDatos = Intersect(FilaSeleccionada, Tabla.DataBodyRange)
If Not FilaDatos Is Nothing Then TotalSeleccionado = TotalSeleccionado + 1
Next FilaSeleccionada
If TotalSeleccionado = 0 Then
MsgBox "No se seleccionaron filas visibles con datos dentro de la tabla.", vbExclamation, "Atención"
Exit Sub
End If
' Confirmación amigable
If MsgBox("Se han detectado " & TotalSeleccionado & " registros visibles. ¿Deseas iniciar?", vbQuestion + vbYesNo, "Confirmar Operación") = vbNo Then Exit Sub
' Inicializar Outlook
On Error Resume Next
Set AplicacionOutlook = GetObject(, "Outlook.Application")
If AplicacionOutlook Is Nothing Then Set AplicacionOutlook = CreateObject("Outlook.Application")
On Error GoTo 0
' 2. CICLO DE PROCESAMIENTO
For Each FilaSeleccionada In RangoVisible.Rows
Set FilaDatos = Intersect(FilaSeleccionada, Tabla.DataBodyRange)
If Not FilaDatos Is Nothing Then
CorreoDestino = CapturarValorCelda(Tabla, FilaDatos, "Correo")
If InStr(CorreoDestino, "@") > 0 Then
AsuntoFinal = CapturarValorCelda(Tabla, FilaDatos, "Asunto")
If AsuntoFinal = "" Then AsuntoFinal = AsuntoDef
CuerpoFinal = PlantillaBase
For Each Columna In Tabla.ListColumns
CuerpoFinal = Replace(CuerpoFinal, "{" & Columna.Name & "}", Intersect(FilaDatos.EntireRow, Columna.Range).Text)
Next Columna
Set CorreoElectronico = AplicacionOutlook.CreateItem(0)
With CorreoElectronico
.To = CorreoDestino
.Subject = AsuntoFinal
.HTMLBody = CuerpoFinal
RutaAdjunto = CapturarValorCelda(Tabla, FilaDatos, "Adjunto")
If RutaAdjunto <> "" And Dir(RutaAdjunto) <> "" Then .Attachments.Add RutaAdjunto
If Prueba Then .Display Else .Send
End With
EscribirValorCelda Tabla, FilaDatos, "Estado", MsgEstado
Exitos = Exitos + 1
Else
EscribirValorCelda Tabla, FilaDatos, "Estado", "Error: Correo inválido"
Fallidos = Fallidos + 1
End If
End If
Next FilaSeleccionada
MsgBox "Proceso finalizado." & vbCrLf & vbCrLf & _
"- Envíos realizados: " & Exitos & vbCrLf & _
"- Errores encontrados: " & Fallidos, vbInformation, "Resumen Dostin Hurtado"
End Sub
Private Function CapturarValorCelda(TblObj As ListObject, FilaRng As Range, NombreCol As String) As String
On Error Resume Next
CapturarValorCelda = Intersect(FilaRng.EntireRow, TblObj.ListColumns(NombreCol).Range).Text
End Function
Private Sub EscribirValorCelda(TblObj As ListObject, FilaRng As Range, NombreCol As String, ValorTxt As String)
On Error Resume Next
Intersect(FilaRng.EntireRow, TblObj.ListColumns(NombreCol).Range).Value = ValorTxt
End Sub