Collect dynamic number of rows for each recipient - excel

Once the macro begins, it runs all line items in the spreadsheet instead of the ones I specified.
The purpose of the program is to send emails to the correct person and append any additional rows with their name.
For each unique email I want to collect all of the data.
The issue is that the email contents are dynamic and the body of the email includes a chart with appended row items for each recipient. The spreadsheet contains more than one row for each recipient.
Due to the sensitive nature of the source data I included an image of the column headers.
Option Explicit
Sub Send()
Dim rEmailAddr As Range, rCell As Range, rNext As Range
Dim NmeRow As Long, x As Long
Dim MailTo As String, MailSubject As String, MailBody As String, AddRow As String, tableHdr As String, MsgStr As String
Dim OutApp As Object, OutMail As Object
Dim CurrentEmail As String, LastEmail As String
If OutApp Is Nothing Then
'Outlook is not opened, so open
Set OutApp = CreateObject("Outlook.Application")
End If
'Set email address as range for first loop to run down
Set rEmailAddr = Range(Range("D2"), Range("D" & Rows.Count).End(xlUp))
'MailSubject does not change, so only needs to be created once
MailSubject = "Action and Response Requested - Reserve Review for Claim(s)"
'Get a row count to clear column AM at the end
x = rEmailAddr.Rows.Count
'Create the html table and header from the first row
tableHdr = "<table border=1><tr><th>" & Range("G1").Value & "</th>" _
& "<th>" & Range("H1").Value & "</th>" _
& "<th>" & Range("I1").Value & "</th>" _
& "<th>" & Range("J1").Value & "</th>" _
& "<th>" & Range("K1").Value & "</th>" _
& "<th>" & Range("L1").Value & "</th>" _
& "<th>" & Range("M1").Value & "</th>" _
& "<th>" & Range("N1").Value & "</th>" _
& "<th>" & Range("O1").Value & "</th>" _
& "<th>" & Range("P1").Value & "</th>" _
& "<th>" & Range("T1").Value & "</th>" _
& "<th>" & Range("U1").Value & "</th>" _
& "<th>" & Range("V1").Value & "</th>" _
& "<th>" & Range("W1").Value & "</th>" _
& "<th>" & Range("X1").Value & "</th>" _
& "<th>" & Range("Y1").Value & "</th>" _
& "<th>" & Range("Z1").Value & "</th>" _
& "<th>" & Range("AA1").Value & "</th>" _
& "<th>" & Range("AB1").Value & "</th>" _
& "<th>" & Range("AC1").Value & "</th>" _
& "<th>" & Range("AD1").Value & "</th>" _
'Check to see if column Q = 'yes' and skip mail if it does
CurrentEmail = ""
LastEmail = ""
For Each rCell In rEmailAddr
CurrentEmail = Replace(rCell.Value, " ", "")
If ((rCell.Value <> "") And CurrentEmail <> LastEmail) Then
NmeRow = rCell.Row
MailTo = rCell.Value 'column D
'Create MailBody table row for first row
MailBody = "<tr>" _
& "<td>" & (rCell.Offset(0, 3).Value) & "</td>" _
& "<td>" & (rCell.Offset(0, 4).Value) & "</td>" _
& "<td>" & (rCell.Offset(0, 5).Value) & "</td>" _
& "<td>" & (rCell.Offset(0, 6).Value) & "</td>" _
& "<td>" & (rCell.Offset(0, 7).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 8).Value) & "</td>" _
& "<td>" & (rCell.Offset(0, 9).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 10).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 11).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 12).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 16).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 17).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 18).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 19).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 20).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 21).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 22).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 23).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 24).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 25).Value) & "</td>" _
& "<td>" & CStr(rCell.Offset(0, 26).Value) & "</td>" _
& "</tr>"
'Second loop checks the email addresses of all cells following the current cell in the first loop.
'Yes will be appended on any duplicate finds and another row added to the mailbody table
For Each rNext In rEmailAddr.Offset(NmeRow - 1, 0).Resize(x - NmeRow) 'process to last row only
If Replace(rNext.Value, " ", "") = Replace(rCell.Value, " ", "") Then
'Create additional table row for each extra row found"
AddRow = "<tr>" _
& "<td>" & CStr(rNext.Offset(0, 3).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 4).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 5).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 6).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 7).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 8).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 9).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 10).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 11).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 12).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 16).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 17).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 18).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 19).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 20).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 21).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 22).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 23).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 24).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 25).Value) & "</td>" _
& "<td>" & CStr(rNext.Offset(0, 26).Value) & "</td>" _
& "</tr>"
MailBody = MailBody & AddRow
End If
'Clear additional table row variable ready for next
Next rNext
'Create email
Set OutMail = OutApp.createitem(0)
With OutMail
.to = Replace(MailTo, " ", "")
.Subject = MailSubject
.HTMLBody = tableHdr & MailBody & "</table>"
.Display
End With
LastEmail = Replace(rCell.Value, " ", "")
End If
Next rCell
End Sub

Use a dictionary (using email address as key) to group the rows for each email with a single pass down the sheet. Then loop through the dictionary keys creating each email from the rows number held as a comma separated list in the dictionary value.
Option Explicit
Sub Send()
Dim OutApp As Object, OutMail As Object
Dim sEmailAddr As String, tableHdr As String
Dim MailTo As String, Mailbody As String, MailSubject As String
Dim wb As Workbook, ws As Worksheet
Dim lastRow As Long, n As Long, i As Long
Dim k, v, arData
Dim dict As Object, fso As Object, ts As Object
Set dict = CreateObject("Scripting.Dictionary")
Set fso = CreateObject("Scripting.FileSystemObject")
Set wb = ThisWorkbook
Set ws = wb.Sheets(1) ' change to suit
' put data into an array
With ws
lastRow = .Range("D" & Rows.Count).End(xlUp).Row
arData = .Range("A1:AD" & lastRow)
End With
' compile list of rows for each address using dictionary
' key = address, value = comma separated list of rows
For i = 2 To UBound(arData)
sEmailAddr = Trim(arData(i, 4)) ' col D
sEmailAddr = Replace(sEmailAddr, " ", "")
' build list of rows for each email address
If dict.exists(sEmailAddr) Then
dict(sEmailAddr) = dict(sEmailAddr) & "," & i
Else
dict.Add sEmailAddr, i
End If
Next
'Create the html table and header from the first row
'G - P, T - AD
tableHdr = "<table border=""1"" cellspacing=""0"" cellpadding=""3""><tr>"
For n = 7 To 30
Select Case n
Case 7 To 16, 20 To 30
tableHdr = tableHdr & "<th>" & arData(1, n) & "</th>"
End Select
Next
tableHdr = tableHdr & "</tr>" & vbCr
'If OutApp Is Nothing Then
'Outlook is not opened, so open
' Set OutApp = CreateObject("Outlook.Application")
'End If
'MailSubject does not change, so only needs to be created once
MailSubject = "Action and Response Requested - Reserve Review for Claim(s)"
' send emails
For Each k In dict.keys
MailTo = k
MailBody = ""
' loop through rows for this email
For Each v In Split(dict(k), ",")
Mailbody = Mailbody & "<tr>" & vbCr
For n = 7 To 30
Select Case n
Case 7 To 11, 13
Mailbody = Mailbody & "<td>" & arData(v, n) & "</td>"
Case 12, 14 To 16, 20 To 30
Mailbody = Mailbody & "<td>" & CStr(arData(v, n)) & "</td>"
End Select
Next
Mailbody = Mailbody & "</tr>" & vbCr
Next
' dump text to file to check without outlook
Set ts = fso.createTextFile(wb.Path & "\" & MailTo & ".html", True)
ts.writeLine "To : " & MailTo & "<br/>"
ts.writeLine "Subject: " & MailSubject & "<br/>"
ts.write tableHdr & Mailbody & "</table>"
ts.Close
'Create email
'Set OutMail = OutApp.createitem(0)
'With OutMail
' .To = Replace(MailTo, " ", "")
' .Subject = MailSubject
' .HTMLBody = tableHdr & Mailbody & "</table>"
' .Display
'End With
Next
MsgBox dict.Count & " emails sent"
End Sub

Related

VBA Not processing .Body Line (or HTMLBody) in Macro

I am trying to make a macro that loops through a table on any sheet across a document and generated emails with info from that table to the individuals on each line. I think I got most of it to work but I can't figure out why .Body is no longer sending any information to outlook.
When I had shorter test messages it worked but now it isn't sending any body text to Outlook. My .To line is working fine as is my subject.
With OutMail
.To = Range("D" & i).Value
.CC = ""
.BCC = ""
.Subject = ActiveSheet.Name & " Service Insert"
'.HTMLBody = "Hi " & Range(C, i).Value & "<br><br>" & "Please see your Service Insert Below." & "<br>" & "<br>" _
& Range(S, 1).Value & "<br>" & "Services Played: " & Range(S, i).Value & "<br>" & "Doubling Services: " & Range("T" & i).Value & "<br>" & "Move Up Services: " & Range("W" & i).Value & " services from " & Range(Y, i) & "<br>" & "Solo Services: " & Range(Z, i).Value & "<br><br>" _
& Range(AA, 1).Value & "<br>" & "Services Played: " & Range(AA, i).Value & "<br>" & "Doubling Services: " & Range(AB, i).Value & "<br>" & "Move Up Services: " & Range(AE, i).Value & " services from " & Range(AG, i) & "<br>" & "Solo Services: " & Range(AH, i).Value & "<br><br>" _
& "Pay Period Totals" & "<br>" & "Total Leave Used: " & Range(F, i).Value & "<br>" & "Sick Leave Used: " & Range(i, i).Value & "<br>" & "Total Doubling Pay: " & Range(K, i).Value & "<br>" & "Total Move Up Pay: " & Range(L, i).Value & "<br>" & "Total Solo Pay: " & Range(M, i).Value & "<br>" & "Total Pay Correction: " & Range(N, i).Value & "<br>" & "Parking Reimbursement: " & Range(O, i).Value & "<br>" & "Mileage Reimbursement: " & Range(P, i).Value & "<br>" & "Travel Reimbursement: " & Range(Q, i).Value & "<br>" & "Total Additional Pay: " & Range(R, i).Value & "<br><br>" _
& "Season Totals" & "<br><br>" & "Total Season Services Used: " & Range(AZ, i).Value & "<br>" & "Sick Leave Remaining: " & Range(AY, i).Value & "<br><br>" & "Please let me know if you have any questions or concerns." & "<br><br>" & "Best, "
.Body = "Hi " & Range("C" & i).Value & vbNewLine & vbNewLine & "Please see your Service Insert Below." & vbNewLine & vbNewLine _
& Range("S1").Value & vbNewLine & "Services Played: " & Range("S" & i).Value & vbNewLine & "Doubling Services: " & Range("T" & i).Value & vbNewLine & "Move Up Services: " & Range("W" & i).Value & " services from " & Range("Y" & i) & vbNewLine & "Solo Services: " & Range("Z" & i).Value & vbNewLine & vbNewLine _
& Range("AA1").Value & vbNewLine & "Services Played: " & Range("AA" & i).Value & vbNewLine & "Doubling Services: " & Range("AB" & i).Value & vbNewLine & "Move Up Services: " & Range("AE" & i).Value & " services from " & Range("AG" & i) & vbNewLine & "Solo Services: " & Range("AH" & i).Value & vbNewLine & vbNewLine _
& "Pay Period Totals" & vbNewLine & "Total Leave Used: " & Range("F" & i).Value & vbNewLine & "Sick Leave Used: " & Range("I" & i).Value & vbNewLine & "Total Doubling Pay: " & Range("K" And i).Value & vbNewLine & "Total Move Up Pay: " & Range("L" And i).Value & vbNewLine & "Total Solo Pay: " & Range("M" And i).Value & vbNewLine & "Total Pay Correction: " & Range("N" And i).Value & vbNewLine & "Parking Reimbursement: " & Range("O" And i).Value & vbNewLine & "Mileage Reimbursement: " & Range("P" And i).Value & vbNewLine & "Travel Reimbursement: " & Range("Q" And i).Value & vbNewLine & "Total Additional Pay: " & Range("R" And i).Value & vbNewLine & vbNewLine _
& "Season Totals" & vbNewLine & vbNewLine & "Total Season Services Used: " & Range("AZ" & i).Value & vbNewLine & "Sick Leave Remaining: " & Range("AY" & i).Value & vbNewLine & vbNewLine & "Please let me know if you have any questions or concerns." & vbNewLine & vbNewLine & "Best, "
'.Attachments.Add ActiveWorkbook.FullName
.Display 'or use .Send
End With
On Error GoTo 0
This is the Body and HTMLBody I tried to make work, neither is sending any information, even failed cell searches to outlook.
I can show more of my the code if needed, for readability I hope this is enough.
Create a variable to create your body string by making some concatenations then assign the string to .Body. This way you can easily check your string and find an error by running step by step.
Dim emailBody as string: emailBody = ""
emailBody = emailBody & "Hi " & Range("C" & i).Value & vbNewLine & vbNewLine
emailBody = emailBody & "Please see your Service Insert Below." & vbNewLine & vbNewLine
emailBody = emailBody & Range("S1").Value & vbNewLine
...
With OutMail
...
.Body = emailBody
...
End With

Sub that creates a new sheet opens VBA editor for a fraction of a second

I have a strange behaviour, with both Excel 2010 and Excel 2019 (both in Windows 10 64 bit).
I have a file with lots of VBA code and a certain Sub that creates a new sheet and copies data from two other sheets.
When this Sub is called it works as expected but, for a fraction of a second, Excel opens and then closes the VBA editor.
In slower PCs the phenomenon is much more visible.
Also, if I protect the VBA Code (Tools, VBA Project properties) the Sub doesn't work as expected.
I can't explain it, any help would be highly appreciated.
Sub ConfrontoSomme(ByVal Foglio1 As String, ByVal Foglio2 As String)
On Error GoTo errore
'se esiste già il foglio lo cancello
Application.ScreenUpdating = False
NomeFoglioDaCreare = "CONFRONTO SOMME"
'ThisWorkbook.Unprotect Password:=" "
Call DeleteSheet(NomeFoglioDaCreare)
ThisWorkbook.Unprotect Password:=" "
Sheets.Add(, ActiveSheet).Name = NomeFoglioDaCreare
ThisWorkbook.Protect Password:=" "
With ActiveWindow
ActiveWindow.DisplayGridlines = False
ActiveWindow.DisplayHeadings = False
Application.DisplayFormulaBar = False
'.Zoom = 89
End With
If CustomZoom = False Then
ActiveWindow.Zoom = 89
Else
ActiveWindow.Zoom = 110
End If
'cerco l'ultima riga della colonna "C" contenente un valore
UltimaRiga1 = LastRowColumn(ThisWorkbook.Sheets(Foglio1), "r", "c")
UltimaRiga2 = LastRowColumn(ThisWorkbook.Sheets(Foglio2), "r", "c")
'lo rimetto a False in quanto il nuovo foglio è stato creato
CreazioneConfrontoSomme = False
'setto altezza prima riga:
ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("A1").RowHeight = 10
'CREO COLONNE PRIMA SOMMA
ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("B2:D2").Merge
ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("B2").Value = Foglio1
ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("B2").Select
With Selection
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
End With
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 12611584
.TintAndShade = 0
.PatternTintAndShade = 0
End With
With Selection.Font
.Name = "Arial"
.Size = 20
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ThemeColor = xlThemeColorDark1
.TintAndShade = 0
.ThemeFont = xlThemeFontNone
End With
With Selection.Borders(xlEdgeLeft)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlMedium
End With
With Selection.Borders(xlEdgeTop)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlMedium
End With
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlMedium
End With
With Selection.Borders(xlEdgeRight)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlMedium
End With
'copio intestazione con larghezza colonne e formattazione
ThisWorkbook.Sheets(Foglio1).Range("B2:D3").Copy Destination:=ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("B4:D5")
ThisWorkbook.Sheets(Foglio1).Range("B2:D3").Copy
ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("B4:D5").PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
ThisWorkbook.Sheets(NomeFoglioDaCreare).Columns("A").ColumnWidth = 1
RowHght = ThisWorkbook.Sheets(Foglio1).Range("B3").EntireRow.Height
ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("B5").RowHeight = RowHght
'+2 per differenza di riga tra foglio originario e il nuovo creato
ThisWorkbook.Sheets(Foglio1).Range("B4:D" & UltimaRiga1).Copy Destination:=ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("B6:D" & UltimaRiga1 + 2)
'=========================================================================================
'CREO COLONNE SECONDA SOMMA
ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("F2:H2").Merge
ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("F2").Value = Foglio2
ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("F2").Select
With Selection
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
End With
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 12611584
.TintAndShade = 0
.PatternTintAndShade = 0
End With
With Selection.Font
.Name = "Arial"
.Size = 20
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.Underline = xlUnderlineStyleNone
.ThemeColor = xlThemeColorDark1
.TintAndShade = 0
.ThemeFont = xlThemeFontNone
End With
With Selection.Borders(xlEdgeLeft)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlMedium
End With
With Selection.Borders(xlEdgeTop)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlMedium
End With
With Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlMedium
End With
With Selection.Borders(xlEdgeRight)
.LineStyle = xlContinuous
.ColorIndex = 0
.TintAndShade = 0
.Weight = xlMedium
End With
'copio intestazione con larghezza colonne e formattazione
ThisWorkbook.Sheets(Foglio2).Range("B2:D3").Copy Destination:=ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("F4:H5")
ThisWorkbook.Sheets(Foglio2).Range("B2:D3").Copy
ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("F4:H5").PasteSpecial Paste:=xlPasteColumnWidths, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
'COLONNA FORMULA DI CONFRONTO SX
ThisWorkbook.Sheets(NomeFoglioDaCreare).Columns("E").ColumnWidth = 25 'più larga per separare meglio le 2 sezioni
'COLONNA FORMULA DI CONFRONTO SX
ThisWorkbook.Sheets(NomeFoglioDaCreare).Columns("I").ColumnWidth = 17
'già fatto prima
'RowHght = ThisWorkbook.Sheets(Foglio1).Range("B3").EntireRow.Height
'ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("B5").RowHeight = RowHght
'+2 per differenza di riga tra foglio originario e il nuovo creato
ThisWorkbook.Sheets(Foglio2).Range("B4:D" & UltimaRiga2).Copy Destination:=ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("F6:H" & UltimaRiga2 + 2)
ThisWorkbook.Sheets(NomeFoglioDaCreare).Columns("B").ColumnWidth = 12 '7.5
ThisWorkbook.Sheets(NomeFoglioDaCreare).Columns("C").ColumnWidth = 36
ThisWorkbook.Sheets(NomeFoglioDaCreare).Columns("D").ColumnWidth = 11
ThisWorkbook.Sheets(NomeFoglioDaCreare).Columns("F").ColumnWidth = 12
ThisWorkbook.Sheets(NomeFoglioDaCreare).Columns("G").ColumnWidth = 36
ThisWorkbook.Sheets(NomeFoglioDaCreare).Columns("H").ColumnWidth = 11
'CREO LA FORMULA PER CERCARE I VALORI DELLA SOMMA A SINISTRA IN QUELLI A DESTRA
CellaPartenza = "$G$6"
CellaFine = "$G$" & UltimaRiga2 + 2
For i = 6 To UltimaRiga1 + 2
CellaPartenza2 = "$C" & i
FormulaConfronto = "=If(CountIf(" & CellaPartenza & ":" & CellaFine & "," & CellaPartenza2 & ") <> 0, """", ""Non in " & """ & $F$2)"
ThisWorkbook.Sheets(NomeFoglioDaCreare).Cells(i, 4).Formula = "" & FormulaConfronto & ""
ThisWorkbook.Sheets(NomeFoglioDaCreare).Cells(i, 4).Font.Size = 13
Next i
'CREO LA FORMULA PER CERCARE I VALORI DELLA SOMMA A DESTRA IN QUELLI A SINISTRA
CellaPartenza = "$C$6"
CellaFine = "$C$" & UltimaRiga1 + 2
For i = 6 To UltimaRiga2 + 2
CellaPartenza2 = "$G" & i
FormulaConfronto = "=If(CountIf(" & CellaPartenza & ":" & CellaFine & "," & CellaPartenza2 & ") <> 0, """", ""Non in " & """ & $B$2)"
ThisWorkbook.Sheets(NomeFoglioDaCreare).Cells(i, 8).Formula = "" & FormulaConfronto & ""
ThisWorkbook.Sheets(NomeFoglioDaCreare).Cells(i, 8).Font.Size = 13
Next i
'NEL FOGLIO CONFRONTO SOMME CREO IL PULSANTE PER ORDINARE DAL VALORE PIU' PICCOLO AL PIU' GRANDE
If CustomZoom = False Then
Set oOLE = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Left:=355, Top:=10, Width:=111, Height:=24)
Else
Set oOLE = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Left:=349.6, Top:=10, Width:=111, Height:=24)
End If
With oOLE
.Object.Caption = "Ordina Min>Mag" 'SCRITTA CHE APPARE SUL PULSANTE
.Name = "OrdinaMinMag" 'NOME MACRO CREATA NEL CODICE SALVATO NEL FOGLIO (NON IN UN MODULO)
.Object.BackColor = RGB(153, 211, 245)
'.Object.ForeColor = RGB(0, 0, 255)
.PrintObject = False
.Object.Font.Name = "CALIBRI"
.Object.Font.Size = 14
'.Object.Font.Bold = True
End With
'NEL FOGLIO CONFRONTO SOMME CREO IL CODICE MACRO PER ORDINARE DAL VALORE PIU' PICCOLO AL PIU' GRANDE, ABBINATO AL PULSANTE
'ad un certo punto ho dovuto scrivere una riga tutta di fila altrimenti appariva l'errore "troppo continuazioni di riga"
'cambia solo da "Sort.SortFields.Add" a "Sort.SortFields.Add2"
'Se > Excel 2010
If Val(Application.Version) > 14 Then
With ThisWorkbook.VBProject.VBComponents(ThisWorkbook.Sheets(NomeFoglioDaCreare).CodeName).CodeModule
.InsertLines .CreateEventProc("Click", oOLE.Name) + 1, vbTab & _
vbCrLf & vbTab & "Application.ScreenUpdating = False" & vbCrLf & vbTab & _
"Range(""C6:C305"").Select" & vbCrLf & vbTab & _
"ActiveSheet.Unprotect Password:="" """ & vbCrLf & vbTab & _
"ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Clear" & vbCrLf & vbTab & _
"ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Add2 Key:=Range(""C6:C305""), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal" & vbCrLf & vbTab & _
"With ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort" & vbCrLf & vbTab & _
".SetRange Range(""C6:C305"")" & vbCrLf & vbTab & _
".Header = xlGuess" & vbCrLf & vbTab & _
".MatchCase = False" & vbCrLf & vbTab & _
".Orientation = xlTopToBottom" & vbCrLf & vbTab & _
".SortMethod = xlPinYin" & vbCrLf & vbTab & _
".Apply" & vbCrLf & vbTab & _
"End With" & vbCrLf & vbTab & _
"Range(""G6:G305"").Select" & vbCrLf & vbTab & "ActiveSheet.Protect Password:="" """ & vbCrLf & vbTab & "ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Clear" & vbCrLf & vbTab & "ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Add2 Key:=Range(""G6:G305""), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal" & vbCrLf & vbTab & "With ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort" & vbCrLf & vbTab & ".SetRange Range(""G6:G305"")" & vbCrLf & vbTab & ".Header = xlGuess" & vbCrLf & vbTab & ".MatchCase = False" & vbCrLf & vbTab & ".Orientation = xlTopToBottom" & vbCrLf & vbTab & ".SortMethod = xlPinYin" & vbCrLf & vbTab & ".Apply" & vbCrLf & vbTab & "End With" & vbCrLf & vbTab & "Range(""A1"").Select" & vbCrLf & vbTab & "Application.ScreenUpdating = True"
Application.VBE.MainWindow.Visible = False
End With
Else
With ThisWorkbook.VBProject.VBComponents(ThisWorkbook.Sheets(NomeFoglioDaCreare).CodeName).CodeModule
.InsertLines .CreateEventProc("Click", oOLE.Name) + 1, vbTab & _
vbCrLf & vbTab & "Application.ScreenUpdating = False" & vbCrLf & vbTab & _
"Range(""C6:C305"").Select" & vbCrLf & vbTab & _
"ActiveSheet.Unprotect Password:="" """ & vbCrLf & vbTab & _
"ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Clear" & vbCrLf & vbTab & _
"ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Add Key:=Range(""C6:C305""), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal" & vbCrLf & vbTab & _
"With ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort" & vbCrLf & vbTab & _
".SetRange Range(""C6:C305"")" & vbCrLf & vbTab & _
".Header = xlGuess" & vbCrLf & vbTab & _
".MatchCase = False" & vbCrLf & vbTab & _
".Orientation = xlTopToBottom" & vbCrLf & vbTab & _
".SortMethod = xlPinYin" & vbCrLf & vbTab & _
".Apply" & vbCrLf & vbTab & _
"End With" & vbCrLf & vbTab & _
"Range(""G6:G305"").Select" & vbCrLf & vbTab & "ActiveSheet.Protect Password:="" """ & vbCrLf & vbTab & "ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Clear" & vbCrLf & vbTab & "ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Add Key:=Range(""G6:G305""), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal" & vbCrLf & vbTab & "With ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort" & vbCrLf & vbTab & ".SetRange Range(""G6:G305"")" & vbCrLf & vbTab & ".Header = xlGuess" & vbCrLf & vbTab & ".MatchCase = False" & vbCrLf & vbTab & ".Orientation = xlTopToBottom" & vbCrLf & vbTab & ".SortMethod = xlPinYin" & vbCrLf & vbTab & ".Apply" & vbCrLf & vbTab & "End With" & vbCrLf & vbTab & "Range(""A1"").Select" & vbCrLf & vbTab & "Application.ScreenUpdating = True"
Application.VBE.MainWindow.Visible = False
End With
End If
'NEL FOGLIO CONFRONTO SOMME CREO IL PULSANTE PER ORDINARE DAL VALORE PIU' GRANDE AL PIU' PICCOLO
If CustomZoom = False Then
Set oOLE = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Left:=355, Top:=50, Width:=111, Height:=24)
Else
Set oOLE = ActiveSheet.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Left:=349.6, Top:=48.6, Width:=111, Height:=24)
End If
With oOLE
.Object.Caption = "Ordina Mag>Min" 'SCRITTA CHE APPARE SUL PULSANTE
.Name = "OrdinaMagMin" 'NOME MACRO CREATA NEL CODICE SALVATO NEL FOGLIO (NON IN UN MODULO)
.Object.BackColor = RGB(153, 211, 245)
'.Object.ForeColor = RGB(0, 0, 255)
.PrintObject = False
.Object.Font.Name = "CALIBRI"
.Object.Font.Size = 14
'.Object.Font.Bold = True
End With
'NEL FOGLIO CONFRONTO SOMME CREO IL CODICE MACRO PER ORDINARE DAL VALORE PIU' GRANDE AL PIU' PICCOLO, ABBINATO AL PULSANTE
'ad un certo punto ho dovuto scrivere una riga tutta di fila altrimenti appariva l'errore "troppo continuazioni di riga"
'cambia solo da "Sort.SortFields.Add" a "Sort.SortFields.Add2"
'Se > Excel 2010
If Val(Application.Version) > 14 Then
With ThisWorkbook.VBProject.VBComponents(ThisWorkbook.Sheets(NomeFoglioDaCreare).CodeName).CodeModule
.InsertLines .CreateEventProc("Click", oOLE.Name) + 1, vbTab & _
vbCrLf & vbTab & "Application.ScreenUpdating = False" & vbCrLf & vbTab & _
"Range(""C6:C305"").Select" & vbCrLf & vbTab & _
"ActiveSheet.Unprotect Password:="" """ & vbCrLf & vbTab & _
"ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Clear" & vbCrLf & vbTab & _
"ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Add2 Key:=Range(""C6:C305""), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal" & vbCrLf & vbTab & _
"With ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort" & vbCrLf & vbTab & _
".SetRange Range(""C6:C305"")" & vbCrLf & vbTab & _
".Header = xlGuess" & vbCrLf & vbTab & _
".MatchCase = False" & vbCrLf & vbTab & _
".Orientation = xlTopToBottom" & vbCrLf & vbTab & _
".SortMethod = xlPinYin" & vbCrLf & vbTab & _
".Apply" & vbCrLf & vbTab & _
"End With" & vbCrLf & vbTab & _
"Range(""G6:G305"").Select" & vbCrLf & vbTab & "ActiveSheet.Protect Password:="" """ & vbCrLf & vbTab & "ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Clear" & vbCrLf & vbTab & "ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Add2 Key:=Range(""G6:G305""), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal" & vbCrLf & vbTab & "With ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort" & vbCrLf & vbTab & ".SetRange Range(""G6:G305"")" & vbCrLf & vbTab & ".Header = xlGuess" & vbCrLf & vbTab & ".MatchCase = False" & vbCrLf & vbTab & ".Orientation = xlTopToBottom" & vbCrLf & vbTab & ".SortMethod = xlPinYin" & vbCrLf & vbTab & ".Apply" & vbCrLf & vbTab & "End With" & vbCrLf & vbTab & "Range(""A1"").Select" & vbCrLf & vbTab & "Application.ScreenUpdating = True"
Application.VBE.MainWindow.Visible = False
End With
Else
With ThisWorkbook.VBProject.VBComponents(ThisWorkbook.Sheets(NomeFoglioDaCreare).CodeName).CodeModule
.InsertLines .CreateEventProc("Click", oOLE.Name) + 1, vbTab & _
vbCrLf & vbTab & "Application.ScreenUpdating = False" & vbCrLf & vbTab & _
"Range(""C6:C305"").Select" & vbCrLf & vbTab & _
"ActiveSheet.Unprotect Password:="" """ & vbCrLf & vbTab & _
"ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Clear" & vbCrLf & vbTab & _
"ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Add Key:=Range(""C6:C305""), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal" & vbCrLf & vbTab & _
"With ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort" & vbCrLf & vbTab & _
".SetRange Range(""C6:C305"")" & vbCrLf & vbTab & _
".Header = xlGuess" & vbCrLf & vbTab & _
".MatchCase = False" & vbCrLf & vbTab & _
".Orientation = xlTopToBottom" & vbCrLf & vbTab & _
".SortMethod = xlPinYin" & vbCrLf & vbTab & _
".Apply" & vbCrLf & vbTab & _
"End With" & vbCrLf & vbTab & _
"Range(""G6:G305"").Select" & vbCrLf & vbTab & "ActiveSheet.Protect Password:="" """ & vbCrLf & vbTab & "ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Clear" & vbCrLf & vbTab & "ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort.SortFields.Add Key:=Range(""G6:G305""), SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal" & vbCrLf & vbTab & "With ActiveWorkbook.Worksheets(""CONFRONTO SOMME"").Sort" & vbCrLf & vbTab & ".SetRange Range(""G6:G305"")" & vbCrLf & vbTab & ".Header = xlGuess" & vbCrLf & vbTab & ".MatchCase = False" & vbCrLf & vbTab & ".Orientation = xlTopToBottom" & vbCrLf & vbTab & ".SortMethod = xlPinYin" & vbCrLf & vbTab & ".Apply" & vbCrLf & vbTab & "End With" & vbCrLf & vbTab & "Range(""A1"").Select" & vbCrLf & vbTab & "Application.ScreenUpdating = True"
Application.VBE.MainWindow.Visible = False
End With
End If
'per non avere nessuna cella selezionata visibile
ThisWorkbook.Sheets(NomeFoglioDaCreare).Range("A500").Select
ActiveWindow.ScrollRow = 1
Application.ScreenUpdating = True
ThisWorkbook.Sheets(NomeFoglioDaCreare).Protect Password:=" "
ThisWorkbook.Protect Password:=" "
errore:
'Call DeleteSheet(NomeFoglioDaCreare)
End Sub

My code is not looping through each row, instead it is printing the top row through my range

My final goal is to print my cells pipe delimited so in order to do so I am trying to print everything on each row into cell AB on each row. I am trying to loop through each row to do so however I am currently getting the top row of code repeated in all my rows instead of each row individually being printed.
Sub print_misc()
Dim cell As Range
Dim lastRow As Long
Sheets("1099-Misc_Form_Template").Select
lastRow = Range("B" & Rows.Count).End(xlUp).row
For Each cell In Range("AB2:" & "AB" & lastRow)
cell.Value = Range("B2") & "|" & Range("C2") & "|" & Range("D2") & "|" & Range("E2") & "|" & Range("F2") & "|" & Range("G2") & "|" & Range("H2") & "|" & Range("I2") & "|" & Range("J2") & "|" & Range("L2") & "|" & Range("M2") & "|" & Range("N2") & "|" & Range("O2") & "|" & Range("P2") & "|" & Range("Q2") & "|" & Range("R2") & "|" & Range("S2") & "|" & Range("U2") & "|" & Range("V2") & "|" & Range("W2") & "|" & Range("X2") & "|" & Range("Y2") & "|" & Range("Z2") & "|" & Range("AA2")
Next
End Sub
Each cell in AB shows the result of the combined cells in that row (pipe delimited).
Current output:
Expected output:
You aren't incrementing the value of the row for each iteration of cell. You are point at row 2 for each one.
You also shouldn't use Select it is unnecessary just directly reference the sheet object.
Sub print_misc()
Dim cell As Range
Dim lastRow As Long
dim iter as long
with Sheets("1099-Misc_Form_Template")
lastRow = .Range("B" & Rows.Count).End(xlUp).row
iter = 2
For Each cell In .Range("AB2:" & "AB" & lastRow)
cell.Value = .Range("B" & iter) & "|" & .Range("C" & iter) & "|" & _
.Range("D" & iter) & "|" & .Range("E" & iter) & "|" & _
.Range("F" & iter) & "|" & .Range("G" & iter) & "|" & _
.Range("H" & iter) & "|" & .Range("I" & iter) & "|" & _
.Range("J" & iter) & "|" & .Range("L" & iter) & "|" & _
.Range("M" & iter) & "|" & .Range("N" & iter) & "|" & _
.Range("O" & iter) & "|" & .Range("P" & iter) & "|" & _
.Range("Q" & iter) & "|" & .Range("R" & iter) & "|" & _
.Range("S" & iter) & "|" & .Range("U" & iter) & "|" & _
.Range("V" & iter) & "|" & .Range("W" & iter) & "|" & _
.Range("X" & iter) & "|" & .Range("Y" & iter) & "|" & _
.Range("Z" & iter) & "|" & .Range("AA" & iter)
iter = iter + 1
Next
end with
End Sub

Send email to various addresses from cells

I have in "Sheet1" numerous email addresses, in columns K, M, O, Q, S, U, W, Y, AA.
I want to create an email that will be sent to all the addresses taken from the last row in Sheet1. Same for data in email body taken from last row.
Dim MonOutlook As Object
Dim MonMessage As Object
Dim EmailTo As String
With Worksheets("Sheet1")
EmailTo = .Range("K" & ligne) & ";" & .Range("M" & ligne) & ";" & .Range("O" & ligne) & ";" & .Range("Q" & ligne) & ";" & .Range("S" & ligne) & ";" & .Range("U" & ligne) & ";" & .Range("W" & ligne) & ";" & .Range("Y" & ligne) & ";" & .Range("AA" & ligne)
End With
Set MonOutlook = CreateObject("Outlook.Application")
Set MonMessage = MonOutlook.CreateItem(0)
MonMessage.To = ""
MonMessage.Cc = ""
MonMessage.Bcc = EmailTo
MonMessage.Subject = "Rate request" & " " & "for" & " " & ThisWorkbook.Sheets("Sheet1").Range("B" & ligne)
MonMessage.body = "Hello,"
Chr (13) & Chr(13) & "Please send me rate for" & " " & ThisWorkbook.Sheets("Sheet1").Range("G" & ligne) & " " & "rooms on basis" & " " & ThisWorkbook.Sheets("Sheet1").Range("H" & ligne) & _
Chr(13) & Chr(13) & "in hotel:" & " " & ThisWorkbook.Sheets("Sheet1").Range("J" & ligne) & _
Chr(13) & Chr(13) & "for the period" & " " & ThisWorkbook.Sheets("suivi").Range("C" & ligne) & " " & ThisWorkbook.Sheets("Sheet1").Range("D" & ligne) & _
Chr(13) & Chr(13) & "Thank you!" & _
Chr(13) & Chr(13) & Application.UserName & " " & "-" & " " & "x Tours"
MonMessage.Display
With ThisWorkbook.Sheets("Sheet1").Range("AB" & ligne)
.Value = Date
.NumberFormat = "dd/mm/yyyy"
End With
ActiveWorkbook.Save
Try the code below, explanations inside the code's comments.
Option Explicit
Sub EmailContactsLastRow()
Dim MonOutlook As Object
Dim MonMessage As Object
Dim EmailSht As Worksheet
Dim EmailTo As String
Dim ligne As Long
' set the worksheet object
Set EmailSht = ThisWorkbook.Sheets("Sheet1")
With EmailSht
ligne = .Cells(.Rows.Count, "K").End(xlUp).Row ' get last row with data in column K
EmailTo = .Range("K" & ligne) & ";" & .Range("M" & ligne) & ";" & .Range("O" & ligne) & ";" & _
.Range("Q" & ligne) & ";" & .Range("S" & ligne) & ";" & .Range("U" & ligne) & ";" & _
.Range("W" & ligne) & ";" & .Range("Y" & ligne) & ";" & .Range("AA" & ligne)
End With
Set MonOutlook = CreateObject("Outlook.Application")
Set MonMessage = MonOutlook.CreateItem(0)
With MonMessage
.To = ""
.Cc = ""
.Bcc = EmailTo
.Subject = "Rate request" & " " & "for" & " " & EmailSht.Range("B" & ligne)
.body = "Hello,"
Chr (13) & Chr(13) & "Please send me rate for" & " " & EmailSht.Range("G" & ligne) & " " & "rooms on basis" & " " & EmailSht.Range("H" & ligne) & _
Chr(13) & Chr(13) & "in hotel:" & " " & EmailSht.Range("J" & ligne) & _
Chr(13) & Chr(13) & "for the period" & " " & EmailSht.Range("C" & ligne) & " " & EmailSht.Range("D" & ligne) & _
Chr(13) & Chr(13) & "Thank you!" & _
Chr(13) & Chr(13) & Application.UserName & " " & "-" & " " & "x Tours"
.Display ' <-- this displays the email. not sending it
.send ' <-- this sends the email out
End With
With EmailSht.Range("AB" & ligne)
.Value = Date
.NumberFormat = "dd/mm/yyyy"
End With
ThisWorkbook.Save
End Sub

How to Bold or color text on auto email body from Excel VBA

I am sending mail linked to Excel data. i need to bold and red only few words and i am trying and i am not able to do it. Hope someone from here can help me out. Cells(i,13) has to get bold and Red when i am sending.
toList = Cells(i, 4) 'gets the recipient from col D
eSubject = "Request for KBR transport to " & Cells(i, 2) & " on " & Format(Cells(i, 3), "dd-mmm-yy")
eBody = "Dear " & Cells(i, 1) & vbCrLf & vbCrLf & "Can you please arrange KBR Transport for below PASSENGERS." & vbNewLine & vbNewLine & _
" " & Cells(i, 13) & vbNewLine & vbNewLine & _
" " & vbNewLine & vbNewLine & _
"Full Name : " & Cells(i, 6) & vbNewLine & vbNewLine & _
"Nationality : " & Cells(i, 7) & vbNewLine & vbNewLine & _
"Departure/Arrival Date : " & "" & Format(Cells(i, 8), "dd-mmm-yy") & vbNewLine & vbNewLine & _
"Airline : " & Cells(i, 9) & vbNewLine & vbNewLine & _
"Flight Number : " & Cells(i, 10) & vbNewLine & vbNewLine & _
"Departure/Arrival Time : " & Cells(i, 11) & vbNewLine & vbNewLine & _
"Escort required: " & Cells(i, 14) & vbNewLine & vbNewLine & _
" " & vbNewLine & vbNewLine & _
" Contact Number: " & Cells(i, 12) & vbNewLine & vbNewLine & _
" " & vbNewLine & vbNewLine & _
"Please confirm pick up time and availability." & vbNewLine & vbNewLine ##
Use HTML body instead, then you can use the HTML <b> and <font> tags. It may suit better as you can use a HTML <table> for the data displayed also.

Resources