Send Outlook Emails with Multiple Attachments using Excel VBA

Note: This webpage is designed to accompany the Youtube video posted above. The video offers detailed explanation on all topics; while this webpage will serve as a repository for the code presented in the video.

    In this session,

  • We will look at a simple example where we create just one email with multiple attachments.
  • Next, we will look at a more complex example where we will send multiple emails with multiple attachments each. We will use Advanced Filters through VBA in this example, which should be interesting.

Example 1: Send Multiple Attachments in a Single Email

Here, we will loop through a set of files and send it to the customer i.e. one single recipient. Main point here is loading all the file names into a string, populating an array from that string using the Split() function and passing the array as a parameter into our Send Email sub procedure.

We will build on this code in the next example.

Option Explicit

Const sFolderPath As String = "C:\Youtube\Outlook Tutorial 01\Outlook\Invoices\"

' Define Body
Const emBody As String = "Hi There,<br><br>" & _
            "Please find your outstanding invoices attached.<br><br>" & _
            "Regards,<br>" & _
            "OSA Team"
                    
' Define Subject
Const emSubject As String = "Overdue Invoices - Food Jar Co"


Sub Send_Multiple_Emails_Basic_Example()
Dim sInvoice As String, emAttach As String, arrAttach() As String, sFileName As String
Dim lrow As Long
Dim i As Long

lrow = wsSingle.Range("a1").CurrentRegion.Rows.Count

For i = 2 To lrow
    sInvoice = wsSingle.Range("A" & i).Value
    sFileName = sFolderPath & sInvoice & ".pdf"
    emAttach = emAttach & sFileName & ","
Next i
emAttach = Left(emAttach, Len(emAttach) - 1)
arrAttach = Split(emAttach, ",")

Send_Email arrAttach
End Sub


Function Send_Email(sfAttach() As String) As Boolean

On Error GoTo SystemErrorHandler
Dim oApp As Outlook.Application
Set oApp = New Outlook.Application
Dim oMail As Outlook.MailItem
Set oMail = oApp.CreateItem(olMailItem)

Dim i As Long

With oMail
    .To = "[email protected]"
    .CC = ""
    .BCC = ""
    .Subject = emSubject
    .HTMLBody = emBody
    For i = LBound(sfAttach) To UBound(sfAttach)
        .Attachments.Add sfAttach(i)
    Next i
    .Display
    '.Send
End With
Send_Email = True
Exit Function
SystemErrorHandler:
Send_Email = False

End Function

Example 2: Send Multiple Attachments through Multiple Emails

This is a more complex example. We need to first, identify the unique customers in our data range using Advanced Filter.

Then, we will loop over each customer and

  • Find the email id for the customer.
  • Find the invoices and gross amounts for the customer using Advanced Filter
  • Populate an array with all the invoices that will need to be attached.
  • Total the gross amounts and embed it into the body of the email.
  • And, send these parameters to the Send Email function.

Full Code with Error Handling as Below.

Option Explicit

Const sFolderPath As String = "C:\Youtube\Outlook Tutorial 01\Outlook\Invoices\"
                  
' Define Subject
Const emSubject As String = "Overdue Invoices - Food Jar Co"

Sub Send_Multiple_Emails_Multi_Attach_w_Advanced_Filters()
Application.ScreenUpdating = False

' Clean up the worksheets
Call CleanUpWorksheets

' Create Invoice Header range
Dim rngCustomer As Range, rngInvHeader As Range
Dim lrowInvHeader As Long

lrowInvHeader = wsInvHeader.Range("A1").CurrentRegion.Rows.Count

Set rngInvHeader = wsInvHeader.Range("a1:f" & lrowInvHeader)
Set rngCustomer = wsInvHeader.Range("c1:c" & lrowInvHeader)

' First find unique customers

rngCustomer.AdvancedFilter _
    Action:=xlFilterCopy, _
    CopyToRange:=wsWork.Range("A1"), _
    Unique:=True

Dim sCustomerID As String, sInvoice As String
Dim lrowCustomer As Long, lrowFilteredRange As Long, lrowError As Long
Dim i As Long, j As Long
Dim emTotal As String
Dim emTo As String, emAttach As String, arrAttach() As String, emBody As String, sFileName As String

lrowCustomer = wsWork.Range("a1").CurrentRegion.Rows.Count

For i = 2 To lrowCustomer
    'Grab the Customer Name
    sCustomerID = wsWork.Range("A" & i).Value
    ' Assign it in range E as a criteria for the autofilter
    wsWork.Range("E2").Value = sCustomerID
    rngInvHeader.AdvancedFilter _
        Action:=xlFilterCopy, _
        CriteriaRange:=wsWork.Range("E1:E2"), _
        CopyToRange:=wsWork.Range("H1:I1"), _
        Unique:=False
    
    lrowFilteredRange = wsWork.Range("h1").CurrentRegion.Rows.Count
    emTo = GetEMailId(sCustomerID)
    emTotal = Application.WorksheetFunction.Sum(wsWork.Range("i2:i" & lrowFilteredRange))
    emTotal = Format(Application.WorksheetFunction.Sum(wsWork.Range("i2:i" & lrowFilteredRange)), "Currency")
    emBody = "Dear Customer,<br><br>" & _
            "We have attached invoices that are now overdue.<br>" & _
            "Total owing now is " & emTotal & ".<br>" & _
            "Prompt payment is expected.<br>" & _
            "Regards,<br><br>" & _
            "OSA Accounts"
    For j = 2 To lrowFilteredRange
        sInvoice = wsWork.Range("H" & j).Value
        sFileName = sFolderPath & sInvoice & ".pdf"
        emAttach = emAttach & sFileName & ","
    Next j
    emAttach = Left(emAttach, Len(emAttach) - 1)
    arrAttach = Split(emAttach, ",")
    If Not Send_Email_w_Multi_Attach(emTo, emBody, arrAttach) Then
        lrowError = wsError.Cells(wsError.Rows.Count, 1).End(xlUp).Offset(1, 0).Row
        wsError.Cells(lrowError, 1).Value = "Problem sending email for " & sCustomerID
    End If
    emAttach = ""
Next i

If wsError.Range("A2") <> "" Then
    MsgBox "Atleast one error found was detected."
    wsError.Activate
    Else
    MsgBox "All emails were sent successfully."
End If



Application.ScreenUpdating = True
End Sub


Sub CleanUpWorksheets()

wsError.Cells.Clear
wsWork.Cells.Clear

wsError.Range("A1").Value = "Status"
wsWork.Range("E1").Value = wsInvHeader.Range("C1").Value

wsWork.Range("h1").Value = wsInvHeader.Range("A1").Value
wsWork.Range("i1").Value = wsInvHeader.Range("f1").Value

End Sub

Function GetEMailId(fsCustomerID As String) As String

Dim targetCustomerID As String, targetEmailID As String
Dim lrowEmail As Long
Dim j As Long

lrowEmail = wsEmailId.Range("a1").CurrentRegion.Rows.Count

For j = 2 To lrowEmail
    targetCustomerID = wsEmailId.Range("A" & j).Value
    If fsCustomerID = targetCustomerID Then
        targetEmailID = wsEmailId.Range("B" & j).Value
        Exit For
    End If
Next j

GetEMailId = targetEmailID
End Function

Private Function Send_Email_w_Multi_Attach(sfTo As String, sfBody As String, sfAttach() As String) As Boolean

On Error GoTo SystemErrorHandler
Dim oApp As Outlook.Application
Set oApp = New Outlook.Application
Dim oMail As Outlook.MailItem
Set oMail = oApp.CreateItem(olMailItem)

Dim i As Long
With oMail
    .To = sfTo
    .CC = ""
    .BCC = ""
    .Subject = emSubject
    .HTMLBody = sfBody
    For i = LBound(sfAttach) To UBound(sfAttach)
        .Attachments.Add sfAttach(i)
        Next i
    .Display
        '.Send
End With
Send_Email_w_Multi_Attach = True
Exit Function
SystemErrorHandler:
    Send_Email_w_Multi_Attach = False


End Function