Python Emails Being Duplicated - python

My script is duplicating my emails when I print print(ggg_email). Im guessing the error is in my ggglastHourMessages. Not sure if im just getting the last 48 hours for the ReceivedTime. Can someone explain if Im doing something wrong there ?
expected results:
Test Email
actual :
Test Email
Test Email
code:
def readEmail():
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
folder = outlook.Folders.Item('SharedMailbox, TEST-Investigation')
inbox = folder.Folders.Item('Inbox')
subfolder = inbox.Folders.Item('BoA ICL Ack Notifications')
messages = subfolder.Items
lastHourDateTime = datetime.now() - timedelta(hours=48)
ggglastHourMessages = messages.Restrict("[ReceivedTime] >= '" + lastHourDateTime.strftime('%m/%d/%Y %H:%M %p') + "'")
ggg_emails_l = []
for ggg_email in ggglastHourMessages:
if 'P2 Cust ID 1111111 File' in ggg_email.Subject:
print(ggg_email)

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.

Python: Downloading Outlook Attachments and Change Filename on Save

the following code works below, however i am trying to add a parameter that changes the filename on the SaveAsFile method to the iteration of (a) the message that i am on.
As an Example the Current output is
Returned mail see transcript for details
Returned mail see transcript for details
The Desired output is
Returned mail see transcript for details1
Returned mail see transcript for details2
Returned mail see transcript for details3
Currently this code just overwrites the same save file in my folder, however i need to accomplish saving that same file from different messages to a new file name.
Code Below:
import win32com.client
import os
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
messages = inbox.Items
message = messages.GetFirst()
subject = message.Subject
i = 0
#
get_path = r'S:\Corporate Shared\Contracting Shared\DATA_PROJECTS\James\Email Extraction\Undeliverable Items'
for m in messages:
i = i + 1 #numeration
a = str(i) #Creates i as a string
if m.Subject == ("Returned mail: see transcript for details"):
#print(message)
attachments = message.Attachments
num_attach = len([x for x in attachments])
for x in range(1, num_attach + 1):
attachment = attachments.Item(x)
attachment.SaveASFile(os.path.join(get_path,attachment.FileName))
print(attachment)
#print(a)
message = messages.GetNext()
else:
message = messages.GetNext()
Instead of using attachment.FileName in the call to os.path.join, store attachment.FileName in a variable, then replace the last "." with "_" + x + "."

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.

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

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

Categories

Resources