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 typedAs 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, noOutlook.Applicationto 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 →
Related guides
- VBA On Error — Resume Next vs GoTo & Why Macros Hide Bugs
- VBA MsgBox — Yes/No, Buttons & the Brackets Rule
- VBA VLookup — The "Not Found" Crash & When a Dictionary Wins
- VBA Copy Paste — Skip the Clipboard for Faster Macros
- VBA For Loop in Excel — 8 Real-World Examples
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.
