Platform note
pywin32 works on Windows.
It uses COM automation to control Outlook.
Example (send email)
# Windows-only
import win32com.client
def send_outlook(to: str, subject: str, body: str):
outlook = win32com.client.Dispatch("Outlook.Application")
mail = outlook.CreateItem(0)
mail.To = to
mail.Subject = subject
mail.Body = body
mail.Send()
# send_outlook("to@example.com", "Hi", "Hello from Outlook")Notes
- COM automation can be blocked by security policies
- prefer SMTP/APIs in server environments
How COM automation works
Outlook for Windows exposes an object model through COM, a Windows technology that lets one program drive another. pywin32 (pip install pywin32) gives Python access to it. win32com.client.Dispatch("Outlook.Application") connects to Outlook, starting it if needed, and returns an object with the same methods that Outlook's built-in VBA macros use. Anything you can read in the Microsoft Outlook object model documentation can be called from Python.
This means the script sends mail as you, from your signed-in profile, with your signature and account. It needs the classic desktop Outlook. The new Outlook for Windows and Outlook on the web do not support COM. It does not work on macOS or Linux.
Creating, previewing, and sending
CreateItem(0) makes a mail item (0 is olMailItem). Call mail.Display() instead of mail.Send() to open the message and let a person read it before it goes. That is the right way to test.
# Windows-only, needs classic desktop Outlook
from pathlib import Path
import win32com.client
def build_mail(to: str, subject: str, html: str, attachment: Path | None = None):
outlook = win32com.client.Dispatch("Outlook.Application")
mail = outlook.CreateItem(0)
mail.To = to
mail.Subject = subject
mail.HTMLBody = html
if attachment is not None:
mail.Attachments.Add(str(attachment.resolve())) # needs a full path as a string
return mail
def read_inbox_subjects(limit: int = 5) -> list[str]:
outlook = win32com.client.Dispatch("Outlook.Application")
inbox = outlook.GetNamespace("MAPI").GetDefaultFolder(6) # 6 = olFolderInbox
items = inbox.Items
items.Sort("[ReceivedTime]", True) # newest first
return [str(items[i].Subject) for i in range(1, min(limit, items.Count) + 1)]
# mail = build_mail("to@example.com", "Report", "<p>Attached.</p>", Path("report.pdf"))
# mail.Display() # preview first
# mail.Send() # send when you are sureOutlook collections are 1-based, so the loop starts at 1. Attachments.Add needs an absolute path as a string, not a Path object.
Safety
mail.Send() sends a real message immediately from your account. Use Display() until the script is correct, and send the first real messages to yourself. Loops that send mail can email hundreds of people in seconds, and there is no undo. Keep the recipient list explicit and short while testing.
Newer Outlook versions may show a security prompt when a program tries to send or read mail. Do not click around it with another automation tool. Ask your IT team, since these prompts exist to stop malware.
Common mistakes
- Running it on a server or a machine without Outlook. Use SMTP or the Microsoft Graph API there.
- Passing a relative path or
Pathobject toAttachments.Add. - Leaving Outlook in a strange state. If Outlook is closed,
Dispatchstarts it invisibly, and the process can keep running. - Zero-based indexing on Outlook collections.
- Sending from the wrong account when several are configured. Set
mail.SendUsingAccount.
Check your understanding
What is the safest way to test an Outlook script that composes email?
Display() opens the draft without sending it. Send() is immediate and cannot be undone.
Show answer
B — Call Display() so you can inspect the message before it is sent — Display() opens the draft without sending it. Send() is immediate and cannot be undone.
On which setup does pywin32 Outlook automation work?
COM is a Windows technology that drives the installed classic Outlook application. Servers and other systems should use SMTP or Microsoft Graph.
Show answer
A — Classic desktop Outlook on Windows — COM is a Windows technology that drives the installed classic Outlook application. Servers and other systems should use SMTP or Microsoft Graph.
In the Outlook object model, where does indexing of collections such as Items start?
COM collections are 1-based, unlike Python lists, so loops over Items must start at 1.
Show answer
B — At 1 — COM collections are 1-based, unlike Python lists, so loops over Items must start at 1.