Forum Discussion
VBA to email table range based on conditions
- Sep 08, 2022
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 FunctionAfter 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 SubThe 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
Hey Tony
I'm modifying the variables referring to the sheets and tables, but I'm uncertain about some details, since I'm a complete VBA noob.
1. When replacing the sheet and workbook references to refer to my real file, should I replace the sheet and table numbers with names? Because my real files have sheet names and table names. I mean lines 21 and 22 from your sub. I'm thinking to change them to the following
Set SurveysSheet = SurveysWb.Data 'Data is the real name of my sheet
Set SurveysTable = SurveysSheet.ListObjects("tblRaw") 'Real name of the table
Same goes for lines 26 and 27 of your sub. I'm thinking if I should change them to:
Set MListSheet = ThisWorkbook.Distinct_mailing_list 'real name of my MList sheet. I'm not sure what the (1) in your sub is for
Set MListTable = MListSheet.ListObjects("MailingList") '
2. On the other hand, I see line 46 of your sub says to show all data. If I only wanted to display certain columns from my surveys table, is that where I would change that? Because unfortunately my real surveys table has many more fields than the example I sent.
Hi Gabriel,
To refer the sheet by name, the syntax should be:
Set SurveysSheet = SurveysWb.Sheets("Data") 'Data is the real name of my sheet
And regarding to the ShowAllData, it is refreshing the filter to nothing and show all the data in table, this is to prepare for next filter. this line must be there.
If you need only certain column to be copied to Email, please change the Range in line 42:
.HTMLBody = RangetoHTML(SurveysTable.Range.SpecialCells(xlCellTypeVisible))
For example, if you only need first 5 column, you can change as:
.HTMLBody = RangetoHTML(Range("A1:" & Cells(SurveysTable.Range.SpecialCells(xlCellTypeLastCell).Row, 5).Address))
5 in above means Column E
Best,
Tony
- SAZ2121Jul 28, 2023Copper ContributorHi Gabriel,
I really enjoyed your thread and conversation with Tony. Since I am looking currently for a smiler files like yours.
Could you please share the files that worked for you?
I would really appreciate it. Thanks - gn00588950Sep 12, 2022Copper Contributor
- Ber93Sep 12, 2022Brass Contributor
Tony, it's working now!
I changed my output from the database, so the date filter is pre-applied, and I also had replaced 0s in the "Resolved" field with "No", to make it more user-friendly. That is what was causing the error. I have removed the lines referencing the dates, and I replaced =0 with ="No", and it is working perfectly now.
I can't thank you enough! You're a genius.
Thanks,
Gabriel
- gn00588950Sep 10, 2022Copper Contributor
Hi Gabriel,
Which line did the error return? I don’t think is related to the unique formula, because you already created another table for the mailing list
Did the survey table header name different from the code ?
I am referring column name : "Name", "Date" & "Resolved" in below code
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:=xlAndThanks
Tony
- Ber93Sep 09, 2022Brass Contributor
Hi again Tony
I modified all the necessary parts and tried running it, but I get the error message "Subscript out of range". This is how I have the code. I added comments in the lines that I modified. Btw, this is how I have my columns in the mailing list table, just in case that is what's causing the problem.
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 = "example" 'my actual path Set SurveysWb = Workbooks.Open(SurveysPath) Dim SurveysSheet As Worksheet Dim SurveysTable As ListObject Set SurveysSheet = SurveysWb.Sheets("xOut_MailingNegSurveys") 'this is the named sheet in the file Set SurveysTable = SurveysSheet.ListObjects("NegSurveys") 'named table Dim MListSheet As Worksheet Dim MListTable As ListObject Set MListSheet = ThisWorkbook.Sheets("Distinct_mailing_list") 'name of the sheet where I am adding this sub Set MListTable = MListSheet.ListObjects("MailingList") 'named table inside the NListSheet 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 Next SurveysWb.Close Set EApp = Nothing Set EItem = Nothing Application.DisplayAlerts = True Application.ScreenUpdating = True End Sub 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 FunctionI'm thinking it might be because my mailing list table is a table I created using =IF(ISBLANK(A2),"",A2) and extended it like 500 rows. I did this because from A to G I have a dynamic array created using UNIQUE+FILTER. Since this VBA code requires an actual table, I created this table from I-N mirroring the dynamic array I have in A-G. Do you think this is what's causing the out of range error?
- Ber93Sep 09, 2022Brass ContributorThanks Tony. I will work on changing that now and let you know how it goes