I'm trying to read my GMail messages using the API provided by Google using Python 3.4.
I'm using this function that is provided by Google at this link:
def GetMimeMessage(service, user_id, msg_id):
try:
message = service.users().messages().get(userId=user_id, id=msg_id,
format='raw').execute()
print 'Message snippet: %s' % message['snippet']
msg_str = base64.urlsafe_b64decode(message['raw'].encode('ASCII'))
mime_msg = email.message_from_string(msg_str)
return mime_msg
except errors.HttpError, error:
print 'An error occurred: %s' % error
However if I use this function as it is I get the following error:
TypeError: initial_value must be str or None, not bytes
So I changed the function a bit:
def GetMimeMessage(service, user_id, msg_id):
try:
message = service.users().messages().get(userId=user_id, id=msg_id,
format='raw').execute()
#print ('Message snippet: %s' % message['snippet'])
msg_str = base64.urlsafe_b64decode(message['raw'].encode('utf-8','ignore'))
print(msg_str)
mime_msg = email.message_from_string(msg_str.decode('utf-8','ignore'))
return mime_msg
except errors.HttpError:
print('An error occurred')
If I don't add the 'ignore' argument I get the following error:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xeb in position
2214: invalid continuation byte
If I use the 'ignore' argument then the content of the mail, for example a HTML text, has some weird characters into it, for example:
=09=09body=2C#bodyTable=2C#bodyCell{
=09=09=09height:100% !important;
=09=09=09margin:0;
=09=09=09padding:0;
=09=09=09width:100% !important;
=09=09}
My problem seems very similar to this one but, given that I'm not a Python expert and I need to use the GMail API, I cannot see how to fix it.
Any idea?
It appears that the mail contents are in quote-print codification.
You can use the quopri module to handle it https://docs.python.org/2/library/quopri.html
As Arkanus suggested the problem was related to the quote-printable codification.
Instead of using quopri I used the decode argument implementing a code that is similar to this one.
The first error was caused by the fact that I'm using Python 3.4. I'm not sure about the reason but using Python 2.7 it works fine.
Related
I am trying to save only a specific part of an email using python. I have the variables service, userId and msg_id but I don't know how to convert the variable plainText to a string in order to take the part that I want in the get_info function
def get_message(service, user_id, msg_id):
try:
#get the message in raw format
message = service.users().messages().get(userId=user_id, id=msg_id, format='raw').execute()
#encode the message in ASCII format
msg_str = base64.urlsafe_b64decode(message['raw'].encode("ASCII")).decode("ASCII")
#put it in an email object
mime_msg = email.message_from_string(msg_str)
#get the plain and html text from the payload
plainText, htmlText = mime_msg.get_payload()
print(get_info(plainText, "start", "finish"))
except Exception as error:
print('An error occurred in the get_message function: %s' % error)
def get_info(plainText, start, end):
usefullText = plainText.split(start)[2]
usefullText = usefullText.split(end)[0]
return usefullText
after running the code I have the following error message:
An error occurred in the get_message function: 'Message' object has no attribute 'split'
Answer:
The method get_payload() doesn't exist for the email.message class. You need to use as_string() instead.
Code Fix:
The code inside your try block needs to be updated, from:
#get the plain and html text from the payload
plainText, htmlText = mime_msg.get_payload()
to:
#get the plain and html text from the payload
plainText, htmlText = mime_msg.as_string()
References:
email.message: Representing an email message — Python 3.8.5 documentation
as_string() method
email.parser: Parsing email messages — Python 3.8.5 documentation
message_from_string() method
I am trying to avoid a telegram error. This error occurs when a message is not modified:
telegram.error.BadRequest: Message is not modified
I would like to make a function to print a message when this error occurs instead the original error message telegram prints. I have tried something like this but does not work:
def error_callback(bot, update, error):
try:
raise error
except BadRequest:
# handle malformed requests - read more below!
print('Same message')
First of all, if there are no evident bugs, this error could be happen if a user if clicking too fast on a button. In this case it can be easily ignored.
Assuming you are using python-telegram-bot library looking at your code, you can follow 2 approaches:
1. Ignore the error globally:
def error(bot, update, error):
if not (error.message == "Message is not modified"):
logger.warning('Update "%s" caused error "%s"' % (update, error))
but you will still receive on the console:
2017-11-03 17:16:41,405 - telegram.ext.dispatcher - WARNING - A TelegramError was raised while processing the Update
the only thing you can do is to disable that string for any error of any type doing this:
updater.dispatcher.logger.addFilter((lambda s: not s.msg.endswith('A TelegramError was raised while processing the Update')))
in your main(). credits
2. Ignore the error in the method you are calling:
You can ignore the error in the method you are calling doing:
try:
# the method causing the error
except TelegramError as e:
if str(e) != "Message is not modified": print(e)
This second approach will ignore the error completely on the console without modifying the error callback function, but you have to use it in every single method causing that exception.
Printing 'text' instead of ignoring:
i suggest you to ignore the error, but if you want to print a string as you said: you can very easily modify those 2 approaches to print the string.
Example for the first approach:
def error(bot, update, error):
if error.message == "Message is not modified":
# print your string
return
logger.warning('Update "%s" caused error "%s"' % (update, error))
Example of the second approach:
try:
# the method causing the error
except TelegramError as e:
if str(e) == "Message is not modified": print(your_string)
I have this bit of code below, it is part of a python script iv been working on(piecing it together blocks at a time as learning curve). This bit binds to an ldap directory to query, so the rest of the script can to the queries.
When successful, it will print the below message in the block. When not successful it will throw an error- or at least i want to control the error.
If im not domain bound/vpn it will throw this message:
{'desc': "Can't contact LDAP server"}
if incorrect credentials :
Invalid credentials
nowhere in my script is it defined for the error message, how can i find where its fetching what to print that messsage- and possibly create or customize it?
(for what its worth i am using PyCharm)
try:
l = ldap.open(server)
l.simple_bind_s(user, pwd)
#if connection is successful print:
print "successfully bound to %s.\n" %server
l.protocol_version = ldap.VERSION3
except ldap.LDAPError, e:
print e
thanks
you can do something like this to provide a specific message for a specific exception.
try:
foo = 'hi'
bar = 'hello'
#do stuff
except ValueError:
raise ValueError("invalid credientials: {},{}".format(foo, bar))
so in your example it could become
except ldap.LDAPError:
raise ldap.LDAPError("invalid credientials: {},{}".format(user, pwd))
or if you literally just want to print it
except ldap.LDAPError:
print("invalid credientials: {},{}".format(user, pwd))
I'm currently need to know how to extract a link from html mail in Gmail account.
I able to connect using the python library for gmail provided by google but once i use the fonction describe as example:
def GetMimeMessage(service, user_id, msg_id):
"""Get a Message and use it to create a MIME Message.
Args:
service: Authorized Gmail API service instance.
user_id: User's email address. The special value "me"
can be used to indicate the authenticated user.
msg_id: The ID of the Message required.
Returns:
A MIME Message, consisting of data from Message.
"""
try:
message = service.users().messages().get(userId=user_id, id=msg_id,
format='raw').execute()
print ('Message snippet: %s' % message['snippet'])
msg_str = base64.urlsafe_b64decode(message['raw'].encode('ASCII'))
mime_msg = email.message_from_string(msg_str)
return mime_msg
except errors.HttpError, error:
print ('An error occurred: %s') % error
message = GetMimeMessage(service, 'me', '15876d11f0719f43')
#message = GetMessage(service, 'me', '15876d11f0719f43')
#message = str(message)
print (message)
The message looks like this:
style=3D"font-family: Verdana, Geneva, sans-serif; font-siz=
e: 14px; line-height: 20px;"><a href=3D"https://e.vidaxl.com/1/4/1505/1/ZJb=
bJSDLWNxmfpHYIRQzlMiIupCb0wiKMrAxIrfXlymZQ_TK5GUcGAT6rIBJD9nfIFJ5XWG6HnYei-=
G1aQqlfnBxKnJ3yujKlOpRY2UxqroSHS51ofyXzr3kFa7OTyJH5zKbxESXzbTlcQOYxRuEnBcKF=
saVBGQXyJomUGLL6RY" target=3D"_blank" style=3D"color:blue;">SUIVEZ VOTRE CO=
MMANDE</a></td>=0A
As you see at each end it add a "=" sign . I don't know why, is it because i print it ?
My main question is how to extract a specific link from a MIMEmail. I tried lxml withoug success. first because i have those "=" added i think or because it's not a valid html or xml.
Thanks for your help
In my script I need to extract a set of emails that match some query. I decided to use GMail's API python client for this. Now, my understanding was that the GetMimeMessage() was supposed to return a set of decoded base 64 messages. Here is my code:
def GmailInput():
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('gmail', 'v1', http=http)
defaultList= ListMessagesMatchingQuery(service, 'me', 'subject:infringement label:unread ')
print(defaultList)
for msg in defaultList:
currentMSG=GetMimeMessage(service, 'me', msg['id'])
....then I parse the text of the emails and extract some things
The problem is, I am unable to actually parse the message body because GetMimeMessage is not returning a base64 decoded message. So what I am actually parsing ends up being completely unreadable by humans.
I find this peculiar because GetMimeMessage (copied below for convenience) literally does a url-safe base 64 decode of the message data. Anyone have any suggestion? Im really stumped on this.
def GetMimeMessage(service, user_id, msg_id):
"""Get a Message and use it to create a MIME Message.
Args:
service: Authorized Gmail API service instance.
user_id: User's email address. The special value "me"
can be used to indicate the authenticated user.
msg_id: The ID of the Message required.
Returns:
A MIME Message, consisting of data from Message.
"""
try:
message = service.users().messages().get(userId=user_id, id=msg_id, format='raw').execute()
print ('Message snippet: %s' % message['snippet'])
msg_str = base64.urlsafe_b64decode(message['raw'].encode('ASCII'))
mime_msg = email.message_from_string(msg_str)
return mime_msg
except errors.HttpError, error:
print ('An error occurred: %s' % error)
You can use User.messages:get. This request requires authorization with at least one of the following scopes.
HTTP request
GET https://www.googleapis.com/gmail/v1/users/userId/messages/id
import base64
import email
from apiclient import errors
def GetMessage(service, user_id, msg_id):
"""Get a Message with given ID.
Args:
service: Authorized Gmail API service instance.
user_id: User's email address. The special value "me"
can be used to indicate the authenticated user.
msg_id: The ID of the Message required.
Returns:
A Message.
"""
try:
message = service.users().messages().get(userId=user_id, id=msg_id).execute()
print 'Message snippet: %s' % message['snippet']
return message
except errors.HttpError, error:
print 'An error occurred: %s' % error
def GetMimeMessage(service, user_id, msg_id):
"""Get a Message and use it to create a MIME Message.
Args:
service: Authorized Gmail API service instance.
user_id: User's email address. The special value "me"
can be used to indicate the authenticated user.
msg_id: The ID of the Message required.
Returns:
A MIME Message, consisting of data from Message.
"""
try:
message = service.users().messages().get(userId=user_id, id=msg_id,
format='raw').execute()
print 'Message snippet: %s' % message['snippet']
msg_str = base64.urlsafe_b64decode(message['raw'].encode('ASCII'))
mime_msg = email.message_from_string(msg_str)
return mime_msg
except errors.HttpError, error:
print 'An error occurred: %s' % error