How to delete most recently mail sent in python? - 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()

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.

Python IMAP select multiple folders

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...

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.

How to receive mail using python

I would like to receive email using python. So far I have been able to get the subject but not the body. Here is the code I have been using:
import poplib
from email import parser
pop_conn = poplib.POP3_SSL('pop.gmail.com')
pop_conn.user('myusername')
pop_conn.pass_('mypassword')
#Get messages from server:
messages = [pop_conn.retr(i) for i in range(1, len(pop_conn.list()[1]) + 1)]
# Concat message pieces:
messages = ["\n".join(mssg[1]) for mssg in messages]
#Parse message intom an email object:
messages = [parser.Parser().parsestr(mssg) for mssg in messages]
for message in messages:
print message['subject']
print message['body']
pop_conn.quit()
My issue is that when I run this code it properly returns the Subject but not the body. So if I send an email with the subject "Tester" and the body "This is a test message" it looks like this in IDLE.
>>>>Tester >>>>None
So it appears to be accurately assessing the subject but not the body, I think it is in the parsing method right? The issue is that I don't know enough about these libraries to figure out how to change it so that it returns both a subject and a body.
The object message does not have a body, you will need to parse the multiple parts, like this:
for part in message.walk():
if part.get_content_type():
body = part.get_payload(decode=True)
The walk() function iterates depth-first through the parts of the email, and you are looking for the parts that have a content-type. The content types can be either text/plain or text/html, and sometimes one e-mail can contain both (if the message content_type is set to multipart/alternative).
The email parser returns an email.message.Message object, which does not contain a body key, as you'll see if you run
print message.keys()
What you want is the get_payload() method:
for message in messages:
print message['subject']
print message.get_payload()
pop_conn.quit()
But this gets complicated when it comes to multi-part messages; get_payload() returns a list of parts, each of which is a Message object. You can get a particular part of the multipart message by using get_payload(i), which returns the ith part, raises an IndexError if i is out of range, or raises a TypeError if the message is not multipart.
As Gustavo Costa De Oliveir points out, you can use the walk() method to get the parts in order -- it does a depth-first traversal of the parts and subparts of the message.
There's more about the email.parser module at http://docs.python.org/library/email.message.html#email.message.Message.
it also good return data in correct encoding in message contains some multilingual content
charset = part.get_content_charset()
content = part.get_payload(decode=True)
content = content.decode(charset).encode('utf-8')
Here is how I solved the problem using python 3 new capabilities:
import imaplib
import email
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login(username, password)
mail.select(readonly=True) # refresh inbox
status, message_ids = mail.search(None, 'ALL') # get all emails
for message_id in message_ids[0].split(): # returns all message ids
# for every id get the actual email
status, message_data = mail.fetch(message_id, '(RFC822)')
actual_message = email.message_from_bytes(message_data[0][1])
# extract the needed fields
email_date = actual_message["Date"]
subject = actual_message["Subject"]
message_body = get_message_body(actual_message)
Now get_message_body is actually pretty tricky due to MIME format. I used the function suggested in this answer.
This particular example works with Gmail, but IMAP is a standard protocol, so it should work for other email providers as well, possibly with minor changes.
if u want to use IMAP4. Use outlook python library, download here : https://github.com/awangga/outlook
to retrieve unread email from your inbox :
import outlook
mail = outlook.Outlook()
mail.login('emailaccount#live.com','yourpassword')
mail.inbox()
print mail.unread()
to retrive email element :
print mail.mailbody()
print mail.mailsubject()
print mail.mailfrom()
print mail.mailto()

Categories