Reputation: 61
I'm working on a macro that creates Workbooks based on a filter and sends them out to a list of emails, one at a time, however, there may be more than one location per email and the loop is picking up each (next) cell, even if it's filtered out. Example table:
Location Email
1 [email protected]
2 [email protected]
3 [email protected]
4 [email protected]
I use another sheet to filter for each unique email and then load the locations into an array so it filters a table. Once that table is filtered I Copy and paste the contents into a new workbook, save it temporarily, attach it to the email and send it out. The problem is that when I reach the second unique email, the email contains values from previous rows (location 2 and 3) and so on. Here's the code:
Sub AutoEmailSend()
Dim rng As ListObject
Dim OutApp As Object
Dim OutMail As Object
Dim cell As Range
Dim TempFilePath As String
Dim TempFileName As String
Dim TempWB As Workbook
Dim LastRow As Long
Set rng = Nothing
On Error Resume Next
Set rng = Sheets("Detail Aging").ListObjects("Locations")
On Error GoTo 0
If rng Is Nothing Then
MsgBox "The selection is not a range or the sheet is protected" & _
vbNewLine & "please correct and try again.", vbOKOnly
Exit Sub
End If
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
Set OutApp = CreateObject("Outlook.Application")
Dim strbody As String
strbody = Worksheets("Body").Range("A1")
Dim strbody2 As String
strbody2 = Worksheets("Body").Range("A2")
Dim strbody3 As String
strbody3 = Worksheets("Body").Range("A3")
Dim strbody4 As String
strbody4 = Worksheets("Body").Range("A4")
Dim strbody5 As String
strbody5 = Worksheets("Body").Range("A5")
On Error GoTo cleanup
For Each cell In Sheets("Emails").Columns("A").Cells.SpecialCells(xlCellTypeConstants)
If cell.Value Like "?*@?*.?*" Then
Sheets("Locations").Range("A1:R1").AutoFilter Field:=12, Criteria1:=cell.Value
Dim RngOne As Range, cell2 As Range
Dim LastCell As Long
Dim arrList() As String, lngCnt As Long
With Sheets("Locations")
LastCell = .Range("D" & Sheets("Locations").Rows.Count).End(xlUp).Row
Set RngOne = .Range("D2:D" & LastCell)
End With
'load values into an array
lngCnt = 0
For Each cell2 In RngOne
If Not cell2.EntireRow.Hidden Then
ReDim Preserve arrList(lngCnt)
arrList(lngCnt) = cell2.Text
lngCnt = lngCnt + 1
End If
Next cell2
Sheets("Detail Aging").Range("A1:I1").AutoFilter Field:=1, Criteria1:=arrList, Operator:=xlFilterValues
With Worksheets("Detail Aging").ListObjects("Locations").Sort
.SortFields.Clear
.SortFields.Add Key:=Range("Locations[[#Headers],[#Data],[Days Late]]"), _
SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:= _
xlSortTextAsNumbers
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Sheets("Body").Range("B1").Formula = "=TEXT(Locations[[#Totals],[Total Balance]], ""$#,##0.00._);($#,##0.00)."")"
Dim strbody6 As String
strbody6 = Worksheets("Body").Range("B1")
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = cell.Value
.CC = Cells(cell.Row, "M").Value & "; " & Cells(cell.Row, "N").Value & "; " & Cells(cell.Row, "O").Value & "; " & Cells(cell.Row, "S").Value
.Subject = "Aging Report | " & Cells(cell.Row, "C").Value & " | " & Cells(cell.Row, "F").Value & " | " & Cells(cell.Row, "T").Value
.HTMLBody = "<BODY style=font-size:11pt;font-family:Arial>Dear Valued Customer,<BR><BR>" & _
strbody & "<BR><BR>" & _
strbody2 & "<B>" & strbody6 & "</B>" & " " & strbody3 & "<BR><BR>" & _
strbody4 & "<BR><BR>" & _
strbody5 & "<BR><BR>" & _
"<i><u>Please use ""Reply All"" when replying to this email. [email protected] is not a monitored email address.</u></i><BR><BR>" & _
"Thank you for your business!</BODY><BR>" & _
"<BODY style=font-size:12pt;font-family:Arial><B>" & Cells(cell.Row, "A").Value & " | <font color=""#d52427"">Company</font></B><BR>" & _
"<span style=font-size:11pt;font-family:Arial>" & Cells(cell.Row, "Q").Value & "<BR>" & _
Cells(cell.Row, "R").Value & "<BR>" & _
Cells(cell.Row, "S").Value & "<BR>" & _
"<font color=""#d52427"">www.Company.com</font></span></body><BR>"
rng.Range.SpecialCells(xlCellTypeVisible).Copy
Workbooks.Add (1)
Set TempWB = ActiveWorkbook
With TempWB.Sheets(1)
.Cells(1).PasteSpecial Paste:=8
.Cells(1).PasteSpecial xlPasteValues, , False, False
.Cells(1).PasteSpecial xlPasteFormats, , False, False
.Cells(1).Select
Application.CutCopyMode = False
.Cells.EntireColumn.AutoFit
.Range("A1:J1").AutoFilter
On Error Resume Next
.DrawingObjects.Visible = True
.DrawingObjects.Delete
On Error GoTo 0
.Name = "Aging Report"
End With
TempFilePath = Environ$("temp") & "\"
TempFileName = "Aging Report " & Format(Now, "dd-mm-yy hh-mm-ss") & ".xlsx"
TempWB.SaveAs TempFilePath & TempFileName
.Attachments.Add TempWB.FullName
TempWB.Close savechanges:=False
Kill TempFilePath & TempFileName
.Send
End With
On Error GoTo 0
Set OutMail = Nothing
End If
Next cell
cleanup:
Set OutApp = Nothing
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
First email is correct like:
To: [email protected]
Cc: [email protected]; [email protected]
Subject: Aging Report | Cust1 | Custname1 | Col1
Attachment: Table containing correct details
Body Text Correct
Col1 Name | Company
Pos1
Phone1
Email1
www.Company.com
Second email however, is something like:
To: [email protected]
Cc: [email protected]; [email protected] (Should be Person2 and Company2)
Subject: Aging Report | Cust1 | Custname1 | Col1 (Should be Cust2 and so on)
Attachment: Table containing correct details
Body Text Correct
Col1 Name | Company (Should be Col2 and so on)
Pos1
Phone1
Email1
www.Company.com
I'm trying to provide as many details as possible. Thank you in advance.
Link with sample workbook: https://1drv.ms/x/s!At5Qdrytuugrlmt5NcJovACVdiNt
Upvotes: 0
Views: 511
Reputation: 1375
Edit - removed old answer as it did not address OP's issue.
Problem
You are using the row of the email address from the Emails sheet (the cell
variable) when attempting to pull the collector. In your example of email #2, cell.Row
is 3 because [email protected] appears in cell A3 of the Emails sheet.
Solution
You need to retrieve the first visible row number from the Locations sheet and use that in your references. Note the addition of the CollectorRow variable.
Sub AutoEmailSend()
Dim rng As ListObject
Dim OutApp As Object
Dim OutMail As Object
Dim cell As Range
Dim TempFilePath As String
Dim TempFileName As String
Dim TempWB As Workbook
Dim LastRow As Long
Dim CollectorRow As Long
Set rng = Nothing
On Error Resume Next
Set rng = Sheets("Detail Aging").ListObjects("Locations")
On Error GoTo 0
If rng Is Nothing Then
MsgBox "The selection is not a range or the sheet is protected" & _
vbNewLine & "please correct and try again.", vbOKOnly
Exit Sub
End If
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
Set OutApp = CreateObject("Outlook.Application")
Dim strbody As String
strbody = Worksheets("Body").Range("A1")
Dim strbody2 As String
strbody2 = Worksheets("Body").Range("A2")
Dim strbody3 As String
strbody3 = Worksheets("Body").Range("A3")
Dim strbody4 As String
strbody4 = Worksheets("Body").Range("A4")
Dim strbody5 As String
strbody5 = Worksheets("Body").Range("A5")
On Error GoTo cleanup
For Each cell In Sheets("Emails").Columns("A").Cells.SpecialCells(xlCellTypeConstants)
If cell.Value Like "?*@?*.?*" Then
Sheets("Locations").Range("A1:R1").AutoFilter Field:=12, Criteria1:=cell.Value
Dim RngOne As Range, cell2 As Range
Dim LastCell As Long
Dim arrList() As String, lngCnt As Long
With Sheets("Locations")
LastCell = .Range("D" & Sheets("Locations").Rows.Count).End(xlUp).Row
Set RngOne = .Range("D2:D" & LastCell)
End With
'load values into an array and get first visible row while we are at it
CollectorRow = 0
lngCnt = 0
For Each cell2 In RngOne
If Not cell2.EntireRow.Hidden Then
If CollectorRow = 0 Then CollectorRow = cell2.Row
ReDim Preserve arrList(lngCnt)
arrList(lngCnt) = cell2.Text
lngCnt = lngCnt + 1
End If
Next cell2
Sheets("Detail Aging").Range("A1:I1").AutoFilter Field:=1, Criteria1:=arrList, Operator:=xlFilterValues
With Worksheets("Detail Aging").ListObjects("Locations").Sort
.SortFields.Clear
.SortFields.Add Key:=Range("Locations[[#Headers],[#Data],[Days Late]]"), _
SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:= _
xlSortTextAsNumbers
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Sheets("Body").Range("B1").Formula = "=TEXT(Locations[[#Totals],[Total Balance]], ""$#,##0.00._);($#,##0.00)."")"
Dim strbody6 As String
strbody6 = Worksheets("Body").Range("B1")
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = cell.Value
.CC = Cells(CollectorRow, "M").Value & "; " & Cells(CollectorRow, "N").Value & "; " & Cells(CollectorRow, "O").Value & "; " & Cells(CollectorRow, "S").Value
.Subject = "Aging Report | " & Cells(CollectorRow, "C").Value & " | " & Cells(CollectorRow, "F").Value & " | " & Cells(CollectorRow, "T").Value
.HTMLBody = "<BODY style=font-size:11pt;font-family:Arial>Dear Valued Customer,<BR><BR>" & _
strbody & "<BR><BR>" & _
strbody2 & "<B>" & strbody6 & "</B>" & " " & strbody3 & "<BR><BR>" & _
strbody4 & "<BR><BR>" & _
strbody5 & "<BR><BR>" & _
"<i><u>Please use ""Reply All"" when replying to this email. [email protected] is not a monitored email address.</u></i><BR><BR>" & _
"Thank you for your business!</BODY><BR>" & _
"<BODY style=font-size:12pt;font-family:Arial><B>" & Cells(CollectorRow, "A").Value & " | <font color=""#d52427"">Company</font></B><BR>" & _
"<span style=font-size:11pt;font-family:Arial>" & Cells(CollectorRow, "Q").Value & "<BR>" & _
Cells(CollectorRow, "R").Value & "<BR>" & _
Cells(CollectorRow, "S").Value & "<BR>" & _
"<font color=""#d52427"">www.Company.com</font></span></body><BR>"
rng.Range.SpecialCells(xlCellTypeVisible).Copy
Workbooks.Add (1)
Set TempWB = ActiveWorkbook
With TempWB.Sheets(1)
.Cells(1).PasteSpecial Paste:=8
.Cells(1).PasteSpecial xlPasteValues, , False, False
.Cells(1).PasteSpecial xlPasteFormats, , False, False
.Cells(1).Select
Application.CutCopyMode = False
.Cells.EntireColumn.AutoFit
.Range("A1:J1").AutoFilter
On Error Resume Next
.DrawingObjects.Visible = True
.DrawingObjects.Delete
On Error GoTo 0
.Name = "Aging Report"
End With
TempFilePath = Environ$("temp") & "\"
TempFileName = "Aging Report " & Format(Now, "dd-mm-yy hh-mm-ss") & ".xlsx"
TempWB.SaveAs TempFilePath & TempFileName
.Attachments.Add TempWB.FullName
TempWB.Close savechanges:=False
Kill TempFilePath & TempFileName
.Send
End With
On Error GoTo 0
Set OutMail = Nothing
End If
Next cell
cleanup:
Set OutApp = Nothing
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
I ran this modified code on your test workbook, and the second email has Customer2's information as intended.
Also, as a side note: since your code relies upon a list of emails in one sheet and filtering data in a different sheet, you would have unexpected behavior if an email in the Emails sheet had no lines in the Locations sheet. This may not be an issue for you - for instance, if another set of code builds the email list - but could be something to think about.
Upvotes: 1