🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Outlook in Excel — Send Email from a Macro (and Why New Outlook Breaks It)

|

VBA Outlook in Excel — Send Email from a Macro (and Why New Outlook Breaks It)

Tested on: Excel 365 v2509 · Excel 2021 · Excel 2019 (classic Outlook) · last verified 2026-06-12

TL;DR — Sending mail from Excel means driving another application's object model. Two decisions matter: how you connect to Outlook (late binding with CreateObject is the portable choice) and how you send (.Display to review safely, .Send to fire immediately and hit the security prompt). One thing to know going in: "New Outlook" has removed VBA support entirely — this only works with classic Outlook.

Sub SendFromExcel()
    Dim olApp As Object, mail As Object
    Set olApp = CreateObject("Outlook.Application")   ' late binding — no reference needed
    Set mail = olApp.CreateItem(0)                    ' 0 = olMailItem

    With mail
        .To = "[email protected]"
        .Subject = "Daily report"
        .Body = "Numbers attached. — sent from Excel"
        .Attachments.Add ThisWorkbook.FullName
        .Display                                       ' review it; use .Send to fire instantly
    End With

    Set mail = Nothing
    Set olApp = Nothing
End Sub

The mental model: you're remote-controlling another app, not writing Excel code

Everything else in your macro talks to Excel. This doesn't. CreateObject("Outlook.Application") reaches across into a separate program and steers it. That reframes every question that follows: connecting to Outlook is a cross-application handshake (so version differences matter), and sending mail trips a security boundary Excel never imposes on its own cells (so a wall of consent prompts is by design, not a bug).

Hold that picture and the two real decisions become obvious. First, how do you get a handle on Outlook — bind early with a reference, or late with CreateObject? Second, how do you actually send — pop the draft for a human to check, or fire it and meet the security prompt? Get those two right and the rest is just filling in .To, .Subject, .Body.

The one rule: late binding (CreateObject) travels; early binding locks you to one machine

This is the decision that determines whether your macro survives being emailed to a colleague:

Early binding needs a reference (Tools → References → Microsoft Outlook XX.0 Object Library). You get IntelliSense and named constants like olMailItem — but the file is now tied to that exact library version, and it throws "Can't find project or library" on a PC with a different Outlook. Late binding (CreateObject("Outlook.Application"), variables typed As Object) has no reference, works across versions, and is the right default for code you share.

The cost of late binding is that named constants don't exist, so you use their numeric values — CreateItem(0) instead of CreateItem(olMailItem). A small price for portability:

' ✓ LATE BINDING — portable, no reference, survives version differences
Dim olApp As Object
Set olApp = CreateObject("Outlook.Application")
Dim mail As Object
Set mail = olApp.CreateItem(0)        ' 0 = olMailItem (the named constant doesn't exist here)

' EARLY BINDING (needs the reference) would let you write:
'   Dim olApp As Outlook.Application
'   Set mail = olApp.CreateItem(olMailItem)
' ...but breaks with "Can't find project or library" on another Outlook version.

Use early binding while you write the code — IntelliSense is genuinely helpful — then switch to late binding before you share it. (For looking up an existing instance instead of starting a new one, GetObject pairs with CreateObject.)

The trap: .Send hits a security wall — .Display is usually what you want

The second decision is how the mail leaves. .Send dispatches immediately — and on most configurations that triggers Outlook's programmatic-access guard, the "A program is trying to send an e-mail message on your behalf" prompt, or a flat refusal under organisational policy:

.Display     ' ✓ opens the draft so a human reviews and clicks Send — no security prompt
.Send        ' ⚠ fires immediately; expect the security prompt or a policy block

.Display sidesteps the whole problem by keeping a human in the loop: the email opens, fully populated, and the person clicks Send. For a "draft 50 personalised emails for me to glance at and send" workflow, that's not a limitation — it's the safer design. Reserve .Send for trusted, unattended automation, and know that making it work silently means dealing with the security model (a trusted location, an Exchange policy, or a third-party tool like Redemption) rather than a one-line fix.

The wall you can't code around: New Outlook has no VBA

This is the part the older tutorials don't mention, and it's the most important thing here in 2026:

"New Outlook" — the rebuilt, web-based client Microsoft is rolling out as the default — does not support VBA, COM add-ins, or macros at all. There is no VBA editor, no ThisOutlookSession, no Outlook.Application to automate. Everything in this article requires classic Outlook.

That's not speculation; it's Microsoft's stated direction, and the official replacement is Power Automate, not a newer VBA. Classic Outlook still runs today, and CreateObject("Outlook.Application") still drives it — but you're now automating a client your own vendor has flagged for retirement. If you're choosing where to invest, that matters: a macro that emails through classic Outlook is built on ground that's already being cleared.

When to use which

Goal Use
Code you'll share across PCs Late binding — CreateObject("Outlook.Application")
Code you're actively writing (want IntelliSense) Early binding via a reference, then switch before sharing
Let a human review before sending .Display
Fire unattended (trusted automation only) .Send (expect the security model)
Attach the workbook .Attachments.Add ThisWorkbook.FullName
React to incoming mail ThisOutlookSession + WithEvents (classic Outlook only)

The opinion: don't build new automation on Outlook VBA in 2026

The line I'll commit to: if you're starting fresh, don't anchor your email automation to Outlook VBA. It still works in classic Outlook today, and if you already have a working macro, keep it running. But Microsoft has been explicit that New Outlook — the default for new installs — has no VBA, and "the default" is where your users are heading whether they chose it or not. Writing brand-new macros against Outlook.Application is building on a foundation the landlord has already posted for demolition.

So treat existing Outlook VBA as legacy to maintain, not a pattern to extend. When you need new "Excel reaches the outside world" automation — email, schedules, cross-app moves — pick something that doesn't depend on a process model Microsoft is removing. The few minutes you'd spend wiring up CreateObject and fighting the security prompt are better spent on an approach that will still exist after the New Outlook rollout finishes.

Common VBA Outlook mistakes (and the fix)

Symptom Cause Fix
"Can't find project or library" on another PC Early binding tied to a specific Outlook version Switch to late binding (CreateObject, As Object)
Security prompt on every .Send Programmatic-access guard is doing its job Use .Display, or address the security model for .Send
429 / "could not create object" New Outlook (no VBA) or Outlook not installed Requires classic Outlook
olMailItem is undefined No reference set (late binding) Use the number: CreateItem(0)
Attachment not found Workbook never saved, so FullName is just a name Save first; pass a full path to Attachments.Add
Outlook stays open / memory leaks Objects not released Set mail = Nothing and Set olApp = Nothing

When the email automation piles up — describe the task instead

You didn't want to study binding modes and security prompts. You wanted "email each manager their team's numbers every Monday." By the time you've chosen late binding, dodged the .Send wall with .Display, and discovered half your users are on New Outlook where none of it runs, the plumbing has eaten the morning. ExcelMaster Agent lets you describe the outcome in plain English — "split this sheet by manager and draft an email to each with their rows attached" — and it does the work without leaning on a process model Microsoft is retiring, backing up your workbook first. Try it free →

FAQ

How do I send an email from Excel using VBA? Create an Outlook application object with CreateObject("Outlook.Application"), make a mail item with CreateItem(0), set .To, .Subject, and .Body, then call .Display to review it or .Send to fire it. Use late binding (As Object) so the macro works on any Outlook version, and remember this needs classic Outlook.

What's the difference between early and late binding for Outlook? Early binding requires a reference to the Microsoft Outlook Object Library and gives you IntelliSense and constants like olMailItem, but ties the file to one Outlook version. Late binding uses CreateObject with As Object variables — no reference, fully portable across versions — at the cost of using numbers like 0 instead of olMailItem. Share code with late binding.

Why does VBA .Send trigger a security warning? Outlook's programmatic-access guard shows "A program is trying to send an e-mail on your behalf" to stop malware mailing silently. Use .Display so a human clicks Send, which avoids the prompt entirely. To send unattended you must satisfy the security model — a trusted location, an Exchange policy, or a tool like Redemption.

Does VBA work in New Outlook? No. New Outlook — the web-based client Microsoft is making the default — has no VBA, no COM add-ins, and no macro support. CreateObject("Outlook.Application") only drives classic Outlook. Microsoft's recommended replacement for the automation is Power Automate.

How do I attach a file to an Outlook email in VBA? Use .Attachments.Add with a full file path: .Attachments.Add ThisWorkbook.FullName attaches the current workbook. Save the workbook first, otherwise FullName returns just the file name with no path and the attachment won't be found.