Downloading Email Attachments from Shared Folder - Python - python

I have the below code to download email attachments based on date sent and email subject criteria:
from datetime import date, timedelta
import os
import win32com.client
path = os.path.expanduser("C:\\Users\\xxxx\\Documents\\Projects\\VBA Projects\\VLOOKUP Automation\\Vlookup File Location")
today = date.today()
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.Folders("xxx").Folders.Item("Inbox")
messages = inbox.Items
subject = "xxx"
dateHigh = date.today() - timedelta(days=1)
dateLow = date.today() - timedelta(days=-1)
max = 2500
for count, message in enumerate(messages):
if count > max:
break
if subject in message.subject and message.senton.date() > dateLow and message.senton.date() < dateHigh:
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(path + '\\' + str(attachment))
Is there any way to specify criteria for only .csv attachments to be downloaded for example?
Additionally, this code was previously being used on a public folder - those folders have now been updated to shared folders. Since the update, I have had to increase the "max" from 500 to 2500 in order to find the specified emails. Is there any way to speed this up?
Thanks

Below is a way to specify which file types you want.
Please enter the file endings in the attachments_of_interest list.
from datetime import date, timedelta
import os
import win32com.client
path = os.path.expanduser("C:\\Users\\xxxx\\Documents\\Projects\\VBA Projects\\VLOOKUP Automation\\Vlookup File Location")
today = date.today()
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.Folders("xxx").Folders.Item("Inbox")
messages = inbox.Items
subject = "xxx"
dateHigh = date.today() - timedelta(days=1)
dateLow = date.today() - timedelta(days=-1)
max_n = 2500
attachments_of_interest = ['.csv']
for count, message in enumerate(messages):
if count > max_n:
break
if subject in message.subject and message.senton.date() > dateLow and message.senton.date() < dateHigh:
attachments = message.Attachments
num_attach = len([x for x in attachments])
for x in range(1, num_attach+1):
attachment = attachments.Item(x)
attachment_fname = str(attachment)
file_ending = attachment_fname.split('.')[-1]
if not attachments_of_interest or file_ending in attachments_of_interest:
attachment.SaveASFile(path + '\\' + attachment_fname)
As for speeding up, you could use a pool:
from multiprocessing.pool import ThreadPool as Pool
from datetime import date, timedelta
import os
import win32com.client
path = os.path.expanduser("C:\\Users\\xxxx\\Documents\\Projects\\VBA Projects\\VLOOKUP Automation\\Vlookup File Location")
today = date.today()
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.Folders("xxx").Folders.Item("Inbox")
messages = inbox.Items
subject = "xxx"
max_n = 2500
attachments_of_interest = ['.csv']
pool_size = 5
# define worker function before a Pool is instantiated
def worker(message):
dateHigh = date.today() - timedelta(days=1)
dateLow = date.today() - timedelta(days=-1)
if subject in message.subject and message.senton.date() > dateLow and message.senton.date() < dateHigh:
attachments = message.Attachments
num_attach = len([x for x in attachments])
for x in range(1, num_attach+1):
attachment = attachments.Item(x)
attachment_fname = str(attachment)
file_ending = attachment_fname.split('.')[-1]
if not attachments_of_interest or file_ending in attachments_of_interest:
attachment.SaveASFile(path + '\\' + attachment_fname)
pool = Pool(pool_size)
for count, message in enumerate(messages):
if count > max_n:
break
pool.apply_async(worker, (message,))
pool.close()
pool.join()

I think this is part of requirement to download csv only.
This outlook component has some methods which you can utilize.
Instead of messages = inbox.Items
try
messages = inbox.Items.GetFirst()
and get first message then use
messages = inbox.Items.oItems.GetNext()
so in this way you always have one message in memory and you can keep looping for longer time.
Make sure you have outlook Microsoft Outlook 16.0 Object Library or higher than 10 so that this method exists. GetFirst()
c# code used by me
Outlook.MailItem oMsg = (Outlook.MailItem)oItems.GetFirst();
//Output some common properties.
Console.WriteLine(oMsg.Subject);
Console.WriteLine(oMsg.SenderName);
Console.WriteLine(oMsg.ReceivedTime);
Console.WriteLine(oMsg.Body);
//Check for attachments.
int AttachCnt = oMsg.Attachments.Count;
Console.WriteLine("Attachments: " + AttachCnt.ToString());
Outlook.MailItem oMsg1 = (Outlook.MailItem)oItems.GetNext();

Related

How to save email from outlook using python

I am trying to save email from sub-folder using the below python script, I am trying to restrict with days=1 means I only need to save emails which are 1 day old.
from win32com.client import Dispatch
from datetime import date, timedelta
import datetime as dt
msg_location = r'C:\Users\rahul\Desktop\msg_files'
outlook = Dispatch("outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6).Folders['Email_snapper']
messages = inbox.Items
message = messages.GetFirst()
Body_content = message.Body
print(Body_content)
for msg in messages:
lastWeekDateTime = dt.datetime.now() - dt.timedelta(days=1)
lastWeekDateTime = lastWeekDateTime.strftime('%m/%d/%Y %H:%M %p')
message = messages.Ryestrict("[ReceivedTime] >= '" + lastWeekDateTime + "'")
#name = str(message)
message.SaveAs(msg+".msg")
Try setting your filter like the following
Example
import re
import win32com.client
import datetime as dt
import os
Outlook = win32com.client.Dispatch("Outlook.Application")
olNs = Outlook.GetNamespace("MAPI")
Inbox = olNs.GetDefaultFolder(6)
lastWeekDateTime = dt.datetime.now() - dt.timedelta(days=1)
lastWeekDateTime = lastWeekDateTime.strftime('%m/%d/%Y %H:%M %p')
print(lastWeekDateTime)
Filter = ("#SQL=" + chr(34) + "urn:schemas:httpmail:datereceived" +
chr(34) + " >= '" + lastWeekDateTime + "'")
Items = Inbox.Items.Restrict(Filter)
Items.Sort('[ReceivedTime]', False)
for Item in Items:
print(Item.Subject)
print(Item.ReceivedTime)
save_name = re.sub('[^A-Za-z0-9]+', '', str(Item.Subject)) + '.msg'
Item.SaveAs(os.getcwd() + '//' + save_name)
else:
print("No Item")
Firstly, it is Restrict, not Ryestrict.
Secondly, Restrict returns Items collection, not a single item. You need to iterate over the items in that collection. If you only expect a single item, use Find instead of Restrict.

How to print email body from outlook without signature - Python

I'm trying to parse emails from Outlook.
I would like the following printed:
subject
body (excluding sender's signature)
Ignore all previous emails from conversion (reply & forward)
Is there any way I can print out the body text before multi-space between lines (usually this is how signature being separated from the main text)?
Any help would be appreciated!
import win32com.client
#other libraries to be used in this script
import os
from datetime import datetime, timedelta
outlook = win32com.client.Dispatch('outlook.application')
mapi = outlook.GetNamespace("MAPI")
for account in mapi.Accounts:
print(account.DeliveryStore.DisplayName)
inbox = mapi.GetDefaultFolder(6)
messages = inbox.Items
messages.Sort('[ReceivedTime]', True)
received_dt = datetime.now() - timedelta(days=1)
received_dt = received_dt.strftime('%m/%d/%Y %H:%M %p')
messages = messages.Restrict("[ReceivedTime] >= '" + received_dt + "'")
messages = messages.Restrict("[SenderEmailAddress] = 'firstname.lastname#gmail.com'")
message = messages.GetFirst()
print ("Current date/time: "+ received_dt)
while message:
print(message.Subject)
print(message.body)
message = messages.GetNext ()
You can use a regex to ignore everything after three newlines (there are normally one or two newlines between paragraphs):
import re
r = re.compile(r"(.*)\n\n\n", re.MULTILINE + re.DOTALL)
# ...
while message:
# ...
match = r.match(message.body)
if match:
body_without_signature = r.match(message.body).groups(0)
else:
# No signature found
body_without_signature = message.body
print(body_without_signature)

How To save all the attachments from the mail in the outlook without specifying the attachment name

I am new to python. I am trying to save all the attachment from the email without specifying the attachment name from the outlook.
We need to download the attachment with the subject name.
because attachment can come in any name and also i need to download the attachment only for past 2 days.
Could anyone help me. Below is my code
from win32com.client import Dispatch
import time
import datetime
import re
outlook = Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder("6")
all_inbox = inbox.Items
val_date = datetime.date.today()
sub_today = 'test4'
att_today = '20201018_2.xlsx'
#att_today = re.match(regex_, )
for msg in all_inbox:
if msg.Subject.find(sub_today) != -1 and msg.SentOn.date() == val_date:
break
for att in msg.Attachments:
if att.FileName == att_today:
print(att_today)
break
try:
print(att.FileName)
#att.SaveAsFile("C:/Users/Shwettha/Downloads/attachment/"+ att.FileName)
att.SaveAsFile(os.path.join("D:\Script\Monitoring",att.FileName))
print("SUCCESSFUL","Attachments Downloaded")
except:
print("ERROR","Attachment Download Failed")

How to read the email from the different account in the outlook

In my outlook, I have 2 accounts(account 1 and account 2). Account 1 is the default account.
I am trying to read the email from the account 2 from the python code. I tried different approach, but it did not work.
Am posting a my code where it reads from my default account. Could you please help me to read the emails from the account 2(which is not default)
from win32com.client import Dispatch
import time
import datetime
import re
outlook = Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder("6")
all_inbox = inbox.Items
val_date = datetime.date.today()
sub_today = 'test4'
att_today = '20201018_2.xlsx'
#att_today = re.match(regex_, )
for msg in all_inbox:
if msg.Subject.find(sub_today) != -1 and msg.SentOn.date() == val_date:
break
for att in msg.Attachments:
if att.FileName == att_today:
print(att_today)
break
try:
print(att.FileName)
#att.SaveAsFile("C:/Users/Shwettha/Downloads/attachment/"+ att.FileName)
att.SaveAsFile(os.path.join("D:\Script\Monitoring",att.FileName))
print("SUCCESSFUL","Attachments Downloaded")
except:
print("ERROR","Attachment Download Failed")
Try setting your inbox like the following
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.Folders["0m3r#Email.com"].Folders["Inbox"]
Or use GetSharedDefaultFolder method (Outlook)
import win32com.client
Outlook = win32com.client.Dispatch("Outlook.Application")
olNs = Outlook.GetNamespace("MAPI")
Recip = olNs.CreateRecipient("0m3r#Email.com")
Recip.Resolve()
shared_inbox = olNs.GetSharedDefaultFolder(Recip, "6")
for Item in shared_inbox.Items:
print(Item.Subject)

Python code could not run in task scheduler

I wrote a python code to download email attachments and this code works fine when I start it manually (just double click/open with python).
However, when I tried setting up a task in task scheduler, the job keeps running forever and no output is seen (no attachments in the output folder). What have I done wrong here?
I tried all combination of scheduler settings I could think of (run only when user is logged on/ run whether or not user is logged on; run with highest privileges)
I also tried defining actions in different ways:
-script: C:\Windows\System32\cmd.exe
-argument: "C:\ProgramData\Anaconda3\python.exe "C:\Users\LN\Documents\PythonScripts\outlookdownload.py""
-script: C:\ProgramData\Anaconda3\python.exe
-argument: "C:\Users\LN\Documents\PythonScripts\outlookdownload.py"
-script: C:\ProgramData\Anaconda3\python.exe
-argument: "C:\Users\LN\Documents\PythonScripts\outlookdownload.py"
-start in: C:\Users\LN\Documents\PythonScripts\
-script: C:\ProgramData\Anaconda3\python.exe
-argument: "C:\Users\LN\Documents\PythonScripts\outlookdownload.py"
-start in: C:\Users\LN\Documents\PythonScripts\"
Below is the python code:
outpfolder= [output folder link]
import datetime
import win32com.client
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.Folders('Elo Inventory').Folders('Inbox')
messages = inbox.Items
message = messages.GetLast()
sentdate = message.senton.date()
datelimit = (datetime.date.today () - datetime.timedelta (days=7))
#define function to save attachment:
def OL_Attsave(outpath, name, filenamefilter):
attachments = message.Attachments
att_count = attachments.Count
for i in range(1,att_count+1):
attachment = attachments.Item(i)
if filenamefilter in attachment.FileName and "image" not in attachment.FileName:
attachment.SaveASFile(outpath + str(sentdate)+"_"+name+"_" +str(attachment.Filename))
return "saved " + str(att_count) + " files for " + name +" to " + outpath
while sentdate>datelimit:
try:
#Company1:
if message.SenderEmailAddress == "abc#company1.com" and message.subject == "INV ELO":
outpath = outpfolder + "company1\\"
name = 'company1'
OL_Attsave(outpath, name ,'')
#Company2:
elif "#company2.com" in message.SenderEmailAddress:
outpath = outpfolder + "company2\\"
name = 'company2'
OL_Attsave(outpath, name, 'INV')
message = messages.GetPrevious()
sentdate = message.senton.date()
except:
message = messages.GetPrevious()
sentdate = message.senton.date()

Categories

Resources