Forum Discussion
VBA to email table range based on conditions
I'm completely new to VBA, but I need to take care of automating something at work. I've followed a great Youtube tutorial by Chester Tugwell called "VBA to Automate Sending Email From Excel Table with Attachment from Folder", but instead of attaching an existing file, I need to add an Excel table as part of the email's body. The contents of the table need to be selected from an existing table in a separate file, based on a couple of conditions.
I have two files (attaching both). One is "Example MList" which is a mailing list, and the other is "Example Surveys", which contains a table with the content that needs to be in the email body. The trick is that each recipient should only receive the rows that are relevant to them. I need the body of each email to contain rows from the Surveys file, where the name of the case owner is equal to the recipient, the date of the case is >= than the date listed in the MList, and the Resolved field =0.
In the MList file, I've saved the VBA code I have from the Youtube tutorial, but the body part is what I'm having trouble with.
I'm attaching both example files too. This is what they look like
Mailing list
Table that needs to go in the email body based on recipient's conditions
This is the code I have so far
Sub EmailNegSurveys() Dim EApp As Object Set EApp = CreateObject("Outlook.Application") Dim EItem As Object Dim path As String path = "C:" 'the file path Dim RList As Range Set RList = Range("A2", Range("a2").End(xlDown)) Dim R As Range For Each R In RList Set EItem = EApp.CreateItem(0) With EItem .To = R.Offset(0, 3) .CC = R.Offset(0, 4) .Subject = "Negative Surveys" .Body = "" 'This should be a table from the file "Example Surveys", retrieving the rows where the Name matches the Recipient, the Date is >= "Date Start", and "Resolved"=0 .Display End With Next R Set EApp = Nothing Set EItem = Nothing End Sub
Any help is much appreciated
Here we go Gabriel,
First of all, we need to add an extra function to copy Table to Email body, the function are reference from: https://stackoverflow.com/questions/70921224/macro-to-copy-visible-cells-from-excel-to-email-body
The function code is here, you can paste after End sub of your original code
Function RangetoHTML(rng As Range) Dim fso As Object Dim ts As Object Dim TempFile As String Dim TempWB As Workbook TempFile = Environ$("temp") & "\" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm" 'Copy the range and create a new workbook to past the data in rng.Copy Set TempWB = Workbooks.Add(1) 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 On Error Resume Next .DrawingObjects.Visible = True .DrawingObjects.Delete On Error GoTo 0 End With 'Publish the sheet to a htm file With TempWB.PublishObjects.Add( _ SourceType:=xlSourceRange, _ Filename:=TempFile, _ Sheet:=TempWB.Sheets(1).Name, _ Source:=TempWB.Sheets(1).UsedRange.Address, _ HtmlType:=xlHtmlStatic) .Publish (True) End With 'Read all data from the htm file into RangetoHTML Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2) RangetoHTML = ts.readall ts.Close RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource=", _ "align=left x:publishsource=") 'Close TempWB TempWB.Close savechanges:=False 'Delete the htm file we used in this function Kill TempFile Set ts = Nothing Set fso = Nothing Set TempWB = Nothing End Function
After added this function, you can paste the following code to your Sub
Sub EmailNegSurveys() Application.DisplayAlerts = False Application.ScreenUpdating = False Dim EApp As Object Set EApp = CreateObject("Outlook.Application") Dim EItem As Object Dim I As Long Dim Rec As String Dim DateStart As Date Dim SurveysWb As Workbook Dim SurveysPath As String SurveysPath = "C:\Users\Yau\Desktop\Example Surveys.xlsx" Set SurveysWb = Workbooks.Open(SurveysPath) Dim SurveysSheet As Worksheet Dim SurveysTable As ListObject Set SurveysSheet = SurveysWb.Sheets(1) Set SurveysTable = SurveysSheet.ListObjects("Table1") Dim MListSheet As Worksheet Dim MListTable As ListObject Set MListSheet = ThisWorkbook.Sheets(1) Set MListTable = MListSheet.ListObjects("Table1") For I = 2 To MListTable.ListRows.Count + 1 Rec = MListTable.Range(I, MListTable.ListColumns("Recipient").Index) DateStart = MListTable.Range(I, MListTable.ListColumns("Date Start").Index) SurveysTable.Range.AutoFilter Field:=SurveysTable.ListColumns("Name").Index, Criteria1:=Rec SurveysTable.Range.AutoFilter Field:=SurveysTable.ListColumns("Date").Index, Criteria1:=">=" & DateStart, Operator:=xlAnd SurveysTable.Range.AutoFilter Field:=SurveysTable.ListColumns("Resolved").Index, Criteria1:=0, Operator:=xlAnd If SurveysTable.Range.SpecialCells(xlCellTypeLastCell).Row > 1 Then Set EItem = EApp.CreateItem(0) With EItem .To = MListTable.Range(I, MListTable.ListColumns("Recipient Email").Index) .CC = MListTable.Range(I, MListTable.ListColumns("Manager Email").Index) .Subject = "Negative Surveys" .HTMLBody = RangetoHTML(SurveysTable.Range.SpecialCells(xlCellTypeVisible)) .Display End With End If SurveysTable.AutoFilter.ShowAllData Next SurveysWb.Close Set EApp = Nothing Set EItem = Nothing Application.DisplayAlerts = True Application.ScreenUpdating = True End Sub
The code run as following logic:
1. Open the Survey Workbook, target the Table1 in Sheets1
2. Loop MList Table from Table1 Row 2 to last row (Since Row 1 is header)
3. Filter Survey Table1 by name, date and resolved
4. If filtered row more than 1 row (Header count as 1), means it have something to notify
5. Copy the table with header to Email
6. Display the email for you
Hope this help 🙂
Regards
Tony
13 Replies
- gn00588950Copper Contributor
Hi Ber93
In order to prepare your email body, you need to access the Table in Surveys workbook.
You can do it via below code:
Dim SurveysWb As Workbook Dim SurveysPath As String SurveysPath = "C:\Example Surveys.xlsx" Set SurveysWb = Workbooks.Open(SurveysPath) 'Get access to Surverys Workbook's Table 1 Dim SurveysSheet As Worksheet Dim SurveysTable As ListObject Set SurveysSheet = SurveysWb.Sheets(1) Set SurveysTable = SurveysSheet.ListObjects("Table1") 'Loop all rows in SurveysTable For I = 2 To SurveysTable.ListRows.Count + 1 'Do your stuff here.. Next
After you are able to access the table, I would like to ask a question:
How you would like to prepare the content from Surveys table?
Say for example, you have Andrew & Joseph in MList
When you prepare email for Andrew, will you get all rows that belongs to Andrew and combine them in single email?
Or send it out with 2 emails?
Once you get this direction, we can work on how to prepare the email content.
Regards
Tony
- Ber93Brass ContributorHi Tony
Thanks so much for your answer. I would like each recipient to get all the rows that belong to them, and fulfill the other 2 conditions (Resolved is 0 and Date >= Date Start from the mailing list) listed together as a table in the body of a single email. So for example, Andrew would get row 2, because the other row belonging to him, has Resolved 1.
Joseph would only get row 5, because the other row belonging to him doesn't meet the date condition. However, if Joseph had more than 1 row meeting all conditions, all his rows would be listed together in the email
I would also like the table in each email to contain the headers if possible.
Best,
Gabriel- gn00588950Copper Contributor
Here we go Gabriel,
First of all, we need to add an extra function to copy Table to Email body, the function are reference from: https://stackoverflow.com/questions/70921224/macro-to-copy-visible-cells-from-excel-to-email-body
The function code is here, you can paste after End sub of your original code
Function RangetoHTML(rng As Range) Dim fso As Object Dim ts As Object Dim TempFile As String Dim TempWB As Workbook TempFile = Environ$("temp") & "\" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm" 'Copy the range and create a new workbook to past the data in rng.Copy Set TempWB = Workbooks.Add(1) 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 On Error Resume Next .DrawingObjects.Visible = True .DrawingObjects.Delete On Error GoTo 0 End With 'Publish the sheet to a htm file With TempWB.PublishObjects.Add( _ SourceType:=xlSourceRange, _ Filename:=TempFile, _ Sheet:=TempWB.Sheets(1).Name, _ Source:=TempWB.Sheets(1).UsedRange.Address, _ HtmlType:=xlHtmlStatic) .Publish (True) End With 'Read all data from the htm file into RangetoHTML Set fso = CreateObject("Scripting.FileSystemObject") Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2) RangetoHTML = ts.readall ts.Close RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource=", _ "align=left x:publishsource=") 'Close TempWB TempWB.Close savechanges:=False 'Delete the htm file we used in this function Kill TempFile Set ts = Nothing Set fso = Nothing Set TempWB = Nothing End Function
After added this function, you can paste the following code to your Sub
Sub EmailNegSurveys() Application.DisplayAlerts = False Application.ScreenUpdating = False Dim EApp As Object Set EApp = CreateObject("Outlook.Application") Dim EItem As Object Dim I As Long Dim Rec As String Dim DateStart As Date Dim SurveysWb As Workbook Dim SurveysPath As String SurveysPath = "C:\Users\Yau\Desktop\Example Surveys.xlsx" Set SurveysWb = Workbooks.Open(SurveysPath) Dim SurveysSheet As Worksheet Dim SurveysTable As ListObject Set SurveysSheet = SurveysWb.Sheets(1) Set SurveysTable = SurveysSheet.ListObjects("Table1") Dim MListSheet As Worksheet Dim MListTable As ListObject Set MListSheet = ThisWorkbook.Sheets(1) Set MListTable = MListSheet.ListObjects("Table1") For I = 2 To MListTable.ListRows.Count + 1 Rec = MListTable.Range(I, MListTable.ListColumns("Recipient").Index) DateStart = MListTable.Range(I, MListTable.ListColumns("Date Start").Index) SurveysTable.Range.AutoFilter Field:=SurveysTable.ListColumns("Name").Index, Criteria1:=Rec SurveysTable.Range.AutoFilter Field:=SurveysTable.ListColumns("Date").Index, Criteria1:=">=" & DateStart, Operator:=xlAnd SurveysTable.Range.AutoFilter Field:=SurveysTable.ListColumns("Resolved").Index, Criteria1:=0, Operator:=xlAnd If SurveysTable.Range.SpecialCells(xlCellTypeLastCell).Row > 1 Then Set EItem = EApp.CreateItem(0) With EItem .To = MListTable.Range(I, MListTable.ListColumns("Recipient Email").Index) .CC = MListTable.Range(I, MListTable.ListColumns("Manager Email").Index) .Subject = "Negative Surveys" .HTMLBody = RangetoHTML(SurveysTable.Range.SpecialCells(xlCellTypeVisible)) .Display End With End If SurveysTable.AutoFilter.ShowAllData Next SurveysWb.Close Set EApp = Nothing Set EItem = Nothing Application.DisplayAlerts = True Application.ScreenUpdating = True End Sub
The code run as following logic:
1. Open the Survey Workbook, target the Table1 in Sheets1
2. Loop MList Table from Table1 Row 2 to last row (Since Row 1 is header)
3. Filter Survey Table1 by name, date and resolved
4. If filtered row more than 1 row (Header count as 1), means it have something to notify
5. Copy the table with header to Email
6. Display the email for you
Hope this help 🙂
Regards
Tony