Replying To email via Outlook in Python - python

I am trying to reply to emails with a keyword in the subject but I need to do it all through outlook. My current code works decently but it would be better if it could reply directly instead of creating a new message.
Hopefully this is the right place to ask this :)
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
o = win32com.client.Dispatch("Outlook.Application")
inbox = outlook.GetDefaultFolder(6)
def check_mail():
global message
messages = inbox.Items
message = messages.GetLast()
if (message.subject.find('#Bot') != -1 and message.unread and whtlist.find(message.SenderName)!= -1 ):
return 1
else:
return 0
def Read_mail():
global message
global ACTIVE
body_content = message.body
print(bcolors.WARNING+'\n______________________________________________________________________\n'+bcolors.OKGREEN)
print (body_content)
print(bcolors.WARNING+'\n______________________________________________________________________\n'+bcolors.OKGREEN)
for att in message.Attachments:
break
try:
att.SaveAsFile(os.getcwd() + '\\new.xlsx')
print(os.getcwd())
except :
print(bcolors.WARNING+'No Attachment Found'+bcolors.OKGREEN)
message.unread=False
Msg = o.CreateItem(0)
Msg.To = message.SenderEmailAddress
print(bcolors.FAIL+'Reply sent to: {}'.format(message.SenderEmailAddress+bcolors.OKGREEN))
Msg.Subject = 'Autoreply'
Msg.Body = 'I see you {}.\n\nTesting\n-Bot'.format(message.SenderName)
Msg.Send()

Do not use Items.GetLast - it is not guaranteed to return the last received email. The Items collection is not sorted in any particular way unless you explicitly call Items.Sort. In your particular case, use Items.Restrict or Items.Find/FindNext to find the message based on your criteria (unread, subject contains a particular word, etc.).
To get a reply, call MailItem.Reply instead of Application.CreateItem - it will return the new MailItem object.

Related

Gmail API: Search for an existing thread with the subject line and if it exists reply to the thread, otherwise send a fresh email in python

I am trying to use gmail api to reply to existing thread (if it exists) or otherwise start a new email thread.
Here is what I found:
x = gmailClient.service.users().threads().list(userId='me',q='from:noreply-dv360#google.com subject:"Report #234354 : "Reporting" from Sneha"').execute().get('threads', [])
but this returns me a list of array which look like this:
{'id': '177ed7354840ddae1', 'snippet': '-- <b>Report</b> Name: <b>Reporting</b> Account: DBM (21324356) <b>Report</b> ID: <b>34565</b> File Name: Reporting_1234354', 'historyId': '232456'}
I want to reply to the given thread... So here's my two major questions:
How to fetch the thread Id of a thread by it's subject line?
How to reply to a thread by it's thread id?
Edit 1:
def send_email(self,sender, to, subject, message_text, cc = None,messageType = "plain"):
queryParam = f'from: me subject: "{subject}"'
message = MIMEText(message_text,messageType)
message['to'] = to
message['from'] = sender
message['subject'] = subject
if cc != None:
message['cc'] = cc
emailBody = {'raw': base64.urlsafe_b64encode(bytes(message.as_string(),"utf-8")).decode("utf-8")}
threadSearch = self.service.users().threads().list(userId='me',q=queryParam, maxResults = 1).execute().get('threads', [])
if len(threadSearch):
threadSearch = threadSearch[0]
emailBody["threadId"] = threadSearch["id"]
messageId = self.getMessageIdFromThread(threadSearch)
emailBody['subject'] = subject
emailBody["Reference"] = messageId
emailBody["In-Reply-To"] = messageId
print("Response: ")
response = self.service.users().messages().send(userId = 'me', body = emailBody).execute()
else:
response = self.service.users().messages().send(userId = 'me', body = emailBody).execute()
return response
def getMessageIdFromThread(self, thread):
tdata = self.service.users().threads().get(userId="me", id=thread['id']).execute()
msg = tdata['messages'][0]['payload']
for eachMsg in msg['headers']:
if eachMsg['name'] == "Message-Id":
return eachMsg["value"]
return False
Here are the changes I did... Now This is what I get:
From Sender Side:
At Receiver End:
For some reason, the threading doesn't happen to the reciever end. Can someone guide me where exactly am I going wrong?

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")

Python Outlook inbox saving attachments win32com.client

I have gotten some of the features I want but need help with 2 others.
I would like to flag the message "Mark as Done" (it's one of the Flag statuses). I have not found how to do this.
If I wanted to do this same thing for 4 other emails how would I do it, with 4 other save paths?
import win32com.client
import os
Outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inboxfolder = Outlook.GetDefaultFolder(6) # "6" refers to the index of a folder - in this case the inbox. You can change that number to reference
inbox = inboxfolder.Items
message = inbox.GetFirst()
subject = message.Subject
sender = message.SenderEmailAddress
for m in inbox:
if m.Class == 43: # this is to make sure it is an email item and not something else.
if m.SenderEmailAddress == 'John#email.com' and m.Unread == True:
path = 'C:\\User\\Path\\Data\\John'
print ('Subject as: ' and message)
for attached in message.Attachments:
attached.SaveASFile(os.path.join(path,attached.FileName)) #Saves attachment to current folder
print (attached)
message.Unread = False
print (message.FlagStatus)
message.FlagStatus = 1 # This is to "mark as Done" but it doesn't work
message = inbox.GetNext()
elif m.SenderEmailAddress == 'Jane#email.com' and m.Unread == True:
path = 'C:\\User\\Path\\Data\\Jane'
# ... How would you add 4 more?
message = inbox.GetNext()
else:
message = inbox.GetNext()
You have to save it message.Save(), Example
import win32com.client
Outlook = win32com.client.Dispatch("Outlook.Application")
olNs = Outlook.GetNamespace("MAPI")
Inbox = olNs.GetDefaultFolder(win32com.client.constants.olFolderInbox)
for Item in Inbox.Items:
if Item.Class == 43:
Item.FlagStatus = 1
Item.Save()
For multiple emails & path use dictionary, Example
emails_with_path = {
"email#one.com": "path_one",
"email#two.com": "path_two",
"email#three.com": "path_three"
}
for m in inbox:
if m.Class == 43:
for email, path in emails_with_path.items():
if m.SenderEmailAddress == email and m.UnRead:
print(email)
print(path)

Printing subjects and sender from email in python

I'm trying to get a python script which looks through my gmail inbox using imap and prints out the subject and sender of any emails which are unseen. I've started but at the moment I don't think it can sort the unseen emails or extract from these the subject and sender.
Does anyone know how to finish this code?
import imaplib
import email
user = "x"
password = "y"
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login(user, password)
mail.list()
mail.select('inbox')
unseen_emails = mail.search(None, 'UnSeen')
print unseen_emails
If you were willing to use poplib, this should work.
import poplib
mymail = []
host = "pop.gmail.com"
mail = poplib.POP3_SSL(host)
print (mail.getwelcome())
print (mail.user("user#gmail.com"))
print (mail.pass_("password"))
print (mail.stat())
print (mail.list())
print ("")
if mail.stat()[1] > 0:
print ("You have new mail.")
else:
print ("No new mail.")
print ("")
numMessages = len(mail.list()[1])
numb=0
for i in range(numMessages):
for j in mail.retr(i+1)[1]:
numb+=1
if numb == 4 or numb == 5:
print(j)
mail.quit()
input("Press any key to continue.")
Just be sure to allow less secure apps in your google account here: https://myaccount.google.com/lesssecureapps
My external lib https://github.com/ikvk/imap_tools
from imap_tools import MailBox, AND
# get list of unseen emails from INBOX folder
with MailBox('imap.mail.com').login('test#mail.com', 'pwd', 'INBOX') as mailbox:
for msg in mailbox.fetch(AND(seen=False)):
msg.subject # str: 'some subject 你 привет'
msg.from_ # str: 'Sender#ya.ru'
NOTE: mailbox.fetch has mark_seen arg!

How do I download only unread attachments from a specific gmail label?

I have a Python script adapted from Downloading MMS emails sent to Gmail using Python
import email, getpass, imaplib, os
detach_dir = '.' # directory where to save attachments (default: current)
user = raw_input("Enter your GMail username:")
pwd = getpass.getpass("Enter your password: ")
# connecting to the gmail imap server
m = imaplib.IMAP4_SSL("imap.gmail.com")
m.login(user,pwd)
m.select("[Gmail]/All Mail") # here you a can choose a mail box like INBOX instead
# use m.list() to get all the mailboxes
resp, items = m.search(None, 'FROM', '"Impact Stats Script"') # you could filter using the IMAP rules here (check http://www.example-code.com/csharp/imap-search-critera.asp)
items = items[0].split() # getting the mails id
for emailid in items:
resp, data = m.fetch(emailid, "(RFC822)") # fetching the mail, "`(RFC822)`" means "get the whole stuff", but you can ask for headers only, etc
email_body = data[0][1] # getting the mail content
mail = email.message_from_string(email_body) # parsing the mail content to get a mail object
#Check if any attachments at all
if mail.get_content_maintype() != 'multipart':
continue
print "["+mail["From"]+"] :" + mail["Subject"]
# we use walk to create a generator so we can iterate on the parts and forget about the recursive headach
for part in mail.walk():
# multipart are just containers, so we skip them
if part.get_content_maintype() == 'multipart':
continue
# is this part an attachment ?
if part.get('Content-Disposition') is None:
continue
filename = part.get_filename()
counter = 1
# if there is no filename, we create one with a counter to avoid duplicates
if not filename:
filename = 'part-%03d%s' % (counter, 'bin')
counter += 1
att_path = os.path.join(detach_dir, filename)
#Check if its already there
if not os.path.isfile(att_path) :
# finally write the stuff
fp = open(att_path, 'wb')
fp.write(part.get_payload(decode=True))
fp.close()
I am filtering messages by subject and getting the attachments, but now I need to only get attachments from new emails. Can I modify the m.search() somehow to return only unread emails?
Try modifying this line:
resp, items = m.search(None, 'FROM', '"Impact Stats Script"')
to:
resp, items = m.search(None, 'UNSEEN', 'FROM', '"Impact Stats Script"')
The Python imaplib documentation shows just adding more search criteria, and the IMAP specification defines the UNSEEN search criteria:
UNSEEN
Messages that do not have the \Seen flag set.

Categories

Resources