Python IMAP select multiple folders - python

I'm trying to get the informations from all the folders but it seems that the code gives me the following error:
command SEARCH illegal in state AUTH, only allowed in states SELECTED
I've googled it but no results for me.
This is the code:
M = imaplib.IMAP4_SSL('',993)
M.login(user,password)
folders = M.list()
for folder in folders[1]:
for allfolders in re.findall('"\/"(.*)',folder):
finalfolders = allfolders.replace(" ",'')
M.select(finalfolders, readonly=True)
print finalfolders
typ, data = M.search(None, 'ALL')
for num in data[0].split():
typ, data = M.fetch(num, '(RFC822)')
email_message = email.message_from_string(data[0][1])
su = email_message['From']
allz = re.findall("<(.*)>",su)
for x in allz:
print x
results.write(x+'\n')
results.flush()
#print su
M.close()
M.logout()
Basically I'm trying to fetch "From", from all the folders founded into my email account.

You can only have one folder selected at any given time using one IMAP connection. This means that your code should EXAMINE or SELECT a mailbox at first, then FETCH whatever you need to download, then do not call CLOSE because it removes messages marked for deletion, and upon entering the next loop iteration, call EXAMINE or SELECT once again, and...

Related

imaplib STORE failed - Mailbox has read-only access. Cannot Delete Yahoo Email

trying to delete emails in my yahoo account using imaplib. i'm new to python, figured out most of the code but unable to find anything that works relating to this error.
imap = imaplib.IMAP4_SSL(imap_server)
imap.login(email_address, password)
imap.select("Learn", readonly=False)
con = imaplib.IMAP4_SSL('imap.mail.yahoo.com',993)
con.login(email_address, password)
con.select('Learn',readonly=False)
imap.select('"Learn"', "(UNSEEN)")
for i in '1':
typ, msg_data = imap.fetch('1', '(RFC822)')
for response_part in msg_data:
if isinstance(response_part, tuple):
msg = email.message_from_bytes(response_part[1])
for header in [ 'from' ]:
print('%-8s: %s' % (header.upper(), msg[header]))
imap.store(i, "+FLAGS", "\\Deleted")
#tried commented codes below and same error
#imap.expunge()
#result, data = imap.uid('STORE', str(i) , '+FLAGS', '(\\Deleted)')
#imap.uid('STORE', i, '+X-GM-LABELS', '\\Trash')
con.close()
con.logout()
i get the error below
STORE command error: BAD [b'[CANNOT] STORE failed - Mailbox has read-only access']
any help would be greatly appreciated
imap.select('"Learn"', "(UNSEEN)")
Select does not take a search criterion. The second parameter is “readonly”, so this is the same as:
imap.select('"Learn"', readonly="(UNSEEN)")
Which as a non-empty string is the same as:
imap.select('"Learn"', readonly=True)
Which is why you can’t make any changes to that mailbox. Delete the second parameter:
imap.select('"Learn"')
You appear to be wanting to do a search for unseen messages. Use search for this.

python IMAP content of email contains a string

I am able to log in a gmail account with python IMAP
imap = imaplib.IMAP4_SSL('imap.gmail.com')
imap.login(myDict["emailUsername"], myDict["emailPassword"])
imap.select(mailbox='inbox', readonly=False)
resp, items = imap.search(None, 'All')
email_ids = items[0].split()
latest_email_id = email_ids[-1]
resp, data = imap.fetch(latest_email_id, "(UID)")
print ("resp= ", resp, " data=", data)
#msg_uid = parse_uid(data[0])
match = pattern_uid.match(data[0].decode("utf-8"))
#print ("match= ", match)
msg_uid = match.group('uid')
I need to make sure that the UID for the last email I have contains a certain string (XYZ). I am NOT looking for header subject but the content of email. How can I do that ?
There's a couple ways you could go:
Fetch the message and walk through the text body parts looking for your string -- example at Finding links in an emails body with Python
Get the server to do the search by supplying 'latest_email_id' and your search criteria back to the server in a UID SEARCH command. For Gmail, you can even use the X-GM-RAW attribute to use the same syntax support by the GMail web interface. See https://developers.google.com/gmail/imap/imap-extensions for details of that.

How to delete most recently mail sent in python?

Using python and imaplib, how can I delete the most recently sent mail?
I have this:
mail = imaplib.IMAP4_SSL('imap-mail.outlook.com')
mail.login('MYEMAIL#hotmail.com', 'MYPASS')
mail.select('Sent')
mail.search(None, "ALL") # Returns ('OK', ['1 2 ... N'])
# doubt
Thanks in advance!
You'll need to use the select method to open the appropriate folder with read and write permissions. If you do not want to mark your messages as seen, you need to use the examine method.
The sort command is available, but it is not guaranteed to be supported by the IMAP server. For example, Gmail does not support the SORT command.
To try the sort command, you would replace M.search(None, 'ALL') with M.sort(search_critera, 'UTF-8', 'ALL')
Then search_criteria would be a string like:
search_criteria = 'DATE' #Ascending, most recent email last
search_criteria = 'REVERSE DATE' #Descending, most recent email first
search_criteria = '[REVERSE] sort-key' #format for sorting
According to RFC5256 these are valid sort-key's:
"ARRIVAL" / "CC" / "DATE" / "FROM" / "SIZE" / "SUBJECT" / "TO"
I found a solution that worked for me. After get sent mailbox access I was needing to found a message with fetch() function and then delete the email message with expunge() function. From imaplib documentation:
IMAP4.expunge()
Permanently remove deleted items from selected
mailbox. Generates an EXPUNGE response for each deleted message.
Returned data contains a list of EXPUNGE message numbers in order
received.
My code:
mail = imaplib.IMAP4_SSL('imap-mail.outlook.com')
mail.login('MYEMAIL#hotmail.com', 'MYPASS')
mail.select('Sent')
typ, data = mail.search(None, 'ALL')
control = 0
tam = len(data[0].split())
while control < tam:
typ, data = mail.fetch(tam - control, '(RFC822)')
if str(data).find(msg['Subject']) and str(data).find(msg['To']) != -1:
print "Msg found! ", control + 1, "most recently message!"
mail.store(str(tam - control), '+FLAGS', '\\Deleted')
mail.expunge()
break
control = control + 1
mail.close()
mail.logout()

How to fetch last 10 messages from IMAP server?

I use imaplib2 library to search the last 10 messages with such command:
imap_client.search(None, '{}:{}'.format(last_uid, last_uid - 9))
But to get last_uid I need exec every time command like this:
imap_client.select("INBOX", readonly=True)
to get last UID.
Are the any ways to:
get last UID without select() command fetch last 10 messages
without last UID. Maybe there are any search criterias like 'LAST' or '-10:'?
I can not exec command like this client.search(None, 'ALL'), because IMAP server have more than 50K messages.
For any future travelers who seek an answer to this, I came up with code from the hint given by #arnt.
svr = imaplib.IMAP4_SSL(server)
if svr.login(user=user, password=password):
print('User ' + user + ' logged in successfully.')
else:
print('Login for the user ' + user + " was denied. Please check your credentials.")
x = svr.select('inbox', readonly=True)
num = x[1][0].decode('utf-8')
#from here you can start a loop of how many mails you want, if 10, then num-9 to num
resp, lst = svr.fetch(num, '(RFC822)')
body = lst[0][1]
email_message = email.message_from_bytes(body)
For me this was quite handy as I was accessing an email with more than 67000 emails in it.
You can get the last UID using the STATUS (UIDNEXT) command. However, you have to select the mailbox in order to retrieve messages, and when you issue SELECT, you'll get a message count back, which the Python imaplib's select returns.
So all you need is:
(status, response_text) = mailbox.select("inbox")
# response_text usually contains only one bytes element that denotes
# the message count in an ASCII string
message_count = int(response_text[0].decode("ascii"))
and then you can fetch the messages by index from message_count - 9 through message_count.
Note that messages are index starting at one.

imaplib.error: command FETCH illegal in state AUTH

I'm trying to download attachments from Gmail, using a combination of pieces of code I found online, and some editing from myself. However, the following code:
import email, getpass, imaplib, os, random, time
import oauth2 as oauth
import oauth2.clients.imap as imaplib
MY_EMAIL = 'example#gmail.com'
MY_TOKEN = "token"
MY_SECRET = "secret"
consumer = oauth.Consumer('anonymous', 'anonymous')
token = oauth.Token(MY_TOKEN, MY_SECRET)
url = "https://mail.google.com/mail/b/"+MY_EMAIL+"/imap/"
m = imaplib.IMAP4_SSL('imap.gmail.com')
m.authenticate(url, consumer, token)
m.select('INBOX')
items = m.select("UNSEEN");
items = items[0].split()
for emailid in items:
data = m.fetch(emailid, "(RFC822)")
returns this error:
imaplib.error: command FETCH illegal
in state AUTH
Why would Fetch be illegal while I'm authorized?
You're lacking error checking on your calls to select. Typically, this is how I'll structure the first parts of a connection to a mailbox:
# self.conn is an instance of IMAP4 connected to my server.
status, msgs = self.conn.select('INBOX')
if status != 'OK':
return # could be break, or continue, depending on surrounding code.
msgs = int(msgs[0])
Essentially, the trouble you're encountering is that you've selected a mailbox that doesn't exist, your status message is probably not "OK" as it should be, and the value you're iterating over isn't valid. Remember, select expects a mailbox name. It does not search based on a flag (which may be what you're attempting with "UNSEEN"). When you select a non-existent mail box you actually get this as a response:
('NO', ['The requested item could not be found.'])
In which case, for email id in items is not operating properly. Not what you're after in any way, unfortunately. What you'd get on a valid mailbox would be like this:
('OK', ['337'])
Hope that helps.
To address the question in comments, if you want to actually retrieve the unseen messages in the mailbox you'd use this:
status, msgs = self.conn.select('INBOX')
# returns ('OK', ['336'])
status, ids = self.conn.search(None, 'UNSEEN')
# returns ('OK', ['324 325 326 336'])
if status == 'OK':
ids = map(int, ids[0].split())
The response is going to be similar to the response from select, but instead of a single integer for the number of messages you'll get a list of ids.
Why would Fetch be illegal while I'm authorized?
IMAP has a state concept.
You can only fetch messages if you have selected a folder.
Here is a nice picture which shows this:
Image source: http://www.tcpipguide.com/free/t_IMAP4GeneralOperationClientServerCommunicationandS-2.htm

Categories