How to check if an email is part of a conversation? - python-3.x

Our company has a Customer Service (CS) process where after a client reports an error with our software, we'll get an email about their complain with generic subject ("User Submitted Error") and short description of the error. We then fix the problem and email back to client. An issue may have 1, or multiple emails back and forth between our CS department and client.
My python scrip used win32com module to pull emails from Outlook and put them into dataframe, each row as an entry for a unique reported error. After reading (https://learn.microsoft.com/en-us/office/vba/api/outlook.mailitem.conversationid), I decided to go with message.ConversationID. However, the generic email subject means sometimes they would group all unrelated emails together, make ConversationID not really that unique nor useful to me.
Can someone provide me some guide on how best to tackle this issue?
outlook = win32com.client.Dispatch('Outlook.Application').GetNamespace('MAPI')
def message_to_row(message, year, start_month, end_month): # Process each email into row of information
message_time = message.ReceivedTime
winrec_time = message.ReceivedTime
rec_time = pywintypes.Time(winrec_time)
rec_year = rec_time.year
rec_month = rec_time.month
rec_day = rec_time.day
rec_time_string = str(rec_time.hour) + ":" + str(rec_time.minute)
rec_time = format(datetime.datetime.strptime(rec_time_string, "%H:%M"), "%H:%M")
if rec_year >= year:
if rec_month in range(start_month, end_month):
convo_id = message.ConversationID
message_body = message.body.replace("_", " ")
row = [convo_id, rec_year, rec_month,
rec_day, rec_time, message_body]
return row

Related

AttributeError: 'ChatForbidden' object has no attribute 'access_hash'

I have made a telegram member scraper and inviter with Python. It was successful on some tests, but there are times my accounts get banned with upon seeing this error message:
AttributeError: 'ChatForbidden' object has no attribute 'access_hash'
I'm not sure why would it show ChatForbidden if I am already an admin of a group. It's hard to test these as I had to buy new phone numbers every time.
Here's a sample and explanation of my code to invite members to a group:
# Log in into the telegram account
client = TelegramClient('Tg_scraper', api_id, api_hash)
chats = []
last_date = None
chunk_size = 200
groups = []
hash_list = []
# Get all the groups/channel of the account
result = client(GetDialogsRequest(
offset_date=last_date,
offset_id=0,
offset_peer=InputPeerEmpty(),
limit=chunk_size,
hash=0
))
chats.extend(result.chats)
# Puts all the group/channel into a list
i = 0
print('Enter a NUMBER to choose a group where the members will be invited into:')
for chat in chats:
try:
groups.append(chat)
hash_list.append(chat.access_hash)
print(f"({i})" + ' - ' + chat.title)
i += 1
except:
continue
g_index = input("Enter a Number: ")
target_group = groups[int(g_index)]
target_group_entity = InputPeerChannel(target_group.id, target_group.access_hash)
Upon the last line, target_group_entity = InputPeerChannel(target_group.id, target_group.access_hash) is where I encounter the error I have stated above. Upon receiving that error, I get banned.
Does this have something to do with permissions? Do new accounts get banned for botting? It works on my first few tests, but then now I can't invite. Thank you so much for anyone who could help in advance.
I am already an admin of a group
This error is unrelated to your permission level.
Upon the last line is where I encounter the error
Wrong. you encounter this error because you're not coding it right with types in mind, expecting all your .chats are groups. Telegram doesn't tell you what fields exactly have, as you see in this error.
You must use type checking to limit your chats objects to only what you expect, your try block is appending then erroring, so, rather than a plain:
except:
continue
you need to actually confirm it won't error when accessing fields.
print('Enter a NUMBER to choose a group where the members will be invited into:')
i = 0
for chat in chats:
if isinstance(chat, telethon.types.Channel):
if chat.broadcast: continue # ignore non-group
groups.append(chat)
hash_list.append(chat.access_hash)
print(f"({i})" + ' - ' + chat.title)
i += 1
g_index = input("Enter a Number: ")
target_group = groups[int(g_index)]

Get only information of the last mail of the contact from Imapclient

So I am a beginner in Python and coding and trying to build up a code that will give information about the last email received from a contact. Right now what I have gives the output of all the email received from the contact. I just want it to print the last email.
Any suggestions on how to go about it?
import email
from imapclient import IMAPClient
HOST = 'imap.gmail.com'
USERNAME = 'username'
PASSWORD = 'password'
ssl = True
## Connect, login and select the INBOX
server = IMAPClient(HOST, use_uid=True, ssl=ssl)
server.login(USERNAME, PASSWORD)
select_info = server.select_folder('INBOX')
messages = server.search(['FROM', 'email_of_the_contact#gmail.com'])
response = server.fetch(messages, ['RFC822'])
for msgid, data in response.items():
msg_string = data[b'RFC822']
msg = email.message_from_string(msg_string.decode())
print('ID %d: From: %s Date: %s' % (msgid, msg['From'], msg['date']))
The answer depends on the actual structure of the 'response' object, which isn't entirely clear, but you could try the following instead of the for loop you've tried:
last_msg_id = list(response.keys())[-1]
data = response[last_msg_id]
msg_string = data[b'RFC822']
msg = email.message_from_string(msg_string.decode())
print('ID %d: From: %s Date: %s' % (last_msg_id , msg['From'], msg['date']))
Basically, instead of looping over all of the message ids and all of the data, we've taken the full list of message ids ('response.keys()') and just pulled the last entry in that list, and used that to pull in the rest of the email detail.

Sending Email with Python using Outlook desktop application - clipboard as the input for email address

I am trying to send the following email automated with Python but i keep get an error. I would like to run the script and then for it to ask me for input on which email address to send it to. But I keep getting an error. If I put an actual email address in the Msg.To section it works but I was hoping that every time I run this script it would ask me which email address to send to (originally I was trying to have it simply use whats on my clipboard as the input but that seemed too complicated so I relegated to input prompt instead).
Here is my code:
emailrecepient = input("enter email address")
import win32com.client
o = win32com.client.Dispatch("Outlook.Application")
Msg = o.CreateItem(0)
Msg.Importance = 2
Msg.Subject = 'SUBJECT'
Msg.HTMLBody = """<p>Hello,<br>"""
Msg.To = "sender"
Msg.Send()

check availability of meeting rooms in outlook with python

I am working on to write a python script to check if particular meeting room is available. If yes then meeting room will be booked, if not then python will find available time slot for that day.
For now, I have achieved to book meeting room but I am not able to check availability of rooms.
To book any meeting room, i have to send mail to that book meeting room configured mail id and corresponding acceptance/decline mail I receive as per the availability.
below is the snippet :
import win32com.client
import datetime
import pywintypes
oOutlook = win32com.client.Dispatch("Outlook.Application")
appt = oOutlook.CreateItem(1)
appt.Start = '2018-05-18 13:30'
appt.Subject = 'Follow Up Meeting'
appt.Duration = 30
appt.Location = '<name of meeting room>'
appt.MeetingStatus = 1
myRecipient = appt.Recipients.Add("<mail id of meeting room")
myRecipient.resolve
my_date = datetime.date(2018,5,18)
pywintypeDate = pywintypes.Time (my_date)
availabilityInfo = myRecipient.FreeBusy(pywintypeDate,30,True)
print(availabilityInfo)
# appt.Save()
# appt.Send()
# print("done")
output is :
000000000000000000000222222200222222022000000000000000000000000000000002222222222220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000002220002222200000000000000000000000000000000002220022022222000000000000000000000000000000000000000000002222000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000222222200000000000000000000000000000000002220000022000000000000000000000000000000000000002220000222222000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000002220022022200000000000000000000000000000000000022000022000000000000000000000000000000000000000000000002222000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000022022200000000000000000000000000000000002220002222000000000000000
so is it first byte (0) indicate time slot from 00:00 to 00:30 and soon for one complete month ?
Is it possible to get output only for one day ?
Do i have to parse the above output to check availability for my particular required time ?
appt.Recipients.Add returns the Recipient object. Resolve it first (Recipient.Resolve), then call Recipient.FreeBusy.

Recursively getting body of email with Pyzmail module

I'm trying to create an app that needs to recursively check an email address for new emails and then do some other stuff; I'm having some problems with the getting the body of the emails, though. I'm using the pyzmail module alongside imapclient, and the Automate the Boring Stuff for guidance (with python 3.6). Here's my code:
mail = imapclient.IMAPClient('imap.gmail.com', ssl=True)
mail.login('email', 'password')
mail.select_folder('INBOX', readonly=False)
uid = mail.gmail_search('NC')
for i in uid:
message = mail.fetch(i, ['BODY[]'], 'FLAGS')
msg = pyzmail.PyzMessage.factory(message[i][b'BODY[]'])
msg.html_part.get_payload().decode(msg.text_part.charset)
But it's not working. I've basically tried different forms of this code but to no avail and there's really not that many examples that can help me along. I'm a bit of a python newbie. Can anybody help?
Thanks,
EDIT
I realized where I made a mistake and fixed a bit of the code:
server = imapclient.IMAPClient('imap.gmail.com', ssl=True)
server.login('p.imagery.serv#gmail.com', 'rabbitrun88ve')
server.select_folder('INBOX', readonly=True)
uids = server.gmail_search('NC')
for i in uids:
messages = server.fetch(i, ['BODY[]'])
msg = pyzmail.PyzMessage.factory(messages[b'BODY[]'])
The problem I'm having is with the last line, which I dont know how to fed using the variables that is created with the iterator. It throws out this message:
ValueError: input must be a string a bytes, a file or a Message
I'm not sure if you still have this problem but for those who might have similar issues in future.
I noticed a little omission in the last line which might be the culprit.
msg = pyzmail.PyzMessage.factory(messages[b'BODY[]'])
You omitted the 'i' variable of the for loop
msg = pyzmail.PyzMessage.factory(messages[i][b'BODY[]'])
I'd like to do next to get body text of searched messages:
server = imapclient.IMAPClient('imap.gmail.com', ssl=True)
server.login('p.imagery.serv#gmail.com', 'rabbitrun88ve')
server.select_folder('INBOX', readonly=True)
uids = server.gmail_search('NC')
rawmessage = server.fetch(uids, ['BODY[]'])
for i in rawmessage:
msg = pyzmail.PyzMessage.factory(rawmessage[i][b'BODY[]'])
msg.html_part.get_payload().decode(msg.text_part.charset)
In this case, you get iteration over fetched emails with body text. I checked similar example but I used text_part.get_payload() instead html regarding features of my server.

Resources