VBA: Automate Email Sending from Excel with Outlook

VBA: Automate Email Sending from Excel with Outlook Tutorial Blog
Automate Outlook emails directly from Excel with this practical VBA tutorial. Learn how to send emails using Excel data, create subject lines and message bodies, loop through recipient lists, add attachments, and manage bulk email workflows with VBA. Ideal for Excel users, analysts, admin teams, finance teams, and professionals who want to save time by automating repetitive email tasks from Excel.

Sending emails manually from Excel is slow and error-prone. Excel VBA with Outlook automates this completely. A macro can send a formatted email — with recipient, subject, body, and attachment — in under 10 lines of code. Combined with cell values, each email can be personalised per row in a contact list.

This guide covers how VBA connects to Outlook, the MailItem properties, and six practical examples. These include a basic single email, a loop through a contact list, an email with attachment, an HTML-formatted body, CC and BCC recipients, and a safe Display-before-send pattern.

Requirement: Microsoft Outlook must be installed and configured on the same machine as Excel. VBA uses Outlook via COM Automation. This works on Windows Excel 365, 2021, 2019, and 2016 only.

How VBA Connects to Outlook

VBA communicates with Outlook through the Outlook Application Object. You create an Outlook instance, then create a MailItem object. Each MailItem represents one email. Set its properties — To, Subject, Body — then call .Send to send or .Display to open it for review first.

1
Open the VBA Editor: press Alt + F11.
2
Insert a new module: Insert > Module.
3
Paste the Sub code from the examples below and press F5 to run.
Core pattern: create Outlook app, create MailItem, set properties, send. Sub SendBasicEmail() Dim OutApp As Object Dim OutMail As Object Set OutApp = CreateObject("Outlook.Application") Set OutMail = OutApp.CreateItem(0) ' 0 = olMailItem With OutMail .To = "recipient@example.com" .Subject = "Subject here" .Body = "Body text here." .Send End With Set OutMail = Nothing Set OutApp = Nothing End Sub

Examples 1–4: Email Automation in Practice

1
Send from cell values — personalised from sheet data

Reading the recipient address and body from worksheet cells makes the macro flexible. Operations teams can update email content directly in the spreadsheet without touching any VBA code.

Sub SendFromCells() Dim OutApp As Object Dim OutMail As Object Dim ws As Worksheet Set ws = ThisWorkbook.Sheets("Email") Set OutApp = CreateObject("Outlook.Application") Set OutMail = OutApp.CreateItem(0) With OutMail .To = ws.Range("B1").Value ' recipient in B1 .Subject = ws.Range("B2").Value ' subject in B2 .Body = ws.Range("B3").Value ' body in B3 .Send End With Set OutMail = Nothing Set OutApp = Nothing MsgBox "Email sent." End Sub
2
Loop through a contact list — bulk personalised emails

When column A holds names and column B holds email addresses, a Do While loop sends one personalised email per row. Each email uses the name from column A in the greeting line. The loop stops at the first blank row.

Sub BulkEmail() Dim OutApp As Object Dim OutMail As Object Dim i As Long Dim ws As Worksheet Set ws = ThisWorkbook.Sheets("Contacts") Set OutApp = CreateObject("Outlook.Application") i = 2 ' row 2 = first data row Do While ws.Cells(i, 1).Value <> "" Set OutMail = OutApp.CreateItem(0) With OutMail .To = ws.Cells(i, 2).Value .Subject = "Report ready" .Body = "Hi " & ws.Cells(i, 1).Value & "," & vbCrLf & _ "Your report is attached." .Send End With Set OutMail = Nothing i = i + 1 Loop Set OutApp = Nothing MsgBox "Done. Sent: " & (i - 2) End Sub
3
Attach the active workbook — email with file attachment

The Attachments.Add method attaches any file to the email. The most common use is attaching the current workbook. Save the workbook first — otherwise the attachment reflects the last saved state, not the current unsaved changes.

Sub EmailWithAttachment() Dim OutApp As Object Dim OutMail As Object ThisWorkbook.Save ' save before attaching Set OutApp = CreateObject("Outlook.Application") Set OutMail = OutApp.CreateItem(0) With OutMail .To = "manager@example.com" .Subject = "Report " & Format(Now, "dd-mmm-yyyy") .Body = "Weekly report attached." .Attachments.Add ThisWorkbook.FullName .Send End With Set OutMail = Nothing Set OutApp = Nothing End Sub
4
HTML email body — formatted text with colours and bold

Set the HTMLBody property instead of Body to send a formatted HTML email. Bold text, colours, tables, and line breaks all work. Note that HTMLBody overrides the Body property — use one or the other, not both.

With OutMail .To = "recipient@example.com" .Subject = "Formatted Report" .HTMLBody = "<html><body>" & _ "<h2 style='color:#1A5C35'>Monthly Sales</h2>" & _ "<p>Revenue: <strong>142,500</strong></p>" & _ "<p style='color:green'>Target: 102%</p>" & _ "</body></html>" .Send End With
Do not mix .Body and .HTMLBody: Setting both causes the last assignment to win. In most Outlook clients, setting HTMLBody after Body replaces the plain-text body entirely.

Examples 5–6: CC/BCC and Safe Display Pattern

5
CC, BCC, and multiple recipients

MailItem has separate CC and BCC properties. Separate multiple addresses with semicolons. This matches Outlook’s own behaviour when typing multiple addresses in the To or CC field manually.

With OutMail .To = "alice@example.com; bob@example.com" .CC = "manager@example.com" .BCC = "compliance@example.com" .Subject = "Q3 Summary" .Body = "Q3 summary attached." .Attachments.Add ThisWorkbook.FullName .Send End With
6
Display before sending — safe review pattern

Replace .Send with .Display to open the email in Outlook for manual review. This is the safest approach during testing. Users can also modify the body or add attachments before dispatching.

With OutMail .To = ws.Range("B1").Value .Subject = ws.Range("B2").Value .Body = ws.Range("B3").Value .Display ' opens Outlook window without sending End With ' Alternatively, prompt the user before sending: If MsgBox("Send?", vbYesNo) = vbYes Then OutMail.Send Else OutMail.Display End If

Common Issues and How to Fix Them

Run-time error 429: ActiveX component can’t create object

This error means Outlook is not installed or registered on the machine. Verify that Microsoft Outlook is installed and opens normally. If Outlook is running already, try using GetObject("", "Outlook.Application") instead of CreateObject to attach to the existing instance.

Outlook shows a security warning for every email

Outlook’s Programmatic Access Security blocks automated sending in some IT configurations. To resolve this, go to File → Options → Trust Center → Macro Settings and trust the VBA project. Alternatively, ask your IT administrator to adjust Outlook’s security policy. Another option is to use a digital code-signing certificate.

Frequently Asked Questions

  • How do I send an email from Excel VBA?+
    Use CreateObject("Outlook.Application") to create an Outlook instance, then call CreateItem(0) to create a MailItem. Set the To, Subject, and Body properties, then call .Send to dispatch the email. Outlook must be installed on the same Windows machine. For safety, use .Display instead of .Send during development to preview the email before it is sent.
  • Can I send an HTML email from VBA?+
    Yes. Use the .HTMLBody property instead of .Body. Set it to a valid HTML string. For example: .HTMLBody = "<html><body><h1>Title</h1></body></html>". Do not set both .Body and .HTMLBody in the same email — the last property assigned wins and overrides the other.
  • How do I add an attachment to the email?+
    Use .Attachments.Add followed by the full file path. For example: .Attachments.Add "C:\Reports eport.xlsx". To attach the current workbook, use .Attachments.Add ThisWorkbook.FullName. Always save the workbook before attaching it so the file reflects the latest changes.
  • How do I send emails to multiple recipients?+
    Separate email addresses with semicolons in the .To, .CC, or .BCC properties. For example: .To = "alice@example.com; bob@example.com". To send a personalised email per row in a contact list, use a loop that creates a new MailItem for each row, sets .To from the cell, and calls .Send before moving to the next row.