#!/usr/bin/env python
#
# A simple script to purge a given folder from an IMAP account.
# Useful for clearing out folders with thousands of messages
# deposited by anti-spam solutions, etc. Plus a good example
# of how to use the Python IMAP client library.
import re, string, sys
import imaplib, getpass
__author__ = "Nick Guy"
__license__ = "GPLv2"
# Build option parser
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-n", "--hostname", dest="hostname", help="Hostname of the IMAP server in question.", metavar="HOSTNAME")
parser.add_option("-u", "--username", dest="username", help="Username to authenticate with. If left blank, you will be prompted to enter one on standard input.", metavar="USERNAME")
parser.add_option("-p", "--password", dest="password", help="Password you wish to authenticate with. If left blank, you will be prompted to enter one on standard input.", metavar="PASS")
parser.add_option("-f", "--folder", dest="folder", help="The folder you want to clear out. If left blank, a list will be shown and you will be asked to enter the name on standard intput.", metavar="FOLDER")
parser.add_option("-s", "--secure", action="store_true", help="Enable SSL support (and TLS in the future). This is always a good idea to try first.", default=False)
parser.add_option("-v", "--verbose", action="store_true", help="Enable verbose output, mostly useful for testing.", default=False)
parser.add_option("-r", "--readonly", action="store_true", help="Operate in Read Only mode. (useful for debugging primarily..)", default=False)
(options,args) = parser.parse_args()
# Process options, making sensible defaults and reading missing values
# from stdin.
if options.hostname == None:
print ("Please specify a hostname: "),
hostname = sys.stdin.readline().strip()
# do error correction here.
else:
hostname = options.hostname
if options.username == None:
print ("Please specify a username: "),
username = sys.stdin.readline().strip()
# Do error checking here.
else:
username = options.username
if options.password == None:
# Getpass module is an ncurses feature that will allow a user
# to type in a password without echoing the characters back to
# the screen.
password = getpass.getpass("Please specify a password: ")
else:
# At some point in the future, learn to overwrite what the option parser found
# on the sys.argv[] array so that passwords don't show up in `ps`
password = options.password
# This is where it gets complicated... We need to now connect to the server to get
# the user's folder list..
if options.secure == True:
mailbox = imaplib.IMAP4_SSL(hostname)
# you'll probably want to deal with all of the necessary SSL warnings here at some point.. :\
# Not to mention integrating the TLS library when you can.
else:
mailbox = imaplib.IMAP4(hostname)
# Connect to the IMAP Server...
try:
mailbox.login(username,password)
except:
print "Unable to authenticatte to IMAP Server: " + hostname + " using username: " + username
mailbox.logout()
sys.exit(5)
if options.folder == None:
print "Select a folder from the list below..."
typ, folders = mailbox.list()
if typ == 'OK':
for folder in folders:
# note that what mailbox.list() returns can vary from server to server.
# So we have to use a regex instead of a standard split().
folder_name = re.split("\s\".\" ", folder)
# Select each mailbox to get the message count, but do
# so read-only so you don't accidentally delete something.
folder_name = folder_name[1].strip("\"")
typ, message_nums = mailbox.select(folder_name, True)
print folder_name + " (" + message_nums[0] + " messages)"
else:
print "Unable to list folders."
if options.verbose == True:
print "output from mail server..."
print "IMAP command response type: " + typ
print "IMAP command response messages: "
print folders
mailbox.logout()
sys.exit(2)
print ("Folder name: "),
folder = sys.stdin.readline().strip() # The extra \n from readline() causes issues with imap4.select()
else:
folder = options.folder
if options.verbose == True:
print "Attempting to acces folder: \"" + folder + "\""
if options.readonly == True:
typ, num_messages = mailbox.select(folder, True)
else:
typ, num_messages = mailbox.select(folder)
if typ == 'OK':
# proceed to deletion, DELETE WITH CAUTION!
if options.verbose == True:
print "About to expunge " + num_messages[0] + " messages... "
# Search for all messages in that box, mark them deleted, then expunge.
typ, data = mailbox.search(None, 'ALL')
if typ != 'OK':
print "Unable to enumerate messages."
mailbox.logout()
sys.exit(6)
else:
for num in data[0].split():
if options.verbose == True:
print "Marking message #" + num + " as deleted."
mailbox.store(num, '+FLAGS', '\\Deleted')
typ, message = mailbox.expunge()
if options.verbose == True:
print "Server response code: " + typ
print "Server response message: ",
print message
if typ == 'OK':
print "Expunged " + num_messages[0] + " messages in " + folder + "."
mailbox.close()
mailbox.logout()
sys.exit(0)
else:
print "Unable to expunge folder: " + folder
if options.verbose == True:
print "Server response code: " + typ
mailbox.logout()
sys.exit(3)
else:
print "Unable to select folder to expunge."
if options.verbose == True:
print "Server response: ",
print num_messages
mailbox.logout()
sys.exit(4)