How to check all emails that came in within a time period? - python

I have the following method get_email() that basically every 20 seconds, gets the latest email and performs a series of other methods on it.
def get_email():
import win32com.client
import os
import time
import datetime as dt
date_time = time.strftime('%m-%d-%Y')
outlook = win32com.client.Dispatch("Outlook.Application").GetNameSpace("MAPI")
inbox = outlook.GetDefaultFolder(6)
messages = inbox.Items
message = messages.GetFirst() # any time calling GetFirst(), you can get GetNext()....
email_subject = message.subject
email_sender = message.SenderEmailAddress
attachments = message.Attachments
body_content = message.body
print ('From: ' + email_sender)
print ('Subject: ' + email_subject)
if attachments.Count > 0:
print (str(attachments.Count) + ' attachments found.')
for i in range(attachments.Count):
email_attachment = attachments.Item(i+1)
report_name = date_time + '_' + email_attachment.FileName
print('Pushing attachment - ' + report_name + ' - to check_correct_email() function.')
if check_correct_email(email_attachment, email_subject, report_name) == True:
save_incoming_report(email_attachment, report_name, get_report_directory(email_subject))
else:
print('Not the attachment we are looking for.')
# add error logging here
break
else: #***********add error logging here**************
print('No attachment found.')
My main question is:
Is there a way I can iterate over every email using the GetNext() function per se every hour instead of getting the latest one every 20 seconds (which is definitely not as efficient as searching through all emails)?
Given that there are two functions: GetFirst() and GetNext() how would I properly have it save the latest checked, and then go through all the ones that have yet to be checked?
Do you think it would be easier to potentially set up a different folder in Outlook where I can push all of these reports to, and then iterate through them on a time basis? The only problem here is, if an incoming report is auto-generated and the time interval between the email is less than 20 seconds, or even 1 second.
Any help at all is appreciated!

You can use the Restrict function to restrict your messages variable to emails sent within the past hour, and iterate over each of those. Restrict takes the full list of items from your inbox and gives you a list of the ones that meet specific criteria, such as having been received in a specified time range. (The MSDN documentation linked above lists some other potential properties you could Restrict by.)
If you run this every hour, you can Restrict your inbox to the messages you received in the past hour (which, presumably, are the ones that still need to be searched) and iterate over those.
Here's an example of restricting to emails received in the past hour (or minute):
import win32com.client
import os
import time
import datetime as dt
# this is set to the current time
date_time = dt.datetime.now()
# this is set to one hour ago
lastHourDateTime = dt.datetime.now() - dt.timedelta(hours = 1)
#This is set to one minute ago; you can change timedelta's argument to whatever you want it to be
lastMinuteDateTime = dt.datetime.now() - dt.timedelta(minutes = 1)
outlook = win32com.client.Dispatch("Outlook.Application").GetNameSpace("MAPI")
inbox = outlook.GetDefaultFolder(6)
# retrieve all emails in the inbox, then sort them from most recently received to oldest (False will give you the reverse). Not strictly necessary, but good to know if order matters for your search
messages = inbox.Items
messages.Sort("[ReceivedTime]", True)
# restrict to messages from the past hour based on ReceivedTime using the dates defined above.
# lastHourMessages will contain only emails with a ReceivedTime later than an hour ago
# The way the datetime is formatted DOES matter; You can't add seconds here.
lastHourMessages = messages.Restrict("[ReceivedTime] >= '" +lastHourDateTime.strftime('%m/%d/%Y %H:%M %p')+"'")
lastMinuteMessages = messages.Restrict("[ReceivedTime] >= '" +lastMinuteDateTime.strftime('%m/%d/%Y %H:%M %p')+"'")
print "Current time: "+date_time.strftime('%m/%d/%Y %H:%M %p')
print "Messages from the past hour:"
for message in lastHourMessages:
print message.subject
print message.ReceivedTime
print "Messages from the past minute:"
for message in lastMinuteMessages:
print message.subject
print message.ReceivedTime
# GetFirst/GetNext will also work, since the restricted message list is just a shortened version of your full inbox.
print "Using GetFirst/GetNext"
message = lastHourMessages.GetFirst()
while message:
print message.subject
print message.ReceivedTime
message = lastHourMessages.GetNext()
You seem to have it running every 20 seconds, so presumably you could run it at a different interval. If you can't run it reliably at a regular interval (which would then be specified in the timedelta, e.g. hours=1), you could save the ReceivedTime of the most recent email checked, and use it to Restrict your search. (In that case, the saved ReceivedTime would replace lastHourDateTime, and the Restrict would retrieve every email sent after the last one checked.)
I hope this helps!

I had a similar question and worked through the above solution. Including another general use example in case other folks find it easier:
import win32com.client
import os
import datetime as dt
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
# setup range for outlook to search emails (so we don't go through the entire inbox)
lastWeekDateTime = dt.datetime.now() - dt.timedelta(days = 7)
lastWeekDateTime = lastWeekDateTime.strftime('%m/%d/%Y %H:%M %p') #<-- This format compatible with "Restrict"
# Select main Inbox
inbox = outlook.GetDefaultFolder(6)
messages = inbox.Items
# Only search emails in the last week:
messages = messages.Restrict("[ReceivedTime] >= '" + lastWeekDateTime +"'")
print(message.subject)
# Rest of code...

The below solution gives past 30 minutes unread folder mails from outlook and the count of the mails within the past 30 minutes
import win32com.client
import os
import time
import datetime as dt
# this is set to the current time
date_time = dt.datetime.now()
#This is set to one minute ago; you can change timedelta's argument to whatever you want it to be
last30MinuteDateTime = dt.datetime.now() - dt.timedelta(minutes = 30 )
outlook = win32com.client.Dispatch("Outlook.Application").GetNameSpace("MAPI")
inbox = outlook.GetDefaultFolder(6)
# retrieve all emails in the inbox, then sort them from most recently received to oldest (False will give you the reverse). Not strictly necessary, but good to know if order matters for your search
messages = inbox.Items.Restrict("[Unread]=true")
messages.Sort("[ReceivedTime]", True)
last30MinuteMessages = messages.Restrict("[ReceivedTime] >= '" +last30MinuteDateTime.strftime('%m/%d/%Y %H:%M %p')+"'")
print "Current time: "+date_time.strftime('%m/%d/%Y %H:%M %p')
print "Messages from the past 30 minute:"
c=0
for message in last30MinuteMessages:
print message.subject
print message.ReceivedTime
c=c+1;
print "The count of meesgaes unread from past 30 minutes ==",c

Using import datetime, this is what I came up with:
count = 0
msg = messages[len(messages) - count - 1]
while msg.SentOn.strftime("%d-%m-%y") == datetime.datetime.today().strftime("%d-%m-%y"):
msg = messages[len(messages) - count - 1]
count += 1
# Rest of the code

Related

Outlook mail restriction on current date

I am doing automation on the manual work where I am reading the data from outlook mail using win32.
But I need to read mail restrict on the current date otherwise won't read the mail. If mail is not there on a current date then it will skip this part. Below are the codes that compare the received date and today but getting the error.
outlook = win32.Dispatch("Outlook.Application").GetNamespace("MAPI")
folder = outlook.GetDefaultFolder(6)
messages = folder.Items
messages.Sort("[ReceivedTime]", True)
CurrentDateTime = dt.datetime.now()
CurrentDateTime = CurrentDateTime.strftime('%m/%d/%Y %H:%M %p')
messages = messages.Restrict("[ReceivedTime] == '" + CurrentDateTime +"'")
print(messages)
for m in messages:
if m.Subject.startswith('Daily SSC count to SD Team'):
m1=m.Body
print(m1)
break;
Error:
File "<COMObject <unknown>>", line 2, in Restrict
pywintypes.com_error: (-2147352567, 'Exception occurred.', (4096, 'Microsoft Outlook', 'Cannot parse condition. Error at "=".', None, 0, -2147352567), None)
Never use = when working with date/time properties - the condition will never be satisfied even if the value (both date and time) matches that of an existing message because of round-off errors.
Always use a range (< and >), or (if you are dealing with the current date and assume there won't be any messages with a newer date), use >= as #0m3r suggested.
It should be only one = not two == try itItems.Restrict method (Outlook) it should give you current date and time
Example
messages = messages.Restrict("[ReceivedTime] = '" + CurrentDateTime +"'")
But if your are trying to set the filter for 24 hours then start with today's date with time 00:00 then use >= on current_date = dt.date.today()
full example
import win32com.client
import datetime as dt
def outlook_email(Inbox):
current_date = dt.date.today()
print(current_date)
current_date = current_date.strftime("%m/%d/%Y %H:%M")
print(current_date)
items = Inbox.Items.Restrict("[ReceivedTime]>='" + current_date + "'")
print(items.Count)
if __name__ == "__main__":
outlook = win32com.client.Dispatch(
"Outlook.Application").GetNamespace(
"MAPI"
)
inbox = outlook.GetDefaultFolder(6)
outlook_email(inbox)

python win32com.client outlook application is not filtering received emails

I wrote the code as below, but it doesn't do a time filter. what am i doing wrong?
import win32com.client
import os
from datetime import datetime, timedelta
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
# setup range for outlook to search emails (so we don't go through the entire inbox)
received_dt = datetime.now() - timedelta(days=1)
received_dt = received_dt.strftime('%m/%d/%Y %H:%M %p')
# Select main Inbox
inbox = outlook.Folders("example#mydomain.com").Folders("Inboxx")
messages = inbox.Items.Restrict("[ReceivedTime] >= '" + received_dt + "'")
for message in messages:
print(str(message.ReceivedTime))
I am pasting the output of the code below.
2021-07-05 19:56:03.826000+00:00
2021-09-21 23:13:31.429000+00:00
2021-09-26 22:15:13.527000+00:00
2021-10-03 12:45:04.919000+00:00
2021-10-03 19:43:05.916000+00:00
2021-10-03 20:40:05.875000+00:00
Can you help me please?
Try to compute the date and time string before you call the Restrict method:
import win32com.client
import os
from datetime import datetime, timedelta
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
# setup range for outlook to search emails (so we don't go through the entire inbox)
lastWeekDateTime = dt.datetime.now() - dt.timedelta(days= 7)
lastWeekDateTime = lastWeekDateTime.strftime('%Y-%m-%d %H:%M') #<-- This format compatible with "Restrict"
received_dt = datetime.now() - timedelta(days=1)
received_dt = received_dt.strftime('%m/%d/%Y %H:%M %p')
# Select main Inbox
inbox = outlook.Folders("example#mydomain.com").Folders("Inboxx")
messages = inbox.Items.Restrict("[ReceivedTime] >= '" + received_dt + "'")
for message in messages:
print(str(message.ReceivedTime))
Read more about the Restrict method in the How To: Use Restrict method to retrieve Outlook mail items from a folder article.

How to make a time restriction in outlook using python?

I am making a program that:
opens outlook
find emails per subject
extract some date from emails (code and number)
fills these data in excel file in.
Standard email looks like this:
Subject: Test1
Hi,
You got a new answer from user Alex.
Code: alex123fj
Number1: 0611111111
Number2: 1020
Number3: 3032
I encounter 2 main problems in the process.
Firstly, I do not get how to make time restriction for emails in outlook. For example, if I want to read emails only from yesterday.
Secondly, all codes and numbers from email I save in lists. But every item gets this ["alex123fj/r"] in place from this ["alex123fj"]
I would appreciate any help or advice, that is my first ever program in Python.
Here is my code:
import win32com.client
import re
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.Folders('myemail#....').Folders('Inbox')
messages = inbox.Items
def get_code(messages):
codes_lijst = []
for message in messages:
subject = message.subject
if subject == "Test1":
body = message.body
matches = re.finditer("Code:\s(.*)$", body, re.MULTILINE)
for match in matches:
codes_lijst.append(match.group(1))
return codes_lijst
def get_number(messages):
numbers_lijst = []
for message in messages:
subject = message.subject
if subject == "Test1":
body = message.body
matches = re.finditer("Number:\s(.*)$", body, re.MULTILINE)
for match in matches:
numbers_lijst.append(match.group(1))
return numbers_lijst
code = get_code(messages)
number = get_number(messages)
print(code)
print(number)
Firstly, never loop through all items in a folder. Use Items.Find/FindNext or Items.Restrict with a restriction on ConversationTopic (e.g. [ConversationTopic] = 'Test1').
To create a date/time restriction, add a range restriction ([ReceivedTime] > 'some value') and [ReceivedTime] < 'other value'

Python Script Not Showing All Rows in Email

I wrote a script that would look into all subfolders for a directory and compare their date modified value to the current timestamp. If its great than 30 minutes then it would send me an email. If there is more than one string returned it sends me the same amount of emails. How can i put all the results in one email instead of it sending me multiple emails for multiple subfolders?
Output now :
Email 1:
C:\Test\Test: 00:30:00
Email 2:
C:\Test\Test2: 00:30:00
Email 3:
C:\Test\Test3: 00:30:00
Expected output:
One email:
C:\Test\Test: 00:30:00
C:\Test\Test2: 00:30:00
C:\Test\Test3: 00:30:00
import os
import time
import sys
from datetime import date
from datetime import datetime
from datetime import timedelta
import win32com.client as win32
print("There are folders inside GOXSA2016 for longer than 30 minutes. Please
login to server and
check for errors. See duration time periods below")
for root, folders, files in os.walk('N:\OCRFF\import'):
for name in folders:
datetimeFormat = '%Y-%m-%d %H:%M:%S.%f'
filedate = datetime.fromtimestamp(os.path.getmtime(os.path.join(root,
name)))
now_time = datetime.now()
now_time = str(now_time)
filedate = str(filedate)
now_time = datetime.strptime(now_time, datetimeFormat)
filedate = datetime.strptime(filedate, datetimeFormat)
difference = now_time-filedate
if difference > timedelta(seconds=1) and os.path.join(root, name)=='N:\\OCRFF\\import':
break
if difference > timedelta(seconds=1):
file_times = os.path.join("\\\Test\Test2" + root.strip("N:"), name),":
",str(difference)
file_times_final = file_times[0] + file_times[1] + file_times[2]
outlook = win32.Dispatch('outlook.application')
mail = outlook.CreateItem(0)
mail.To = 'test#test.com'
mail.Subject = '**CORRESPONDENCE ALERT**'
mail.HTMLBody = f"""
There are folders inside that arelonger than 30
minutes. Please login to server and
check for errors. See duration time period below for
the folder path.<br/><br/>"""
mail.HTMLBody = mail.HTMLBody + file_times_final + """<br/>"""
mail.HTMLBody = mail.HTMLBody + '''<br /><br /> Thank You, <br />
Payment
Processing Center<br />'''
mail.Send()
There are many ways to do this. A simple way is to make file_times_final a list and append to it, then send one email outside the loop like was suggested.
After your import add file_times_final = [] this is an empty list declaration. You can store anything inside a list with list.append(input)
So instead of file_times_final = file_times[0] + file_times[1] + file_times[2] make it
file_times_final.append(file_times[0] + file_times[1] + file_times[2]) This just says append to your list those times every time the loop hits.
Then take out your email code outside of the loop and the result should be a comma separated list with brackets [] surrounding it. You can play with the output format.

Python read last 10 emails from Outlook

I can read my last email from my Outlook and send all the results according to each line's content.
However, I am unable to find the way to read my last 10 emails to be added to the fileCollect.txt file.
Any ideas how I could do this? Here is my current code:
import win32com.client
import csv
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6) # "6" refers to the index of a folder - in this case,
# the inbox. You can change that number to reference
# any other folder
messages = inbox.Items
message = messages.GetLast()
fileCollect = open("fileCollect.txt",'a')
delimiter = "¿"
fileCollect.write( str(message.Sender) + delimiter + str(message.Subject)+ delimiter + str(message.Body) )
fileCollect.close()
csvfile = open("csvfile.csv",'a')
with open("fileCollect.txt","r") as outfile:
for line in outfile:
if line.find("test") != -1:
csvfile.write(line)
csvfile.close()
The Items collection will not be sorted in any particular order until you actually sort it by calling Items.Sort. The VB script below sorts the collection by ReceivedTime in the descending order:
set messages = inbox.Items
messages.Sort("ReceivedTime", True)
set message = messages.GetFirst()
while not (message Is Nothing)
MsgBox message.Subject
set message = messages.GetNext()
wend
You can get the last 10 messages by specifying a negative index:
last_10_messages = messages[-10:]
This will return an array from messages[-10], which is the 10th to the last message, to the last message in the messages array.
use len(inbox.Items) to get the length of the inbox.
use inbox.Items.Item(i) to get i-th email in the inbox.
Ref:
https://learn.microsoft.com/en-us/office/vba/api/outlook.items.item

Categories

Resources