python IMAPlib how to move emails with no UIDs into sub folders - python

I am using the following to move emails into subfolders, however this crashes in some cases because I am told some emails don't have UIDs. Is there an alternative to this to move emails into subfolders without using UIDs?
def parse_uid(self, data):
match = pattern_uid.match(data)
return match.group('uid')
where
pattern_uid = re.compile('\d+ \(UID (?P<uid>\d+)\)')
Called this way:
resp, data = self.m.fetch(str(self.i), "(UID)")
msg_uid = self.parse_uid(data[0].decode())
with self.i being the integer id for the given email.
The aim was to copy messages using msg_uid as follows:
result = self.m.uid('COPY', msg_uid, 'Inbox/VALORISATIONS/KGI')
print("Result:", result[0])
if result[0] == 'OK':
mov, data = self.m.uid('STORE', msg_uid, '+FLAGS', '(\Deleted)')
self.m.expunge()
print("Mail moved to subfolder")
And this gives for some providers (Allianz, Metzler, KGI, Mitsubishi) the following error message:
Traceback (most recent call last):
File "AutomatePDP_IMAP.py", line 3283, in <module>
GestionBoitePDP.get_mail_deal_with_it(skipgetpasswords = None)
File "AutomatePDP_IMAP.py", line 3264, in get_mail_deal_with_it
msg_uid = self.parse_uid(data[0].decode())
File "AutomatePDP_IMAP.py", line 111, in parse_uid
return match.group('uid')
AttributeError: 'NoneType' object has no attribute 'group'
Adding the following condition in the parse_uid function:
def parse_uid(self, data):
match = pattern_uid.match(data)
if match is not None:
return match.group('uid')
else:
return "UID NA"
and then using:
if msg_uid != "UID NA":
result = self.m.uid('COPY', msg_uid,'Inbox/VALORISATIONS/ALAHLI')
print("Result:", result[0])
if result[0] == 'OK':
mov, data = self.m.uid('STORE', msg_uid, '+FLAGS', '(\Deleted)')
self.m.expunge()
print("Mail moved to subfolder")
I followed Max's advice and removed self.m.expunge() from the loop and added it after the loop.
Problem solved.

I followed Max's advice and removed self.m.expunge() from the loop and added it after the loop.

Related

How to fix: "TypeError: 'bool' object is not subscriptable"

I am currently working with a basic client/server application and implementing a simple RSA / public-key authentication system. I have ran into this error and can not, for the life of me, figure it out.
I am using the latest version of python.
server.py
def getUserData(username):
global privateKeysFilename
filename = privateKeysFilename
with open(filename, "r") as keysFile:
for line in keysFile:
line = [token.rstrip("\n") for token in line.split(",")]
if(username == line[0]):
if DEBUG:
print("\n=== DEBUG\nUser data = %s\n===\n" %(line))
return line
return False
def running(self):
global BUFFER, DEBUG, start, final
while 1:
print('Waiting for a connection')
connection, client_address = self.server_socket.accept()
connection.send("Successful connection!".encode())
x = randint(start, final)
self.fx = function(x)
connection.send(str(x).encode())
try:
# Output that a client has connected
print('connection from', client_address)
write_connection()
# Set the time that the client connected
start_time = datetime.datetime.now()
# Loop until the client disconnects from the server
while 1:
# Receive information from the client
userData = connection.recv(BUFFER)
#data = connection.recv(1024).decode()
if(userData != "0"):
#define split character
ch = ","
userData = userData.split(ch.encode())
username = userData[0]
r = int(userData[1])
userData = getUserData(username)
e, n = int(userData[1]), int(userData[2])
y = modularPower(r, e, n)
if DEBUG:
print("=== DEBUG\ne = %d\nn = %d\nr = %d\ny = %d\n===\n" %(e, n, r, y))
if(self.fx == y):
#if authentication passed
connection.send("Welcome!!!".encode())
else:
connection.send("Failure!!!".encode())
if (userData != 'quit') and (userData != 'close'):
print('received "%s" ' % userData)
connection.send('Your request was successfully received!'.encode())
write_data(userData)
# Check the dictionary for the requested artist name
# If it exists, get all their songs and return them to the user
if userData in self.song_dictionary:
songs = ''
for i in range(len(self.song_dictionary.get(userData))):
songs += self.song_dictionary.get(userData)[i] + ', '
songs = songs[:-2]
print('sending data back to the client')
connection.send(songs.encode())
print("Sent", songs)
# If it doesn't exist return 'error' which tells the client that the artist does not exist
else:
print('sending data back to the client')
connection.send('error'.encode())
else:
# Exit the while loop
break
# Write how long the client was connected for
write_disconnection(start_time)
except socket.error:
# Catch any errors and safely close the connection with the client
print("There was an error with the connection, and it was forcibly closed.")
write_disconnection(start_time)
connection.close()
data = ''
finally:
if data == 'close':
print('Closing the connection and the server')
# Close the connection
connection.close()
# Exit the main While loop, so the server does not listen for a new client
break
else:
print('Closing the connection')
# Close the connection
connection.close()
# The server continues to listen for a new client due to the While loop
and here is the output with error:
Traceback <most recent call last>:
File "server.py", line 165, in running
e, n = int(userData[1]), int(userData[2])
TypeError: 'bool' object is not subscriptable
Any help would be greatly appreciated! :)
By using userData[n] you are trying to access the nth element in a subscriptable object.
This can be a list, dict, tuple or even a string.
The error you see means that your object userData is neither of the previous mentioned types, and it's a bool ( True or False )
Since it's the result of calling the function getUserData(), I recommend you check the return type of this function and make sure it's of the mentioned types and revise your code logic.
[Update]
By checking the function getUserData() it looks it only returns line if the username is included, if not it returns False which is not handled in the main code.
I suggest this edit to the code to inlclude success status to the return value as follows.
def getUserData(username):
global privateKeysFilename
filename = privateKeysFilename
with open(filename, "r") as keysFile:
for line in keysFile:
line = [token.rstrip("\n") for token in line.split(",")]
if(username == line[0]):
if DEBUG:
print("\n=== DEBUG\nUser data = %s\n===\n" %(line))
return True, line
return False, None
And then in your code when you call getUserData() you check for the success first before parsing data like this
userData = getUserData(username)
if userData [0]:
e, n = int(userData[1]), int(userData[2])
y = modularPower(r, e, n)
else:
# Your failure condition

How to print just message body from payload of a mail in python 2.7

I am trying to print message but getting unwanted text. Not able to filter that.
#!/usr/bin/python
import imaplib
import email
import re
p = re.compile(r'Server Status')
mail = imaplib.IMAP4_SSL('stbeehive.yxz.com')
(retcode, capabilities) = mail.login('abc#yxz.com','passwd')
print retcode, capabilities
mail.list()
mail.select('Inbox')
n=0
(retcode, messages) = mail.search(None,'(UNSEEN)')
if retcode == 'OK':
for num in messages[0].split() :
print 'Processing '
n=n+1
typ, data = mail.fetch(num,'(RFC822)')
for response_part in data:
if isinstance(response_part, tuple):
original = email.message_from_string(response_part[1])
print original['From']
print original['Subject']
if original.is_multipart():
message = original.get_payload()[0]
print message
for line in message:
if p.findall(line):
print line
else:
print original.get_payload()
print n
When I am trying to print getting below message.I just want third line from this.
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Server Status#XYZBSS##XYZ Running
I tried to filter "Server Status" by using re.compile in the above code but getting below error.
File "./mail.py", line 27, in <module>
for line in message:
File "/usr/lib64/python2.6/email/message.py", line 292, in __getitem__
return self.get(name)
File "/usr/lib64/python2.6/email/message.py", line 358, in get
name = name.lower()
AttributeError: 'int' object has no attribute 'lower'
Without seeing the message this is mildly speculative, but it looks like you are extracting a body part with headers and all. You want to find the correct body part, then extract its payload.
Without an actual message to look at, there is no way to test this, but I'm guessing something like
if original.is_multipart():
# Quick hack, should probably properly recurse
message = original.get_payload()[0].get_payload()
else:
message = original.get_payload()
#print message
for line in message.split('\n'):
if 'Server Status' in line: # look ma, no regex necessary
print line

Python imaplib delete's 2 emails then crashes

What I am trying to do:
I want to retrieve emails from gmail, download the email as a text file then delete the original email off the gmail server.
The Issue:
The Issue I run into is when I add the delete portion of the code. So If I don't delete, it will pull down all the emails I want and save them as text files. Once I added the delete portion of my code it downloads 2 emails then deletes them off the gmail server then gives the error below on the third. I can run the script again and it will download another 2 and give the same error on the third. I can't see what i'm doing wrong, any help with this would be greatly appreciated.
The Code
#!/usr/bin/env python
import getpass, imaplib, email, os
from email.parser import HeaderParser
detach_dir = os.path.expanduser('~/Documents/Test/')
M = imaplib.IMAP4_SSL("imap.gmail.com", 993)
address = "EMAIL#GMAIL.com"
password = "PASSWORD"
M.login(address, password)
M.select("EMAIL LABEL")
resp, items = M.search(None, "ALL")
items = items[0].split()
for emailid in items:
resp, data = M.FETCH(emailid, '(RFC822)')
mail = email.message_from_string(data[0][1])
for part in mail.walk():
if part.get_content_maintype() == 'multipart':
continue
if part.get_content_subtype() != 'plain':
continue
payload = part.get_payload()
filename = mail["Subject"] + "_gmail.txt"
filename = filename.replace('FW: ', '').replace(' ', '_').replace('\n', '').replace('\r', '').replace('__', '_')
print "FILENAME IS: " + filename
att_path = os.path.join(detach_dir, filename)
if (not os.path.isfile(att_path)):
fp = open(att_path, 'w+')
fp.write(payload)
fp.close()
M.store(emailid, '+FLAGS', '\\Deleted')
M.expunge()
The Error
FILENAME IS: email_1_gmail.txt
FILENAME IS: email_2_gmail.txt
Traceback (most recent call last):
File "/Users/user1/Documents/Personal Work/Project/gmail4.py", line 20, in <module>
mail = email.message_from_string(data[0][1])
TypeError: 'NoneType' object has no attribute '__getitem__'

Python. Imaplib moving mail to Trash

I have read some solutions but none apparently worked, maybe because of Gmail, I'm not sure, the thing is I want to move my emails from INBOX to Trash and this is what I do:
def process_mailbox():
message={}
M = imaplib.IMAP4_SSL('imap.gmail.com')
try:
M.login('myemail#gmail.com', 'mypassword')
except imaplib.IMAP4.error:
print "LOGIN FAILED!!! "
# ... exit or deal with failure...
rv, mailboxes = M.list()
print mailboxes
if rv == 'OK':
M.select("INBOX")
rv, data = M.search(None, "ALL")
if rv != 'OK':
print "No messages found!"
for num in data[0].split(): #Read all the mails
rv, data = M.fetch(num, '(RFC822)')
if rv != 'OK':
print "ERROR getting message", num
return
msg = email.message_from_string(data[0][1])
#print 'Subject %s: %s' % (num, msg['Subject'])
message['Subject']=msg['Subject']
print 'Subject: '+message['Subject']
if msg.get_content_type() == "text_plain": #No Multipart messages
body = msg.get_payload()
message['Body']=body
else: #Multipart messages
for part in msg.walk():
if part.get_content_type() == "text/plain": # ignore attachments/html
message['Body']=body
#print message['Body']
date_tuple = email.utils.parsedate_tz(msg['Date'])
if date_tuple:
local_date = datetime.datetime.fromtimestamp(
email.utils.mktime_tz(date_tuple))
print "Local Date:", local_date.strftime("%Y-%m-%d")
message['Date']=local_date.strftime("%Y-%m-%d")
#send_mail(message)
#insert_vulnerability_mail(message['Subject'],message['Date'],message['Body'].encode('utf-8'))
# M.store(num, '+FLAGS', '\\Deleted')
M.copy(num,'[Gmail]/Trash')
M.close()
M.logout()
So, as you can see, is: M.copy(num,'[Gmail]/Trash') and the result is that I move some emails, lets say, if I have 7 I move 4 out of 7, then I get this error:
Traceback (most recent call last):
File "mail.py", line 116, in <module>
process_mailbox()
File "mail.py", line 75, in process_mailbox
msg = email.message_from_string(data[0][1])
TypeError: 'NoneType' object has no attribute '__getitem__'
Which I don't understand because when I execute next time the programm I move more emails, get the error on an other email, execute and I end up moving everything, but I have to execute several times.
Does anyone know what is going on¿? Thank you on advance
Try this:
imap.store(mail_to_be_deleted, '+FLAGS', r'(\Deleted)')

Python: 'NoneType' object is unsubscriptable : imaplib

This is covered extensively in SO, so I apologize in advance ...however, I've gone through the posts and can't get this to work.
GOALS
Want to get email from gmail that match certain criteria, save the attachments, then delete them.
ISSUE
So, I can get everything to work except deleting the emails. It deletes a few then I get this error:
Traceback (most recent call last): File "get_overdues.py", line 22,
in
email_body = data[0][1] TypeError: 'NoneType' object is unsubscriptable
Every time I run it it deletes more emails then exits with the same error. This has to run on a cronjob and can't be babysat.
What am I doing wrong?
m = imaplib.IMAP4_SSL("imap.gmail.com")
m.login(user,word)
m.select("INBOX")
searchString = "(SUBJECT \"Daily Mail Notices\")"
resp, items = m.search(None,searchString)
items = items[0].split()
for emailid in items:
print emailid
resp, data = m.fetch(emailid, "(RFC822)")
email_body = data[0][1]
mail = email.message_from_string(email_body)
if mail.get_content_maintype() != 'multipart':
continue
print "["+mail["From"]+"] :" + mail["Subject"] + mail["Date"]
sub_dir = re.sub('[,:\- ]','', mail["Date"])
for part in mail.walk():
if part.get_content_maintype() == 'multipart':
continue
if part.get('Content-Disposition') is None:
continue
message_dir = os.path.join(dump_dir, sub_dir)
if not os.path.exists(message_dir):
os.makedirs(message_dir)
filename = part.get_filename()
counter = 1
if not filename:
filename = 'overdues-%s' % counter
counter += 1
att_path = os.path.join(dump_dir, message_dir, filename)
if not os.path.isfile(att_path) :
fp = open(att_path, 'wb')
fp.write(part.get_payload(decode=True))
fp.close()
m.store(emailid, '+FLAGS', r'(\Deleted)')
m.expunge()
m.close()
m.logout()
Your problem is clearly with fetch:
resp, data = m.fetch(emailid, "(RFC822)")
email_body = data[0][1]
It's returning a NoneType for either data or, less likely, for data[0], and None obviously isn't subscriptable. You may want to double check the results of m.fetch and see if it's coming the form you expect it to.
This is probably because this email was deleted (and not expunged).

Categories