Python Central HubSign in

Automation and Scripting / Phase 4: Communication Automation

Automating Outlook with pywin32

Automate Outlook email tasks on Windows using pywin32 (COM automation).

Platform note

pywin32 works on Windows.

It uses COM automation to control Outlook.

Example (send email)

Python
# 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.

Python
# 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 sure

Outlook 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 Path object to Attachments.Add.
  • Leaving Outlook in a strange state. If Outlook is closed, Dispatch starts 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

quizCheck yourself
  1. What is the safest way to test an Outlook script that composes email?

    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.

  2. On which setup does pywin32 Outlook automation work?

    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.

  3. In the Outlook object model, where does indexing of collections such as Items start?

    Show answer

    B — At 1 — COM collections are 1-based, unlike Python lists, so loops over Items must start at 1.

Was this page helpful?

Let us know how we did