Home > Net >  Pull variable data from all outlook emails that have a particular subject line then take date from t
Pull variable data from all outlook emails that have a particular subject line then take date from t

Time:11-06

I get an email every day with fruit quantities sold on the day. Though I now have come up with some code to log the relevant data going forward, I have been unable to do it going backwards.

The data is stored in the body of the email like so:

Date of report:,01-Jan-2020
Apples,8
Pears,5
Lemons,7
Oranges,9
Tomatoes,6
Melons,3
Bananas,0
Grapes,4
Grapefruit,8
Cucumber,2
Satsuma,1

What I would like for the code to do is first search through my emails and find the emails that match a particular subject, iterate line by line through and find the variables I'm searching for, and then log them in a dataframe with the "Date of Report" logged in a date column and converted into the format: "%m-%d-%Y".

I think I can achieve this by doing some amendments to the code I've written to deal with keeping track of it going forward:

# change for the fruit you're looking for
Fruit_1 = "Apples"
Fruit_2 = "Pears"

outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6) 
messages = inbox.Items
messages.Sort("[ReceivedTime]", True)

# find data email
for message in messages:
    if message.subject == 'FRUIT QUANTITIES':
        if Fruit_1 and Fruit_2 in message.body: 
            data = str(message.body)
            break
        else:
            print('No data for', Fruit_1, 'or', Fruit_2, 'was found')
            break

fruitd = open("fruitd.txt", "w") # copy the contents of the latest email into a .txt file
fruitd.write(data)
fruitd.close()

def get_vals(filename: str, searches: list) -> dict:
    #Searches file for search terms and returns the values
    dct = {}
    with open(filename) as file:
        for line in file:
            term, *value = line.strip().split(',')
            if term in searches:
                dct[term] = float(value[0]) # Unpack value 
    # if terms are not found update the dictionary w remaining and set value to None
    if len(dct.keys()) != len(searches):
        dct.update({x: None for x in search_terms if x not in dct})
    return dct


searchf = [
    Fruit_1, 
    Fruit_2
] # the list of search terms the function searches for

result = get_vals("fruitd.txt", searchf) # search for terms 
print(result)

# create new dataframe with the values from the dictionary
d = {**{'date':today}, **result}
fruit_vals = pd.DataFrame([d]).rename(columns=lambda z: z.upper())
fruit_vals['DATE'] = pd.to_datetime(fruit_vals['DATE'], format='%d-%m-%Y')
print(fruit_vals)

I'm creating a .txt titled 'fruitd' because I was unsure how I could iterate through an email message body any other way. Unfortunately I don't think creating a .txt for each of the past emails is really feasible and I was wondering whether there's a better way of doing it?

Any advice or pointers would be most welcome.

**EDIT Ideally would like to get all the variables in the search list; so Fruit_1 & Fruit_2 with room to expand it to a Fruit_3 Fruit_4 (etc) if necessary.

CodePudding user response:

#PREP THE STUFF
Fruit_1 = "Apples"
Fruit_2 = "Pears"
SEARCHF = [
    Fruit_1, 
    Fruit_2
]

#DEF THE STUFF
# modified to take a list of list of strs as `report` arg
# apparently IDK how to type-hint; type-hinting removed
def get_report_vals(report, searches):
    dct = {}
    for line in report:
        term, *value = line
        # `str.casefold` is similar to `str.lower`, arguably better form
        # if there might ever be a possibility of dealing with non-Latin chars
        if term.casefold().startswith('date'):
            #FIXED (now takes `date` str out of list)
            dct['date'] = pd.to_datetime(value[0])
        elif term in searches:
            dct[term] = float(value[0])
    if len(dct.keys()) != len(searches):
        # corrected (?) `search_terms` to `searches`
        dct.update({x: None for x in searches if x not in dct})
    return dct


#DO THE STUFF
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6) 
messages = inbox.Items
messages.Sort("[ReceivedTime]", True)

results = []

for message in messages:
    if message.subject == 'FRUIT QUANTITIES':
        # are you looking for:
        #  Fruit_1 /and/ Fruit_2
        # or:
        #  Fruit_1 /or/  Fruit_2
        if Fruit_1 in message.body and Fruit_2 in message.body:
            # FIXED
            data = [line.strip().split(",") for line in message.body.split('\n')]
            results.append(get_report_vals(data, SEARCHF))
        else:
            pass

fruit_vals = pd.DataFrame(results)
fruit_vals.columns = map(str.upper, fruit_vals.columns)
  • Related