Hello, tech enthusiasts! ๐
Every morning, the same kind of email arrives: “Daily Sales Report”, with an Excel file attached. You open the email, click the file, choose Save As, find the right folder and click Save. It takes a minute. But a minute every day, plus the days you forget, adds up.
Today we will write a Python script that reads your Outlook Inbox, finds the right emails and saves the attachments for you. We will use pywin32. It is a library that lets Python talk to Windows programs like Outlook. Think of it like a remote control: Python presses the buttons inside Outlook for you.
What you need
- Windows with the desktop Outlook app, already signed in to your email
- Python 3 from https://www.python.org
- The pywin32 library
- A folder for the files, for example
C:\Reports\Attachments
Install pywin32 in the Command Prompt:
pip install pywin32
Note: this method works with the classic desktop Outlook only. It does not work with Outlook in the browser.
Step 1: Connect to Outlook and open the Inbox
Create a file called save_attachments.py:
import win32com.client
# Connect to the Outlook app that is installed on this computer
outlook = win32com.client.Dispatch("Outlook.Application")
namespace = outlook.GetNamespace("MAPI")
# 6 is the number Outlook uses for the Inbox folder
inbox = namespace.GetDefaultFolder(6)
print("Emails in Inbox:", inbox.Items.Count)
Run it with python save_attachments.py. If you see a number, Python is talking to Outlook.
MAPI is the system Outlook uses to reach your mailbox. You do not need to understand it, just use the name.
Step 2: Loop through the emails
Now we look at each email. We sort them so the newest come first:
items = inbox.Items
items.Sort("[ReceivedTime]", True) # True = newest first
for item in items:
# 43 means "mail item". Skip meeting invites and other items.
if item.Class != 43:
continue
print(item.ReceivedTime, "|", item.Subject)
Your Inbox can also hold calendar invites and delivery reports. They do not always have the same fields, so we skip anything that is not a normal email.
Step 3: The full script with filters
Now let us filter by subject and date, and save the files. Replace the code with this full version:
import datetime
import re
from pathlib import Path
import win32com.client
SUBJECT_WORD = "Daily Sales Report" # text to look for in the subject
DAYS_BACK = 7 # only check the last 7 days
SAVE_FOLDER = Path(r"C:\Reports\Attachments")
SAVE_FOLDER.mkdir(parents=True, exist_ok=True)
since = datetime.date.today() - datetime.timedelta(days=DAYS_BACK)
outlook = win32com.client.Dispatch("Outlook.Application")
inbox = outlook.GetNamespace("MAPI").GetDefaultFolder(6)
items = inbox.Items
items.Sort("[ReceivedTime]", True) # newest first
saved = 0
for item in items:
if item.Class != 43: # skip non-email items
continue
received = item.ReceivedTime.date()
if received < since:
break # sorted newest first, so we can stop here
if SUBJECT_WORD.lower() not in item.Subject.lower():
continue
for att in item.Attachments:
# Remove characters that Windows does not allow in file names
clean_name = re.sub(r'[\\/:*?"<>|]', "_", att.FileName)
# Add the date so files with the same name do not overwrite each other
target = SAVE_FOLDER / f"{received:%Y-%m-%d}_{clean_name}"
att.SaveAsFile(str(target)) # Outlook needs a full path as text
saved += 1
print("Saved:", target)
print(f"Done. {saved} file(s) saved.")
Step 4: Understand the important parts
ReceivedTimegives the date and time the email arrived. We use.date()to compare only the day.- Because the list is sorted newest first, we can
breakwhen we reach an old email. This makes the script fast, even with a big Inbox. att.SaveAsFile()saves one attachment. It needs a full path, likeC:\Reports\Attachments\file.xlsx, as text. That is why we usestr(target).- We add the date to the file name. Daily reports often have the same name every day, and we do not want to overwrite yesterday’s file.
Step 5: Run and check
Run python save_attachments.py. Open C:\Reports\Attachments and check the files. ๐
This script only reads emails and saves files. It does not delete or move anything in Outlook, so it is safe to run many times.
Common problems
pywintypes.com_errorwhen connecting. โ Open Outlook once by hand and make sure it is signed in. Also check you are using desktop Outlook.- Logos and signature images are saved too. โ Skip small files: add
if att.Size < 10000: continue, or only keep names ending with.xlsx. - No emails found, but you can see them. โ Maybe a rule moves them to another folder. Use
inbox.Folders["Reports"]to open a subfolder of the Inbox. - Outlook shows a security prompt. โ This protects you from unknown programs. Keep your antivirus active and allow access only for scripts you wrote yourself.
Wrap-up
You now have a script that collects your daily files without a single click. Next, combine it with the pandas cleaning from an earlier post: save the attachment, clean it, and build your report, all in one run. Happy automating!