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