Pywin – Automate Window Apps with Python

What I really dislike in my work are all these activities that are not complicated but have to be performed very often on a regular basis. Imagine copy-paste something n times over and over again…

A great example, that actually happened to me, was analysing incoming mails. More precisely – on daily basis to my mailbox in MSOutlook 2 messegaes were delivered. One for e-commerce sales and second one for professional sales. What I had to do was save reports (attachments) from certain dates, under distinct folders (e-commerce / prof) and rename each of the file using date. Pretty annoying, isnt it?

Being a Python Dev and Analyst made me lazy guy that seeks for automation as much as it is possible. And guess what? I decided to get rid of my fav task and use Py-power.

Pywin

Pywin is indeed a win. Not funny, I know but this library is simply outstanding. Pywin32 provides multiple methods that allow user to manipulate various Windows API objects. For instance using Pywin you can refer directly to Windows GUI methods, perform complex operations of file structures, use native WIN methods to interfere with servicess etc. To learn more about this library I recommend to visit this page: http://timgolden.me.uk/pywin32-docs/index.html

Let’s code a script

Our goal is to access MS Outlook. To achieve that we have to use COM model. Not going into technical details COM model allows us to manipulate with Win objects.

Before we code anything lets think what is the process. We receive mails with attached .xlsx file that contains report. Each mail has title consisting of follwoing items “DD-MM-YYYY sales”. Then we have to save att. to certain destination folder and rename it using report date.

So let’s import libraries that we will use:

import win32com.client as pywin
import re
from datetime import datetime

Besides Pywin we will need date to deal with timestamps and re to perform regex operations.

Now we can code our class:

class Collect:

    def __init__(self,data_start,data_stop,mail_address,path_pro,path_com, option="Inbox"):
        self._podziel_date(data_start,data_stop)
        self.pro = path_pro
        self.com = path_com
        self.mail = mail_address   
        self.handler = pywin.Dispatch('Outlook.Application').GetNamespace("MAPI")
        self.box = self.handler.Folders(mail_address).Folders(option) 
        self.messeges = self.box.Items 

    def _podziel_date(self,data_start,data_stop): 
        self.start = datetime.strptime(data_start, '%Y-%m-%d') 
        self.stop = datetime.strptime(data_stop, '%Y-%m-%d') 

    def retreive_reports(self):
        for mail in self.messeges:
            temp_received_var = str(mail.ReceivedTime)
            temp_received_var = temp_received_var[:10] 
            temp_received_var_date = datetime.strptime(temp_received_var, '%Y-%m-%d')
            if temp_received_var_date >= self.start and temp_received_var_date <= self.stop:
                if re.search("^.*Raport sprzedaży.*", mail.Subject):
                    if re.search("^.*E-Commerce.*", mail.Subject):
                        for attachment in mail.Attachments:
                            print(temp_received_var, attachment.FileName)
                            ev = self.com + str(temp_received_var)[:10] + " " + attachment.FileName
                            attachment.SaveASFile(ev)
                    if re.search("^.*Professional.*", mail.Subject):
                        for attachment in mail.Attachments:
                            print(temp_received_var, attachment.FileName)
                            ev = self.pro + str(temp_received_var)[:10] + " " + attachment.FileName
                            attachment.SaveASFile(ev)

We passed to the class constructor few parameters. Data start/stop are time frames, mail_address indicates mail account (IMPORTANT: this mail must be used within Outlook profile), path pro/com are path to folders where our reports will be stored and last arguments contains inbox name.

Within the constructor some important actions take place.

pywin.Dispatch(‘Outlook.Application’).GetNamespace(“MAPI”) here we inform Python that we are going to comunicate with Outlook so we want to create namespaces which are kind of session equivalent.

self.box = self.handler.Folders(mail_address).Folders(option) – next step is to select correct account (here we need to indicate profil by the email address provided with on of the params) and then catalouge where mails are stored -> Inbox.

parametr z adresem e-mail) oraz który katalog zawiera poszukiwane przez nas maile.

self.messages = self.box.Items – finally we want to focus on messages which are represented by .Items collection.

There is one more custom method that involved strptime function. We want to convert initial/final date from pure string to date object so we can easily compare dates.

Method retreive_reports here the “magic” happens. Previously created element with .Item method is iterable which means we can access each element with a loop. Pywin allows us to check each message title with only one attribute of the mail object -> .Title. Same goes for date reveived -> .ReceivedTime

Going thru all the messages we chose only these that meet following conditions:

  1. Date received matches time frames
  2. Title contains key-words.

To check title criterion we shall use regex search fuction.

Final step is to save attachment under certain catalog and rename it.

Summary

I’m aware of the fact that this script is not optimised nor generic one 😉 But I needed a quick solution to one of the most annoying things that happened to me recently

Leave a Reply

Your email address will not be published. Required fields are marked *