Python imaplib deleting multiple emails gmail - python

my code look like this...
import imaplib
import email
obj = imaplib.IMAP4_SSL('imap.gmail.com','993')
obj.login('user','pass')
obj.select('inbox')
delete = []
for i in range(1, 10):
typ, msg_data = obj.fetch(str(i), '(RFC822)')
print i
x = i
for response_part in msg_data:
if isinstance(response_part, tuple):
msg = email.message_from_string(response_part[1])
for header in [ 'subject', 'to', 'from', 'Received' ]:
print '%-8s: %s' % (header.upper(), msg[header])
if header == 'from' and '<sender's email address>' in msg[header]:
delete.append(x)
string = str(delete[0])
for xx in delete:
if xx != delete[0]:
print xx
string = string + ', '+ str(xx)
print string
obj.select('inbox')
obj.uid('STORE', string , '+FLAGS', '(\Deleted)')
obj.expunge()
obj.close()
obj.logout()
the error I get is
Traceback (most recent call last):
File "del_email.py", line 31, in <module>
obj.uid('STORE', string , '+FLAGS', '(\Deleted)')
File "C:\Tools\Python(x86)\Python27\lib\imaplib.py", line 773, in uid
typ, dat = self._simple_command(name, command, *args)
File "C:\Tools\Python(x86)\Python27\lib\imaplib.py", line 1088, in _simple_command
return self._command_complete(name, self._command(name, *args))
File "C:\Tools\Python(x86)\Python27\lib\imaplib.py", line 918, in _command_complete
raise self.error('%s command error: %s %s' % (name, typ, data))
imaplib.error: UID command error: BAD ['Could not parse command']
I am looking for a way to delete multiple emails at once using imaplib or other module. I am looking for the simplest example to go off of. This example was given at this link here Using python imaplib to "delete" an email from Gmail? the last answer's example. I'ts not working correctly. I can however get the the 1st example to work to delete one email every time the script is ran. I'd rather try the doing it with a multiple than running the script several thousand times. my main goal is to delete multiple emails through imaplib any workarounds or other working modules or examples would be appreciated.

You might find this a bit easier using IMAPClient as it takes care of a lot more of low level protocol aspects for you.
Using IMAPClient your code would look something like:
from imapclient import IMAPClient
import email
obj = IMAPClient('imap.gmail.com', ssl=True)
obj.login('user','pass')
obj.select('inbox')
delete = []
msg_ids = obj.search(('NOT', 'DELETED'))
for msg_id in msg_ids:
msg_data = obj.fetch(msg_id, ('RFC822',))
msg = email.message_from_string(msg_data[msg_id]['RFC822'])
for header in [ 'subject', 'to', 'from', 'Received' ]:
print '%-8s: %s' % (header.upper(), msg[header])
if header == 'from' and '<senders email address>' in msg[header]:
delete.append(x)
obj.delete_messages(delete)
obj.expunge()
obj.close()
obj.logout()
This could be made more efficient by fetching multiple messages in a single fetch() call rather than fetching them one at a time but I've left that out for clarity.
If you're just wanting to filter by the sender's address you can get the IMAP server to do the filtering for you. This avoids the need to download the message bodies and makes the process a whole lot faster.
This would look like:
from imapclient import IMAPClient
obj = IMAPClient('imap.gmail.com', ssl=True)
obj.login('user','pass')
obj.select('inbox')
msg_ids = obj.search(('NOT', 'DELETED', 'FROM', '<senders email address>'))
obj.delete_messages(msg_ids)
obj.expunge()
obj.close()
obj.logout()
Disclaimer: I'm the author and maintainer of IMAPClient.

Initial post :
SyntaxError: '<sender's email address>'
# did you mean :
"<sender's email address>"

Related

How to delete email from gmail using python IMAP?

I am trying to read otp from mail and after that I want to delete that email from gmail option. I have no problem in reading email but I am not able to delete mail. I tried some code from stackoverflow. below is my code.
def getOtpMail(vEmail, vPaasword):
connection = imaplib.IMAP4_SSL(IMAP_URL) # stablish connection with IMAP server
try:
connection.login(vEmail, vPaasword) # Login with userid password
except Exception as e:
print(e)
return
loopLock = True
while loopLock:
# fetch
connection.select('"INBOX"', readonly=True)
retCode, messages = connection.search(None, '(UNSEEN)')
print(messages[0])
latest = int(messages[0].split()[-1])
res, msg = connection.fetch(str(latest), "(RFC822)")
for response in msg:
if isinstance(response, tuple):
print('\n------------email--------------\n')
msg = email.message_from_bytes(response[1])
if SENDER_NAME in msg['From'] and KEYWORD in msg['Subject']:
loopLock = False
# fetch required information
for part in msg.walk():
body = part.get_payload()
word_list = body.split()
index = word_list.index('verification')
otp = word_list[index + 3].strip('.')
#delete mail - below two line not working
connection.store(str(latest), '+FLAGS', '"[Gmail]/Trash"')
print(connection.expunge())
return otp
else:
continue
I read documentation and print connection.expunge() so I got response as ('NO', [b'EXPUNGE attempt on READ-ONLY folder (Failure)']) . I think issue I have to establish connection in WRITE mode. I am not sure about it.
In this issue, I opened mail box in readonly mode. Hence my program not able to write and store in IMAP server.
I changed
connection.select('"INBOX"', readonly=True)
to
connection.select('"INBOX"', readonly=False)
also I changed command type and flag type in store method -
connection.store(str(latest), '+FLAGS', '"[Gmail]/Trash"')
to
connection.store(str(latest), '+FLAGS', '\\Deleted')
.

How to delete only one, specific message using IMAP in Python

I'm looking for one, specific message, and then, after found, I want to delete it from inbox. Just this one.
My code:
import email
import imaplib
def check_email(self, user, password, imap, port, message):
M = imaplib.IMAP4_SSL(imap, port)
M.login(user, password)
M.select()
type, message_numbers = M.search(None, '(ALL)')
subjects = []
for num in message_numbers[0].split():
type, data = M.fetch(num, '(RFC822)')
msg = email.message_from_bytes(data[0][1])
subjects.append(msg['Subject'])
if message in subjects:
M.store(num, '+FLAGS', '\\Deleted')
else:
raise FileNotFoundError('Ooops!')
M.close()
M.logout()
I want to find and delete only one mail by title, gven in the variable (message).
Can you help me?
You loop over all the messages, then delete the last one (which is what num ends up pointing to after the loop finishes) if any one of the messages has a subject which matches. You probably want to reindent the code so that the check takes place inside the loop, and probably abandon the rest of the loop once you found the one you want.
def check_email(self, user, password, imap, port, message):
M = imaplib.IMAP4_SSL(imap, port)
M.login(user, password)
M.select()
type, message_numbers = M.search(None, '(ALL)')
found = False
for num in message_numbers[0].split():
type, data = M.fetch(num, '(RFC822)')
msg = email.message_from_bytes(data[0][1])
# No need to collect all the subjects in a list
# Just examine the current one, then forget this message if it doesn't match
if message in msg['Subject']:
M.store(num, '+FLAGS', '\\Deleted')
found = True
break
# Don't raise an exception before cleaning up
M.close()
M.logout()
# Now finally
if not Found:
raise FileNotFoundError('Ooops!')

Collect Python output till current execution and assign it to variable for sending email

I am doing text processing using Python in which I am looking for a specific text in a console log and printing every matched line. This is accomplished by a function called:
get_matched_log_lines(url, search_pattern, print_pattern) where url = from which I get my log, search_pattern = my target search pattern, print_pattern = the way I want to print my output(its, %s.%s)
How do I send this entire output of function get_matched_log_lines() via email? Emailing function code is already written by me in Python.
Here is what I think/attempted so far:
email_content = get_matched_log_lines(url, search_pattern, print_pattern)
TO = 'recipient email address'
FROM ='sender email address'
#emailing function - py_mail
py_mail("Test email subject", email_content, TO, FROM)
This provides me an empty email.
Here is my answer based on the suggestions by PyNEwbie:
def get_matched_log_lines(url, search_pattern, print_pattern):
out = open("output_file.txt", "w")
for something in somthings:
test = print_pattern % matched_line
print >>out, test
out.close()
^^ just a general example (syntax maybe incorrect). The idea is to open the file in write mode and then dumping the output in it.
fp = open("output_file.txt", 'r')
# Create a text/plain message
msg = fp.read()
fp.close()
email_content = msg
Then open the same file in read mode and store its output to some var (in my case email_content)
Finally send an email with that email_content,
email_content = get_matched_log_lines(url, search_pattern, print_pattern)
TO = 'recipient email address'
FROM ='sender email address'
#emailing function - py_mail
py_mail("Test email subject", email_content, TO, FROM)

Python IMAP search using a subject encoded with utf-8

This question is related to question Python IMAP search using a subject encoded with iso-8859-1, but the reply given there is not working for me.
I am doing the following IMAP search in python:
typ, data = self.M.search("utf-8", "(SUBJECT %s)" % u"réception".encode("utf-8"))
And I get the following exception:
...
typ, data = self.M.search("utf-8", "(SUBJECT %s)" % u"réception".encode("utf-8"))
File "/usr/local/python/2.7.2/lib/python2.7/imaplib.py", line 625, in search
typ, dat = self._simple_command(name, 'CHARSET', charset, *criteria)
File "/usr/local/python/2.7.2/lib/python2.7/imaplib.py", line 1070, in _simple_command
return self._command_complete(name, self._command(name, *args))
File "/usr/local/python/2.7.2/lib/python2.7/imaplib.py", line 905, in _command_complete
raise self.error('%s command error: %s %s' % (name, typ, data))
error: SEARCH command error: BAD ['Could not parse command']
Why is that? How can I solve this problem?
import imaplib
import getpass
email = "XXXXXXX#gmail.com"
sock = imaplib.IMAP4_SSL("imap.gmail.com", 993)
sock.login(email, getpass.getpass())
# select the correct mailbox...
sock.select()
# turn on debugging if you like
sock.debug = 4
then:
# use the undocumented IMAP4.literal attribute
sock.literal = "réception"
sock.uid('SEARCH', 'CHARSET', 'UTF-8', 'SUBJECT')
u"réception" will need to be wrapped with quotes: u'"réception"', as IMAPLIB will not quote the string for you in the list.
Update: I could not get gmail's IMAP implementation to accept even a quoted string, and had to use IMAP literal syntax. I'm not sure if this is limitation of my encoding using socat, or a limitation with gmail.
a UID SEARCH CHARSET utf-8 SUBJECT "réception"
a BAD Could not parse command
a UID SEARCH CHARSET utf-8 SUBJECT {10}
+ go ahead
réception
* SEARCH
a OK SEARCH completed (Success)
Unfortunately, imaplib does not provide any way to force using of an IMAP literal.
External lib https://github.com/ikvk/imap_tools supports search by encoded data
from imap_tools import MailBox, A
# get list of emails that subject contains "réception" from INBOX folder
with MailBox('imap.mail.com').login('test#mail.com', 'pwd') as mailbox:
for msg in mailbox.fetch(A(subject='réception'), charset='utf8'):
print(msg.subject)
this one works for me
# use the undocumented IMAP4.literal attribute
sock.literal = u"réception".encode('utf-8')
sock.uid('SEARCH', 'CHARSET', 'UTF-8', 'SUBJECT')
Thanks, Lee!

Python 3.0 smtplib

I have a very simple piece of code that I used in previous versions of Python without issues (version 2.5 and prior). Now with 3.0, the following code give the error on the login line "argument 1 must be string or buffer, not str".
import smtplib
smtpserver = 'mail.somedomain.com'
AUTHREQUIRED = 1 # if you need to use SMTP AUTH set to 1
smtpuser = 'admin#somedomain.com' # for SMTP AUTH, set SMTP username here
smtppass = 'somepassword' # for SMTP AUTH, set SMTP password here
msg = "Some message to send"
RECIPIENTS = ['admin#somedomain.com']
SENDER = 'someone#someotherdomain.net'
session = smtplib.SMTP(smtpserver)
if AUTHREQUIRED:
session.login(smtpuser, smtppass)
smtpresult = session.sendmail(SENDER, RECIPIENTS, msg)
Google shows there are some issues with that error not being clear, but I still can't figure out what I need to try to make it work. Suggestions included defining the username as b"username", but that doesn't seem to work either.
UPDATE: just noticed from a look at the bug tracker there's a suggested fix also:
Edit smtplib.py and replace the existing encode_plain() definition with this:
def encode_plain(user, password):
s = "\0%s\0%s" % (user, password)
return encode_base64(s.encode('ascii'), eol='')
Tested here on my installation and it works properly.
Traceback (most recent call last):
File "smtptest.py", line 18, in <module>
session.login(smtpuser, smtppass)
File "c:\Python30\lib\smtplib.py", line 580, in login
AUTH_PLAIN + " " + encode_plain(user, password))
File "c:\Python30\lib\smtplib.py", line 545, in encode_plain
return encode_base64("\0%s\0%s" % (user, password))
File "c:\Python30\lib\email\base64mime.py", line 96, in body_encode
enc = b2a_base64(s[i:i + max_unencoded]).decode("ascii")
TypeError: b2a_base64() argument 1 must be bytes or buffer, not str
Your code is correct. This is a bug in smtplib or in the base64mime.py.
You can track the issue here:
http://bugs.python.org/issue5259
Hopefully the devs will post a patch soon.
As a variation on Jay's answer, rather than edit smtplib.py you could "monkey patch" it at run time.
Put this somewhere in your code:
def encode_plain(user, password):
s = "\0%s\0%s" % (user, password)
return encode_base64(s.encode('ascii'), eol='')
import smtplib
encode_plain.func_globals = vars(smtplib)
smtplib.encode_plain = encode_plain
This is kind of ugly but useful if you want to deploy your code onto other systems without making changes to their python libraries.
This issue has been addressed in Python3.1. Get the update at http://www.python.org/download/releases/3.1/

Categories

Resources