Using VBA to insert Excel table into Outlook email

BradA

Board Regular
Joined
Sep 24, 2010
Messages
75
Hello all,

Here's my issue. I'd like to think there's a way to solve it, but I have no idea how. Any help would be appreciated.

Background: Each week we send an email to each of our contractors telling them how much they’re getting paid for that week. We are creating these emails manually right now and want to automate the process. We start with a table in Excel that shows us all of the work orders. It’s about 1500 rows (one work order per row) and 10 columns, with a header row at the top. It is sorted by contractor. We copy all the work orders (all 10 columns) for each respective contractor and paste it into an email. Additionally, we paste in whatever verbiage into the body of the email and send it out. We do this for about 150 contractors per week, so 150 manual emails with lots of copying and pasting. Big waste of time.


My Steps Thus Far: I have used Ron de Bruin’s guide (Mail Range/Selection in the body of the mail) to automate the process. I’m pretty happy with it. It’s doing what I want in terms of finding the correct data and inserting that data into body of the email, and sending the email. If I didn’t care how it looked I’d be satisfied and ready to go live with it.

Issue I Need Resolved: While the code is inserting the proper portion of the table into each email, what it is not doing is adding the header row from the table. I suppose that the contractor would be able to interpret it all even without the header row but it would look a lot more professional if it had the header row. Any ideas how to do this?

Here’s what I have so far. I’m pretty sure you can disregard everything above where I get Outlook cranked up. Thanks in advance for any ideas.

Code:
Sub Payroll()

'This sub is designed to automate the sending of the weekly payroll emails to vendors

Dim OutApp As Object
Dim OutMail As Object
Dim rng As Range
Application.ScreenUpdating = False


Set Emails = ActiveWorkbook.Worksheets("Emails")
Set Data = ActiveWorkbook.ActiveSheet

'Use the email address list to populate email addresses for each vendor
    BRData = Data.Cells(Rows.Count, 11).End(xlUp).Row
    BREmails = Emails.Cells(Rows.Count, 2).End(xlUp).Row
    
    'fill email addresses into Data sheet
    For i = 2 To BRData
        VendorName = Data.Cells(i, 11).Value
        For m = 1 To BREmails
            If Emails.Cells(m, 2).Value = VendorName Then
                Data.Cells(i, 12).Value = Emails.Cells(m, 3).Value
                Exit For
            End If
        Next m
    Next i
    
    'look for missing email addresses
    MissingEmails = ""
    For t = 2 To BRData
        If Data.Cells(t, 12).Value = "" Then 'if the emaal column on Data sheet is blank for that row...
            If Not Data.Cells(t, 11).Value = Data.Cells(t + 1, 11).Value Then 'the condition is only met when this is the last row for that contractor, such that we're only getting each name once in the msgbox below
                VendorMissingEmail = Data.Cells(t, 11).Value
                If MissingEmails = "" Then
                    MissingEmails = MissingEmails & VendorMissingEmail
                Else: MissingEmails = MissingEmails & ", " & VendorMissingEmail
                End If
            End If
        End If
    Next t
    
    
    If Not MissingEmails = "" Then 'give msgbox of which contractors don't have an email on the Email address sheet
        MsgBox "The following contractors do not have email addresses provided on the Emails sheet:" & vbNewLine & vbNewLine & vbNewLine & MissingEmails & vbNewLine & vbNewLine & vbNewLine & "Please add in the missing email addresses and start over.", , "There are missing email addresses"
        Exit Sub
    End If
            
    
' Now start on the actual data part of this
    For d = 2 To BRData
        VendorName2 = Data.Cells(d, 11).Value
        VendorNameNext = Data.Cells(d + 1, 11).Value
        VendorNamePrvs = Data.Cells(d - 1, 11).Value
        If Not VendorName2 = VendorNameNext Then
            BRCurrentVendor = d 'we have identified the bottom row for this particular vendor and will start to look for the top row for that vendor
                For g = 2 To d
                    If Data.Cells(g, 11).Value = VendorName2 Then
                        TRCurrentVendor = g 'we have now identified the top row for this particular vendor
                        
                        
                        
                        Set rng = Data.Range("A" & TRCurrentVendor & ":K" & BRCurrentVendor) 'TRYING TO SET UP THE TABLE
                        
              
                        
                        'Now that we have the top and bottom row for this vendor we can send the email.
                        
                    
                         Set OutApp = CreateObject("Outlook.Application")
                         Set OutMail = OutApp.CreateItem(0)
                        
                        'Define the pieces that will go in the body of the email
                        Recipient = Data.Cells(d, 12).Value
                        Vendor_WO_Count = (BRCurrentVendor - TRCurrentVendor) + 1 'not currently using this
                        Vendor_Total_due = WorksheetFunction.Sum(Range("J" & TRCurrentVendor & ":J" & BRCurrentVendor)) 'not currently using this
                
        
                    
                         'On Error Resume Next
                         With OutMail
                             .To = Recipient
                             .CC = ""
                             .BCC = ""
                             .Subject = VendorName2 & " Payroll for the week of..."

                             .HTMLBody = RangetoHTML(rng)
                             '.Display
                             .Send
                         End With
                         'On Error GoTo 0
        
                    
                         Set OutMail = Nothing
                         Set OutApp = Nothing
                         Recipient = 0
                         
                         Exit For 'exits the G stuff, so it doesn't want to send me an email for each row for that contractor
                        
                        
                        
                    End If
                Next g
                'Exit For 'temporary, so I don't have 150 emails pop up...
            End If
    Next d
        
    
MsgBox "DONE"

Application.ScreenUpdating = True
End Sub

Function RangetoHTML(rng As Range)
' By Ron de Bruin.
    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
 

Excel Facts

Who is Mr Spreadsheet?
Author John Walkenbach was Mr Spreadsheet until his retirement in June 2019.
I think this should work.

It creates a header range then combines it with the vendor data.

Code:
Dim RngHdr As Range
...
For g = 2 To d
   If Data.Cells(g, 11).Value = VendorName2 Then
       TRCurrentVendor = g 'we have now identified the top row for this particular vendor
        Set RngHdr = Data.Range("A1:K1")'Column Header range.
        Set rng = Union(RngHdr, Data.Range("A" & TRCurrentVendor & ":K" & BRCurrentVendor)) 'TRYING TO SET UP THE TABLE
 
Upvote 0

Forum statistics

Threads
1,222,091
Messages
6,163,847
Members
451,861
Latest member
Lurch65

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top