Search code examples
pythonwin32compythoncom

How to continuously monitor a new mail in outlook and unread mails of a specific folder in python


I want to check for a particular sender email and process it automatically wherever it arrives

However, there may be some situation where my outlook was restarted, mean while i received mail from sender and marked as unread

For continuous monitor for a new mail for a specific subject i have found the following code

import win32com.client
import pythoncom
import re

class Handler_Class(object):
  def OnNewMailEx(self, receivedItemsIDs):
    # RecrivedItemIDs is a collection of mail IDs separated by a ",".
    # You know, sometimes more than 1 mail is received at the same moment.
    for ID in receivedItemsIDs.split(","):
        mail = outlook.Session.GetItemFromID(ID)
        subject = mail.Subject
    print subject   
        try: 
            command = re.search(r"%(.*?)%", subject).group(1)

            print command # Or whatever code you wish to execute.
        except:
            pass


outlook = win32com.client.DispatchWithEvents("Outlook.Application",Handler_Class)

#and then an infinit loop that waits from events.
pythoncom.PumpMessages() 

Even i want to go through all the unread mails to check whether a mail from a sender has came and process it( if found)

Is there any function to check for unread mails to add within handler_class

Or let me know for any alternate procedure


Solution

  • So if you restart your python script every time your Outlook restart, then add these lines to your code to check unread emails in your Inbox:

    ol = win32com.client.Dispatch( "Outlook.Application")
    inbox = ol.GetNamespace("MAPI").GetDefaultFolder(6)
    for message in inbox.Items:
        if message.UnRead == True:
            print message.Subject #or whatever command you want to do
    

    Put this code before your definition of outlook in your code

    EDIT

    For me, the code you posted works great until I close Outlook and then even if I reopen it, I don't get anything when a new message is received (see one of my comments). I guess the fact of closing Outlook "unlink" with pythoncom.PumpMessages(). Anyway, I come around to do both your checking for unread email in the class Handler_Class and restart the monitoring in case you restart Outlook.

    import win32com.client
    import ctypes # for the VM_QUIT to stop PumpMessage()
    import pythoncom
    import re
    import time
    import psutil
    
    class Handler_Class(object):
    
        def __init__(self):
            # First action to do when using the class in the DispatchWithEvents     
            inbox = self.Application.GetNamespace("MAPI").GetDefaultFolder(6)
            messages = inbox.Items
            # Check for unread emails when starting the event
            for message in messages:
                if message.UnRead:
                    print message.Subject # Or whatever code you wish to execute.
    
        def OnQuit(self):
            # To stop PumpMessages() when Outlook Quit
            # Note: Not sure it works when disconnecting!!
            ctypes.windll.user32.PostQuitMessage(0)
    
        def OnNewMailEx(self, receivedItemsIDs):
        # RecrivedItemIDs is a collection of mail IDs separated by a ",".
        # You know, sometimes more than 1 mail is received at the same moment.
            for ID in receivedItemsIDs.split(","):
                mail = self.Session.GetItemFromID(ID)
                subject = mail.Subject
                print subject   
                try: 
                    command = re.search(r"%(.*?)%", subject).group(1)
                    print command # Or whatever code you wish to execute.
                except:
                    pass
    
    # Function to check if outlook is open
    def check_outlook_open ():
        list_process = []
        for pid in psutil.pids():
            p = psutil.Process(pid)
            # Append to the list of process
            list_process.append(p.name())
        # If outlook open then return True
        if 'OUTLOOK.EXE' in list_process:
            return True
        else:
            return False
    
    # Loop 
    while True:
        try:
            outlook_open = check_outlook_open()
        except: 
            outlook_open = False
        # If outlook opened then it will start the DispatchWithEvents
        if outlook_open == True:
            outlook = win32com.client.DispatchWithEvents("Outlook.Application", Handler_Class)
            pythoncom.PumpMessages()
        # To not check all the time (should increase 10 depending on your needs)
        time.sleep(10)
    

    Not sure it is the best way, but it seems to work the way you look for.