0

Below is my Python code using win32com to read emails from a particular folder.


from logging import root
import os
import win32com.client
from datetime import datetime, timedelta
import zipfile

date_format = "%m/%d/%Y %H:%M"

def recursively_find_folder(folder, target_name):
    if folder.Name == target_name:
        return folder
    for subfolder in folder.Folders:
        found_folder = recursively_find_folder(subfolder, target_name)
        if found_folder:
            return found_folder

#function to check the emails mentioned in outlook folder and down load the attachements based on email subject
def download_attachments(folder_name, output_folder, start_time, end_time, target_subject):
    outlook_app = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
    #root_folder = outlook_app.Folders.Item(3)  # Assume the first folder is the mailbox
    root_folder = outlook_app.GetDefaultFolder(6)  # Assume the first folder is the mailbox
      
    target_folder = recursively_find_folder(root_folder, folder_name)

    if target_folder:
        print(f"Found folder: {target_folder.Name}")

        # Iterate through items in the folder
        items = target_folder.Items
        items.sort("[ReceivedTime]", True)

        for item in items:
            print("Item:: ", item)
            print("    Subject:: ", item.Subject.lower())
            print("    Recevied Time: ", item.ReceivedTime)
            # Check if the email matches the criteria
            for subject in target_subject:
                print(subject)
                print("Email Received Time: ", datetime.strptime(item.ReceivedTime.strftime('%m/%d/%Y %H:%M'), date_format))
                if (
                    start_time <= datetime.strptime(item.ReceivedTime.strftime('%m/%d/%Y %H:%M'), date_format) <= end_time
                    and subject.lower().strip() in item.Subject.lower().strip()
                    and item.Attachments.Count > 0
                ):
                    print(f"Processing email: {item.Subject}")
                    for attachment in item.Attachments:
                        # Save attachments to the output folder
                        attachment.SaveAsFile(os.path.join(output_folder, attachment.FileName))
                        print(f"Downloaded attachment: {attachment.FileName}")
                else:
                    print("Nothing Happened!!!")

    else:
        print(f"Folder '{folder_name}' not found.")
        
#--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#function to find zip folder and unzip it
def find_and_unzip_report_file(folder_path, extraction_path):
    # Check if the folder exists
    if not os.path.exists(folder_path):
        print(f"Error: Folder '{folder_path}' not found.")
        return

    # Get a list of all files in the folder
    files = os.listdir(folder_path)

    # Find the report file based on the name pattern
    report_file = next((file for file in files if file.lower().startswith('report') and file.lower().endswith('.zip')), None)

    if report_file:
        # Construct the full path to the zip file
        zip_file_path = os.path.join(folder_path, report_file)

        # Create the extraction path if it doesn't exist
        os.makedirs(extraction_path, exist_ok=True)

        # Unzip the contents of the zip file
        with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
            zip_ref.extractall(extraction_path)
        
        os.rename(folder_path + 'CC CM Provisioning - INC SLA - ALL.csv', folder_path + 'CC CM Provisioning - INC SLA - ALL' + '-' + report_file[7:24] + '.csv')
        
        os.remove(zip_file_path)
        print(f"Successfully unzipped '{zip_file_path}' to '{extraction_path}'.")
    else:
        print("Error: Report file not found in the specified folder.")


if __name__ == "__main__":
    folder_to_download = "service_tickets"
    output_directory = "//prod_drive/meta/downloads/"
    # Get the first day of the current month
   
    start_date_time = (datetime.today().replace(day=1, hour=23, minute=0, second=0, microsecond=0) - timedelta(days=1)).strftime('%m/%d/%Y %H:%M')
    
    end_date_time = (datetime.today().replace(day=1, hour=23, minute=10, second=0, microsecond=0) - timedelta(days=1)).strftime('%m/%d/%Y %H:%M') 
    date_format = "%m/%d/%Y %H:%M"
    start_time = datetime.strptime(start_date_time, date_format)
    print("Start Time:", start_time)
    end_time = datetime.strptime(end_date_time, date_format)
    print("End Time: ", end_time)
    target_subject = ['CC CM Provisioning - INC SLA - ALL','CC CM Provisioning - SCTASK SLA - All','CC CM Provisioning - SCTASK - All']


    download_attachments(folder_to_download, output_directory, start_time, end_time, target_subject)
    
    find_and_unzip_report_file(output_directory, output_directory)

But the above code only reads email till 05/31/2024 and nothing after that. I tried running the code for other folders as well, but is the same. Emails scanned/processed only till 05/31.

Could someone please advise what exactly the issue in my code. Couldnt find any similar posts regarding this.

1
  • Forgot to mention, Im using Outlook from O365. Commented Aug 8, 2024 at 18:23

2 Answers 2

0

Your code assumes you can only have MailItem objects in the folder. If you have an NDR (represented by the ReportItem object), ReceivedTime prioperty is not exposed, and your code will error out.

Sign up to request clarification or add additional context in comments.

7 Comments

@Dmitry_Streblechenko thank you for your response. But im not at all concerned about NDR mails. I have a rule that moves emails to a specific folder, and those are the emails and their attachments are of my interest. Why I wrote a generic code is that, Im planning to circulate it among my team, so that everyone can use one single code, as different people have different maibox folder structure. Kindly advise if you have any other inputs.
Well, rephrasing a popular saying, you might not be interested in NDRs, but they will be interested in you :-). If you only want MailItem objects, add a check for the item.Class property == 43.
It doesnt make any difference.. same issue and not the latest emails are being read. Any advise?
You'd need to step through your code to see where and why it bails out. Does items.Count match what you see in Outlook?
No, the count returns wrong result and for some reason it just reads mails till 05/01/2024. Thats when I developed my code and tested for the first time. Not sure if it has anything to do with win32com object getting cached. But I tried pythoncom.coinitialize() and pythoncom.counitialize() at the start and end of the script. But no luck.
|
0

It seems win32com works only with Outlook Classic which uses a .pst data file, and I switched from outlook classic to 'New Outlook' on May. As a result, my mailbox and folders were not synced in the classic version and the code is picking only those till May which are available there. After i switched to the classic version, I saw that my mailbox is not refreshed, and after a while when the mailbox got refreshed and ran the above code, it started reading all the emails from the necessary folders as desired.

enter image description here

Hopefully in future, win32com might put in a fix to read from 'New Outlook' as well where the .pst file is not being used.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.