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)')
Related
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.
I am creating something so when it receives an email depending on what is the subject line it does a function now the code I have works in python 2.7 and runs in 3.7 but gives one error "TypeError: can't concat int to bytes" I've haven't tried much because I couldn't find anything online and im new to python please let me know
import imaplib
import email
from time import sleep
from ssh import myRoomOff, myRoomOn
count = 0
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('EMAIL', 'PASSWORD')
mail.list()
mail.select('inbox')
#need to add some stuff in here
while True:
mail.select('inbox')
typ, data = mail.search(None, 'UNSEEN')
ids = data[0]
id_list = ids.split()
#get the most recent email id
latest_email_id = int( id_list[-1] )
#iterate through 15 messages in decending order starting with latest_email_id
#the '-1' dictates reverse looping order
for i in range( latest_email_id, latest_email_id-1, -1 ):
typ, data = mail.fetch(i, '(RFC822)' )
for response_part in data:
if isinstance(response_part, tuple):
msg = email.message_from_bytes(response_part[1])
varSubject = msg['subject']
count += 1
print(str(count) + ", " + varSubject)
if varSubject == "+myRoom":
myRoomOn()
elif varSubject == "-myRoom":
myRoomOff()
else:
print("I do not understand this email!")
pass
sleep(2)
error
Traceback (most recent call last):
File "/Users/danielcaminero/Desktop/alexaCommandThing/checkForEmail.py", line 28, in <module>
typ, data = mail.fetch(i, '(RFC822)' )
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/imaplib.py", line 548, in fetch
typ, dat = self._simple_command(name, message_set, message_parts)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/imaplib.py", line 1230, in _simple_command
return self._command_complete(name, self._command(name, *args))
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/imaplib.py", line 988, in _command
data = data + b' ' + arg
TypeError: can't concat int to bytes
The first argument of mail.fetch() must be a string, but range() yields an int.
So an string-cast would fix it:
typ, data = mail.fetch(str(i), '(RFC822)')
Not a necessary change to fix it, but a more pythonic way to reverse a list is to use list slicing [::-1]. You can save some lines and the range() call.
Furthermore your indent is wrong, you handle only the data from the last iteration.
...
id_list = ids.split()
for i in id_list[::-1]:
typ, data = mail.fetch(i, '(RFC822)')
for response_part in data:
if isinstance(response_part, tuple):
msg = email.message_from_bytes(response_part[1])
varSubject = msg['subject']
count += 1
print(str(count) + ", " + varSubject)
if varSubject == "+myRoom":
myRoomOn()
elif varSubject == "-myRoom":
myRoomOff()
else:
print("I do not understand this email!")
pass
(Here you don't need the string cast, because id_list is a list of byte-string. And a byte-string is a valid value for fetch() too.)
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
Update: my code works under python 2.6.5 but not python 3 (I'm using 3.4.1).
I'm unable to search for messages in the "All Mail" or "Sent Mail" folders - I get an exception:
imaplib.error: SELECT command error: BAD [b'Could not parse command']
my code:
import imaplib
m = imaplib.IMAP4_SSL("imap.gmail.com", 993)
m.login("myemail#gmail.com","mypassword")
m.select("[Gmail]/All Mail")
using m.select("[Gmail]/Sent Mail") doesn't work either.
But reading from the inbox works:
import imaplib
m = imaplib.IMAP4_SSL("imap.gmail.com", 993)
m.login("myemail#gmail.com","mypassword")
m.select("inbox")
...
I used the mail.list() command to verify the folder names are correct:
b'(\\HasNoChildren) "/" "INBOX"',
b'(\\Noselect \\HasChildren) "/" "[Gmail]"',
b'(\\HasNoChildren \\All) "/" "[Gmail]/All Mail"',
b'(\\HasNoChildren \\Drafts) "/" "[Gmail]/Drafts"',
b'(\\HasNoChildren \\Important) "/" "[Gmail]/Important"',
b'(\\HasNoChildren \\Sent) "/" "[Gmail]/Sent Mail"',
b'(\\HasNoChildren \\Junk) "/" "[Gmail]/Spam"',
b'(\\HasNoChildren \\Flagged) "/" "[Gmail]/Starred"',
b'(\\HasNoChildren \\Trash) "/" "[Gmail]/Trash"'
I'm following the solutions from these questions, but they don't work for me:
imaplib - What is the correct folder name for Archive/All Mail in Gmail?
I cannot search sent emails in Gmail with Python
Here is a complete sample program that doesn't work on Python 3:
import imaplib
import email
m = imaplib.IMAP4_SSL("imap.gmail.com", 993)
m.login("myemail#gmail.com","mypassword")
m.select("[Gmail]/All Mail")
result, data = m.uid('search', None, "ALL") # search all email and return uids
if result == 'OK':
for num in data[0].split():
result, data = m.uid('fetch', num, '(RFC822)')
if result == 'OK':
email_message = email.message_from_bytes(data[0][1]) # raw email text including headers
print('From:' + email_message['From'])
m.close()
m.logout()
The following exception is thrown:
Traceback (most recent call last):
File "./eport3.py", line 9, in <module>
m.select("[Gmail]/All Mail")
File "/RVM/lib/python3/lib/python3.4/imaplib.py", line 682, in select
typ, dat = self._simple_command(name, mailbox)
File "/RVM/lib/python3/lib/python3.4/imaplib.py", line 1134, in _simple_command
return self._command_complete(name, self._command(name, *args))
File "/RVM/lib/python3/lib/python3.4/imaplib.py", line 965, in _command_complete
raise self.error('%s command error: %s %s' % (name, typ, data))
imaplib.error: SELECT command error: BAD [b'Could not parse command']
Here's the corresponding Python 2 version that works:
import imaplib
import email
m = imaplib.IMAP4_SSL("imap.gmail.com", 993)
m.login("myemail#gmail.com","mypassword")
m.select("[Gmail]/All Mail")
result, data = m.uid('search', None, "ALL") # search all email and return uids
if result == 'OK':
for num in data[0].split():
result, data = m.uid('fetch', num, '(RFC822)')
if result == 'OK':
email_message = email.message_from_string(data[0][1]) # raw email text including headers
print 'From:' + email_message['From']
m.close()
m.logout()
As it's mentioned in this answer:
Try using m.select('"[Gmail]/All Mail"'), so that the double quotes get transmitted.
I suspect imaplib is not properly quoting the string, so the server gets what looks like two arguments: [Gmail]/All, and Mail.
And it works in python v3.4.1
import imaplib
import email
m = imaplib.IMAP4_SSL("imap.gmail.com", 993)
m.login("myemail#gmail.com","mypassword")
m.select('"[Gmail]/All Mail"')
result, data = m.uid('search', None, "ALL") # search all email and return uids
if result == 'OK':
for num in data[0].split():
result, data = m.uid('fetch', num, '(RFC822)')
if result == 'OK':
email_message = email.message_from_bytes(data[0][1]) # raw email text including headers
print('From:' + email_message['From'])
m.close()
m.logout()
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).