update categories in emails using python - python

I am trying to update categories of emails available in one of the data frame using below code.
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6)
messages = inbox.Items
i = 0
for message in messages:
try:
message.Categories = output.iat[i,2]
except:
message.Categories = 'No Category'
i = i + 1
Below script used to move updated emails from inbox to another folder and then remove to inbox
donebox = outlook.GetDefaultFolder(6).Folders[20]
def delay(time):
for j in range(time):
j=j+1
i = 0
while (messages.Count > 0):
print(i,messages.Count)
message = messages.GetLast()
message.Move(donebox)
delay(1000000)
i = i + 1
messages = donebox.Items
i = 0
while (messages.Count > 0):
print(i,messages.Count)
message = messages.GetLast()
message.Move(inbox)
delay(1000000)
i = i + 1
In outlook updated Categories from output dataframe for emails are able visible only once email selected. Is there any option which can refresh outlook and categories will be updated automatically. Please advice.

For everyone who cant save changing of non-selected mail Categories property by Python:
mail.Categories='Red category'
mail.Save()

It worked for me!
import win32com.client
from win32com.client import Dispatch
outlook=win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
folder = outlook.Folders.Item("Inbox")
messages = folder.Items
for i in range(messages.Count):
messages[i].GetInspector()
messages[i].Categories = 'Purple Category'
messages[i].Save()

If only one category needs to be assigned to each email, dmitrii.kotenko has provided the solution.
If you need to append more than one category, pass the categories as a string separated by commas
mail.Categories = "category1, category2, category3"
mail.Save()

Related

Win32com locating time of email after restricting timeframe

I would like to capture the date/time when a message was sent so that I can store the info in dataframe. I have connected to my inbox and can extract the email and I have restricted the time so that I can only get emails from the last 7 days.
Here's my code:
import win32com.client as wc
import pandas as pd
import datetime as dt
last_week = dt.date.today()- dt.timedelta(days = 7)
last_week = last_week.strftime('%m/%d/%Y %H:%M %p')
#Search through my inbox
outlook = wc.Dispatch("Outlook.Application")
mapi = outlook.GetNamespace("MAPI")
root_folder = mapi.Folders['username'].Folders['Inbox'].Folders['folder']
print(root_folder.Name)
#restrict inbox to 7 days
messages = root_folder.Items
messages = messages.Restrict("[ReceivedTime] >= '" + last_week + "'")
messages.Sort("[ReceivedTime]", True)
#grab message and convert to pandas DF. Expected 7 messages
counter = 0
for message in messages:
if message.Subject == 'Message_1':
print(counter, message.Subject)
print(messages.SentOn) ### I Get my Attributes Error here :(
html_str = message.HTMLBody
get_table = pd.read_html(html_str)[0]
counter += 1
When I added the SentOn Method I am getting an AttributeError saying "Restrict.SentOn" I am assuming that this is because I have restricted my time period.
How do I get the actual date/time of the individual message?
I needed to use the individual object as the item to get the .SentOn info from

Unable to send 2 pywin32 emails within one program runtime

So I have the ability to open outlook and insert all the needed values to create a draft of an email, however, when I reopen the window and attempt to send another email it gives met this error.
self.mailItem = olApp.CreateItem(0)
File "<COMObject Outlook.Application>", line 2, in CreateItem
pywintypes.com_error: (-2147023174, 'The RPC server is unavailable.', None, None)
Is it the way I call it or is it the way this pywin32 works, how would I go about resolving this issue to the point where i can send as much emails, using the same code? Replacing self.mailItem.Display() with self.mailItem.Send(), allows me to send the multiple I desire however I want the user to edit any composed email before sending it. thus this not being a option.
my email class
import win32com.client as win32
from PyQt5.QtWidgets import QMessageBox
olApp = win32.Dispatch('Outlook.Application')
olNS = olApp.GetNameSpace('MAPI')
class emailComposition():
def __init__(self):
self.mailItem = olApp.CreateItem(0)
self.mailItem.BodyFormat = 1
self.mailItem.Sensitivity = 2
attachment = self.mailItem.Attachments.Add("C:\\Users\\----\Desktop\\Krypt\\Images\\Logos\\Logo1.png")
attachment.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001F", "MyId1")
def setSubject(self, subj):
self.mailItem.Subject = subj
def setSender(self, senderEmail):
self.sender = senderEmail
def setRecipient(self, recipientEmail, recipientName):
self.mailItem.To = recipientEmail
self.rName = recipientName
def setText(self, ItemList):
items = "<br>• xyz <br>• xyz"
# still need to do something with the ItemList, removing it has no effect on the error outcome!
self.mailItem.HTMLBody = "<p>Good Day " + self.rName + " <br>Could you please send me a quote on the following: " + items + " </p> <p>Thanks</p><img src=""cid:MyId1"" width=""100"" height=""100"" >"
def displayEmail(self):
try:
self.mailItem._oleobj_.Invoke(*(64209, 0, 8, 0, olNS.Accounts.Item(self.sender)))
except:
msg = QMessageBox()
msg.setIcon(QMessageBox.Warning)
msg.setText("Unregistered email")
msg.setInformativeText("""The email provided isn't a registered email within outlook.\nA default email will be used.""")
msg.setWindowTitle("Krypt")
msg.exec_()
self.mailItem.Display()
Code i use to call this class, all of it is in a button press connect
def createEmail(self):
input = self.ui.tblQuoteItems.item(0, 0)
if input is not None:
if self.ui.edtSupplier.text() != "" and self.ui.edtSupplierRep.text() != "":
x = emailComposition()
x.setRecipient(self.ui.edtSupplierEmail.text(), self.ui.edtSupplierRep.text())
x.setSubject("Official Quote")
x.setSender(self.ui.edtUserEmail.text())
self.read() #Loads self.itemList with needed items
x.setText(self.itemList)
x.displayEmail()
Try to get a Namespace and any standard folder reference after creating a new Outlook Application instance in the code:
import win32com.client as win32
olApp = win32.Dispatch('Outlook.Application')
olNS = olApp.GetNameSpace('MAPI')
objFolder = objNS.GetDefaultFolder(olFolderInbox)
Read more about that in the Automating Outlook from a Visual Basic Applications article.
Also you may find the Application Shutdown Changes in Outlook article helpful.

gmail api: get latest 2 emails from thread

The code below retrieves the latest email in the thread. How do I retrieve the latest 2 emails in the thread? Thanks in advance.
messages = service.users().threads().list(userId='me').execute().get('threads', [])
for message in messages:
if search in message['snippet']:
# add/modify the following lines:
thread = service.users().threads().get(userId='me', id=message['id'], fields='messages(id,internalDate)').execute() #.get( [])
last = len(thread['messages']) - 1
message_id = thread['messages'][last]['id']
# non-modified code:
full_message = service.users().messages().get(userId='me', id=message_id, format="raw").execute()
msg_str = base64.urlsafe_b64decode(full_message['raw'].encode('ASCII'))
mime_msg = email.message_from_bytes(msg_str)
y = re.findall(r'Delivered-To: (\S+)', str(mime_msg))
print(y[0])
The line last = len(thread['messages']) - 1 specifies that you want to retrieve the last message from a thread
Consequently, to retrieve the prelast message, you need to specify prelast = len(thread['messages']) - 2
And respectively prelast_message_id = thread['messages'][prelast]['id']
Now, you can push both last and prelast message Ids into an array and perform your # non-modified code in a for loop on both message ids.

Writing email reply bot using poplib and random emails keep showing up in me re.findall(...) call

I'm using poplib to connect to a gmail account and I want it to reply to emails that are sent to it.
However sometimes my regular expression's statement grabs random emails that aren't the one I wanted to reply to.
For example:
5952f967.8543630a.1c70d.283f#mx.google.com
Code below:
def checkEmail():
mail = poplib.POP3_SSL('pop.gmail.com')
mail.user(USER)
mail.pass_(PASS)
numEmails = len(mail.list()[1])
count = 0
if(numEmails>=1):
for i in range(numEmails):
for msg in mail.retr(i+1)[1]:
sender = re.findall(r'[\w\.-]+#[\w\.-]+',msg)
for s in sender:
if s and count == 0:
count += 1
replySender(s)
print s
message = email.message_from_string(msg)
count = 0
mail.quit()

Python - Outlook Response (Accept, Reject, etc.) Date/Time

I am working on a project that involves pulling a lot of appointment/meeting data from Outlook from multiple people. One piece of information that I am trying to find is the response for each attendee and, if possible, the date and time that the response happened. For example, if Person X sends me a meeting request on 4/21/2015 12:31:00 PM and I accepted the meeting request at 4/21/2015 1:30:00 PM, how would I get the latter of those two times? I have been browsing the Microsoft docs for this (Link) but have had no luck so far.
Here is a quick summary in Python:
import win32com.client
outlook = win32com.client.Dispatch('Outlook.Application')
namespace = outlook.GetNamespace('MAPI')
recipient = namespace.createRecipient('Other Person')
resolved = recipient.Resolve()
sharedCalendar = namespace.GetSharedDefaultFolder(recipient, 9)
appointments = sharedCalendar.Items
for i in range(0,1):
print appointments[i]
print appointments[i].start
print appointments[i].end
print appointments[i].organizer
print appointments[i].location
print appointments[i].duration
for j in range(0,len(appointments[i].recipients)):
print 'recip, status: ' + str(appointments[i].recipients[j]) + ', ' + str(appointments[i].recipients[j].TrackingStatusTime)
AppointmentItem.ReplyTime and AppointmentItem.ResponseStatus
here is another way
import win32com.client
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6)
messages = inbox.Items
messages.Sort("[ReceivedTime]", True)
for i, msg in enumerate(messages):
print(msg.MessageClass) # use this in condition
if msg.MessageClass=='IPM.Note':
print('This a Meeting')
elif msg.MessageClass =='IPM.Schedule.Meeting.Request':
print('This is a meeting Meeting')
elif msg.MessageClass =='IPM.Schedule.Meeting.Resp.Pos':
print('Accepted Response , POS = Positive')
elif msg.MessageClass =='IPM.Schedule.Meeting.Resp.Tent':
print('Accepted as Tentative ')
elif msg.MessageClass == 'IPM.Schedule.Meeting.Resp.Neg':
print('Declined Meeting , Neg = Negative')
# Check only first 10 items, change the number as per requirement
if i > 10:
break
https://learn.microsoft.com/en-us/office/vba/outlook/Concepts/Forms/item-types-and-message-classes

Categories