I hate GMail, but sometimes you gotta. They're notoriously awful at deleting lots of messages at once, as their own search engine will tell you. I had more than 1,000,000 messages I needed to purge and couldn't do it using their own tools. So I wrote my own.
-
-
Save dirkakrid/57146d20d90b9c90babcff29c32a6b47 to your computer and use it in GitHub Desktop.
Bulk move messages from All Mail to Trash
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- encoding: utf-8 -*- | |
## http://nickblogus.tumblr.com/post/73553186015/gmail-deleting-big-amount-of-old-messages-problem | |
import imaplib | |
from email.parser import HeaderParser | |
from email.utils import parsedate_tz, mktime_tz | |
from datetime import datetime, timedelta | |
def chunks(arr, num): | |
for i in xrange(0, len(arr), num): | |
yield arr[i:i + num] | |
def check_result(command, resp, result): | |
assert resp == "OK", "%s failed with %s: %s" % (command, resp, result) | |
return result | |
def main(host, userid, password, days): | |
age_threshold = timedelta(days=int(days)) | |
now = datetime.now() | |
print "connecting" | |
box = imaplib.IMAP4_SSL(host, 993) | |
print "logging in" | |
check_result("logging in", *box.login(userid, password)) | |
print "selecting" | |
check_result("selecting", *box.select("[Gmail]/All Mail")) | |
print "searching" | |
result = check_result("searching", *box.search(None, '(BEFORE "%s")' % (now - age_threshold).strftime("%d-%b-%Y"))) | |
uids = result[0].split() | |
print "%d messages in result" % len(uids) | |
total_deleted = 0 | |
chunk_size = 250 | |
for chunk in chunks(uids, chunk_size): | |
deleted = False | |
for attempt in range(0, 3): | |
try: | |
print "deleting %d, attempt %d" % (len(chunk), attempt) | |
check_result("storing", *box.store(",".join(chunk), "+X-GM-LABELS", "\\Trash")) | |
deleted = True | |
total_deleted += chunk_size | |
break | |
except AssertionError, e: | |
print "attempt %d failed: %s" % (attempt, e) | |
assert deleted, "unable to delete after multiple attempts" | |
print "deleted %6.2f%%, %d of %d" % ((total_deleted * 100.0 / len(uids)), total_deleted, len(uids)) | |
# assert box.expunge()[0] == "OK" | |
if __name__ == "__main__": | |
import sys | |
host, userid, password, days = sys.argv[1:] | |
main(host, userid, password, days) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment