def random_folder(logged_in_client: IMAPClient): folder = "random-122122121" if not logged_in_client.folder_exists(folder): logged_in_client.create_folder(folder) yield folder if logged_in_client.folder_exists(folder): logged_in_client.delete_folder(folder) assert not logged_in_client.folder_exists(folder)
class ImapDB(BaseDB): def __init__(self, username, password='******', host='localhost', port=143, *args, **kwargs): super().__init__(username, *args, **kwargs) self.imap = IMAPClient(host, port, use_uid=True, ssl=False) res = self.imap.login(username, password) self.cursor.execute( "SELECT lowModSeq,highModSeq,highModSeqMailbox,highModSeqThread,highModSeqEmail FROM account LIMIT 1" ) row = self.cursor.fetchone() self.lastfoldersync = 0 if row: self.lowModSeq, self.highModSeq, self.highModSeqMailbox, self.highModSeqThread, self.highModSeqEmail = row else: self.lowModSeq = 0 self.highModSeq = 1 self.highModSeqMailbox = 1 self.highModSeqThread = 1 self.highModSeqEmail = 1 # (imapname, readonly) self.selected_folder = (None, False) self.mailboxes = {} self.sync_mailboxes() self.messages = {} def get_messages_cached(self, properties=(), id__in=()): messages = [] if not self.messages: return messages, id__in, properties fetch_props = set() fetch_ids = set(id__in) for id in id__in: msg = self.messages.get(id, None) if msg: found = True for prop in properties: try: msg[prop] except (KeyError, AttributeError): found = False fetch_props.add(prop) if found: fetch_ids.remove(id) messages.append(msg) # if one messages is missing, need to fetch all properties if len(messages) < len(id__in): fetch_props = properties return messages, fetch_ids, fetch_props def get_messages(self, properties=(), sort={}, inMailbox=None, inMailboxOtherThan=(), id__in=None, threadId__in=None, **criteria): # XXX: id == threadId for now if id__in is None and threadId__in is not None: id__in = [id[1:] for id in threadId__in] if id__in is None: messages = [] else: # try get everything from cache messages, id__in, properties = self.get_messages_cached( properties, id__in=id__in) fetch_fields = { f for prop, f in FIELDS_MAP.items() if prop in properties } if 'RFC822' in fetch_fields: # remove redundand fields fetch_fields.discard('RFC822.HEADER') fetch_fields.discard('RFC822.SIZE') if inMailbox: mailbox = self.mailboxes.get(inMailbox, None) if not mailbox: raise errors.notFound(f'Mailbox {inMailbox} not found') mailboxes = [mailbox] elif inMailboxOtherThan: mailboxes = [ m for m in self.mailboxes.values() if m['id'] not in inMailboxOtherThan ] else: mailboxes = self.mailboxes.values() search_criteria = as_imap_search(criteria) sort_criteria = as_imap_sort(sort) or '' if sort else None mailbox_uids = {} if id__in is not None: if len(id__in) == 0: return messages # no messages matches empty ids if not fetch_fields and not sort_criteria: # when we don't need anything new from IMAP, create empty messages # useful when requested conditions can be calculated from id (threadId) messages.extend( self.messages.get(id, 0) or ImapMessage(id=id) for id in id__in) return messages for id in id__in: # TODO: check uidvalidity mailboxid, uidvalidity, uid = parse_message_id(id) uids = mailbox_uids.get(mailboxid, []) if not uids: mailbox_uids[mailboxid] = uids uids.append(uid) # filter out unnecessary mailboxes mailboxes = [m for m in mailboxes if m['id'] in mailbox_uids] for mailbox in mailboxes: imapname = mailbox['imapname'] if self.selected_folder[0] != imapname: self.imap.select_folder(imapname, readonly=True) self.selected_folder = (imapname, True) uids = mailbox_uids.get(mailbox['id'], None) # uids are now None or not empty # fetch all if sort_criteria: if uids: search = f'{",".join(map(str, uids))} {search_criteria}' else: search = search_criteria or 'ALL' uids = self.imap.sort(sort_criteria, search) elif search_criteria: if uids: search = f'{",".join(map(str, uids))} {search_criteria}' uids = self.imap.search(search) if uids is None: uids = '1:*' fetch_fields.add('UID') fetches = self.imap.fetch(uids, fetch_fields) for uid, data in fetches.items(): id = format_message_id(mailbox['id'], mailbox['uidvalidity'], uid) msg = self.messages.get(id, None) if not msg: msg = ImapMessage(id=id, mailboxIds=[mailbox['id']]) self.messages[id] = msg for k, v in data.items(): msg[k.decode()] = v messages.append(msg) return messages def changed_record(self, ifolderid, uid, flags=(), labels=()): res = self.dmaybeupdate( 'imessages', { 'flags': json.dumps(sorted(flags)), 'labels': json.dumps(sorted(labels)), }, { 'ifolderid': ifolderid, 'uid': uid }) if res: msgid = self.dgefield('imessages', { 'ifolderid': ifolderid, 'uid': uid }, 'msgid') self.mark_sync(msgid) def import_message(self, rfc822, mailboxIds, keywords): folderdata = self.dget('ifolders') foldermap = {f['ifolderid']: f for f in folderdata} jmailmap = { f['jmailboxid']: f for f in folderdata if f.get('jmailboxid', False) } # store to the first named folder - we can use labels on gmail to add to other folders later. id, others = mailboxIds imapname = jmailmap[id][imapname] flags = set(keywords) for kw in flags: if kw in KEYWORD2FLAG: flags.remove(kw) flags.add(KEYWORD2FLAG[kw]) appendres = self.imap.append('imapname', '(' + ' '.join(flags) + ')', datetime.now(), rfc822) # TODO: compare appendres[2] with uidvalidity uid = appendres[3] fdata = jmailmap[mailboxIds[0]] self.do_folder(fdata['ifolderid'], fdata['label']) ifolderid = fdata['ifolderid'] msgdata = self.dgetone('imessages', { 'ifolderid': ifolderid, 'uid': uid, }, 'msgid,thrid,size') # XXX - did we fail to sync this back? Annoying if not msgdata: raise Exception( 'Failed to get back stored message from imap server') # save us having to download it again - drop out of transaction so we don't wait on the parse message = parse.parse(rfc822, msgdata['msgid']) self.begin() self.dinsert( 'jrawmessage', { 'msgid': msgdata['msgid'], 'parsed': json.dumps('message'), 'hasAttachment': message['hasattachment'], }) self.commit() return msgdata def update_messages(self, changes, idmap): if not changes: return {}, {} changed = {} notchanged = {} map = {} msgids = set(changes.keys()) sql = 'SELECT msgid,ifolderid,uid FROM imessages WHERE msgid IN (' + ( ('?,' * len(msgids))[:-1]) + ')' self.cursor.execute(sql, list(msgids)) for msgid, ifolderid, uid in self.cursor: if not msgid in map: map[msgid] = {ifolderid: {uid}} elif not ifolderid in map[msgid]: map[msgid][ifolderid] = {uid} else: map[msgid][ifolderid].add(uid) msgids.discard(msgid) for msgid in msgids: notchanged[msgid] = { 'type': 'notFound', 'description': 'No such message on server', } folderdata = self.dget('ifolders') foldermap = {f['ifolderid']: f for f in folderdata} jmailmap = { f['jmailboxid']: f for f in folderdata if 'jmailboxid' in f } jmapdata = self.dget('jmailboxes') jidmap = {d['jmailboxid']: (d['role'] or '') for d in jmapdata} jrolemap = { d['role']: d['jmailboxid'] for d in jmapdata if 'role' in d } for msgid in map.keys(): action = changes[msgid] try: for ifolderid, uids in map[msgid].items(): # TODO: merge similar actions? imapname = foldermap[ifolderid]['imapname'] uidvalidity = foldermap[ifolderid]['uidvalidity'] if self.selected_folder != (imapname, False): self.imap.select_folder(imapname) self.selected_folder = (imapname, False) if imapname and uidvalidity and 'keywords' in action: flags = set(action['keywords']) for kw in flags: if kw in KEYWORD2FLAG: flags.remove(kw) flags.add(KEYWORD2FLAG[kw]) self.imap.set_flags(uids, flags, silent=True) if 'mailboxIds' in action: mboxes = [idmap(k) for k in action['mailboxIds'].keys()] # existing ifolderids containing this message # identify a source message to work from ifolderid = sorted(map[msgid])[0] uid = sorted(map[msgid][ifolderid])[0] imapname = foldermap[ifolderid]['imapname'] uidvalidity = foldermap[ifolderid]['uidvalidity'] # existing ifolderids with this message current = set(map[msgid].keys()) # new ifolderids that should contain this message new = set(jmailmap[x]['ifolderid'] for x in mboxes) for ifolderid in new: # unless there's already a matching message in it if current.pop(ifolderid): continue # copy from the existing message newfolder = foldermap[ifolderid]['imapname'] self.imap.copy(imapname, uidvalidity, uid, newfolder) for ifolderid in current: # these ifolderids didn't exist in new, so delete all matching UIDs from these folders self.imap.move( foldermap[ifolderid]['imapname'], foldermap[ifolderid]['uidvalidity'], map[msgid][ifolderid], # uids ) except Exception as e: notchanged[msgid] = {'type': 'error', 'description': str(e)} raise e else: changed[msgid] = None return changed, notchanged def destroy_messages(self, ids): if not ids: return [], {} destroymap = defaultdict(dict) notdestroyed = {} idset = set(ids) rows = self.dget('imessages', {'msgid': ('IN', idset)}, 'msgid,ifolderid,uid') for msgid, ifolderid, uid in rows: idset.discard(msgid) destroymap[ifolderid][uid] = msgid for msgid in idset: notdestroyed[msgid] = { 'type': 'notFound', 'description': "No such message on server", } folderdata = self.dget('ifolders') foldermap = {d['ifolderid']: d for d in folderdata} jmailmap = { d['jmailboxid']: d for d in folderdata if 'jmailboxid' in d } destroyed = [] for ifolderid, ifolder in destroymap.items(): #TODO: merge similar actions? if not ifolder['imapname']: for msgid in destroymap[ifolderid]: notdestroyed[msgid] = \ {'type': 'notFound', 'description': "No folder"} self.imap.move(ifolder['imapname'], ifolder['uidvalidity'], destroymap[ifolderid].keys(), None) destroyed.extend(destroymap[ifolderid].values()) return destroyed, notdestroyed def deleted_record(self, ifolderid, uid): msgid = self.dgetfield('imessages', { 'ifolderid': ifolderid, 'uid': uid }, 'msgid') if msgid: self.ddelete('imessages', {'ifolderid': ifolderid, 'uid': uid}) self.mark_sync(msgid) def get_raw_message(self, msgid, part=None): self.cursor.execute( 'SELECT imapname,uidvalidity,uid FROM ifolders JOIN imessages USING (ifolderid) WHERE msgid=?', [msgid]) imapname, uidvalidity, uid = self.cursor.fetchone() if not imapname: return None typ = 'message/rfc822' if part: parsed = self.fill_messages([msgid]) typ = find_type(parsed[msgid], part) res = self.imap.getpart(imapname, uidvalidity, uid, part) return typ, res['data'] def get_mailboxes(self, fields=None, **criteria): byimapname = {} # TODO: LIST "" % RETURN (STATUS (UNSEEN MESSAGES HIGHESTMODSEQ MAILBOXID)) for flags, sep, imapname in self.imap.list_folders(): status = self.imap.folder_status(imapname, ([ 'MESSAGES', 'UIDVALIDITY', 'UIDNEXT', 'HIGHESTMODSEQ', 'X-GUID' ])) flags = [f.lower() for f in flags] roles = [f for f in flags if f not in KNOWN_SPECIALS] label = roles[0].decode() if roles else imapname role = ROLE_MAP.get(label.lower(), None) can_select = b'\\noselect' not in flags byimapname[imapname] = { # Dovecot can fetch X-GUID 'id': status[b'X-GUID'].decode(), 'parentId': None, 'name': imapname, 'role': role, 'sortOrder': 2 if role else (1 if role == 'inbox' else 3), 'isSubscribed': True, # TODO: use LSUB 'totalEmails': status[b'MESSAGES'], 'unreadEmails': 0, 'totalThreads': 0, 'unreadThreads': 0, 'myRights': { 'mayReadItems': can_select, 'mayAddItems': can_select, 'mayRemoveItems': can_select, 'maySetSeen': can_select, 'maySetKeywords': can_select, 'mayCreateChild': True, 'mayRename': False if role else True, 'mayDelete': False if role else True, 'maySubmit': can_select, }, 'imapname': imapname, 'sep': sep.decode(), 'uidvalidity': status[b'UIDVALIDITY'], 'uidnext': status[b'UIDNEXT'], # Data sync properties 'createdModSeq': status[b'UIDVALIDITY'], # TODO: persist 'updatedModSeq': status[b'UIDVALIDITY'], # TODO: from persistent storage 'updatedNotCountsModSeq': status[b'UIDVALIDITY'], # TODO: from persistent storage 'emailHighestModSeq': status[b'HIGHESTMODSEQ'], 'deleted': 0, } # set name and parentId for child folders for imapname, mailbox in byimapname.items(): names = imapname.rsplit(mailbox['sep'], maxsplit=1) if len(names) == 2: mailbox['parentId'] = byimapname[names[0]]['id'] mailbox['name'] = names[1] # update cache self.mailboxes = {mbox['id']: mbox for mbox in byimapname.values()} return byimapname.values() def sync_mailboxes(self): self.get_mailboxes() def mailbox_imapname(self, parentId, name): parent = self.mailboxes.get(parentId, None) if not parent: raise errors.notFound('parent folder not found') return parent['imapname'] + parent['sep'] + name def create_mailbox(self, name=None, parentId=None, isSubscribed=True, **kwargs): if not name: raise errors.invalidProperties('name is required') imapname = self.mailbox_imapname(parentId, name) # TODO: parse returned MAILBOXID try: res = self.imap.create_folder(imapname) except IMAPClientError as e: desc = str(e) if '[ALREADYEXISTS]' in desc: raise errors.invalidArguments(desc) except Exception: raise errors.serverFail(res.decode()) if not isSubscribed: self.imap.unsubscribe_folder(imapname) status = self.imap.folder_status(imapname, ['UIDVALIDITY']) self.sync_mailboxes() return f"f{status[b'UIDVALIDITY']}" def update_mailbox(self, id, name=None, parentId=None, isSubscribed=None, sortOrder=None, **update): mailbox = self.mailboxes.get(id, None) if not mailbox: raise errors.notFound('mailbox not found') imapname = mailbox['imapname'] if (name is not None and name != mailbox['name']) or \ (parentId is not None and parentId != mailbox['parentId']): if not name: raise errors.invalidProperties('name is required') newimapname = self.mailbox_imapname(parentId, name) res = self.imap.rename_folder(imapname, newimapname) if b'NO' in res or b'BAD' in res: raise errors.serverFail(res.encode()) if isSubscribed is not None and isSubscribed != mailbox['isSubscribed']: if isSubscribed: res = self.imap.subscribe_folder(imapname) else: res = self.imap.unsubscribe_folder(imapname) if b'NO' in res or b'BAD' in res: raise errors.serverFail(res.encode()) if sortOrder is not None and sortOrder != mailbox['sortOrder']: # TODO: update in persistent storage mailbox['sortOrder'] = sortOrder self.sync_mailboxes() def destroy_mailbox(self, id): mailbox = self.mailboxes.get(id, None) if not mailbox: raise errors.notFound('mailbox not found') res = self.imap.delete_folder(mailbox['imapname']) if b'NO' in res or b'BAD' in res: raise errors.serverFail(res.encode()) mailbox['deleted'] = datetime.now().timestamp() self.sync_mailboxes() def create_submission(self, new, idmap): if not new: return {}, {} todo = {} createmap = {} notcreated = {} for cid, sub in new.items(): msgid = idmap.get(sub['emailId'], sub['emailId']) if not msgid: notcreated[cid] = {'error': 'nos msgid provided'} continue thrid = self.dgetfield('jmessages', { 'msgid': msgid, 'deleted': 0 }, 'thrid') if not thrid: notcreated[cid] = {'error': 'message does not exist'} continue id = self.dmake( 'jsubmission', { 'sendat': datetime.fromisoformat()(sub['sendAt']).isoformat() if sub['sendAt'] else datetime.now().isoformat(), 'msgid': msgid, 'thrid': thrid, 'envelope': json.dumps(sub['envelope']) if 'envelope' in sub else None, }) createmap[cid] = {'id': id} todo[cid] = msgid self.commit() for cid, sub in todo.items(): type, rfc822 = self.get_raw_message(todo[cid]) self.imap.send_mail(rfc822, sub['envelope']) return createmap, notcreated def update_submission(self, changed, idmap): return {}, {x: 'change not supported' for x in changed.keys()} def destroy_submission(self, destroy): if not destroy: return [], {} destroyed = [] notdestroyed = {} namemap = {} for subid in destroy: deleted = self.dgetfield('jsubmission', {'jsubid': subid}, 'deleted') if deleted: destroy.append(subid) self.ddelete('jsubmission', {'jsubid': subid}) else: notdestroyed[subid] = { 'type': 'notFound', 'description': 'submission not found' } self.commit() return destroyed, notdestroyed def _initdb(self): super()._initdb() self.dbh.execute(""" CREATE TABLE IF NOT EXISTS ifolders ( ifolderid INTEGER PRIMARY KEY NOT NULL, jmailboxid INTEGER, sep TEXT NOT NULL, imapname TEXT NOT NULL, label TEXT, uidvalidity INTEGER, uidfirst INTEGER, uidnext INTEGER, highestmodseq INTEGER, uniqueid TEXT, mtime DATE NOT NULL )""") self.dbh.execute( "CREATE INDEX IF NOT EXISTS ifolderj ON ifolders (jmailboxid)") self.dbh.execute( "CREATE INDEX IF NOT EXISTS ifolderlabel ON ifolders (label)") self.dbh.execute(""" CREATE TABLE IF NOT EXISTS imessages ( imessageid INTEGER PRIMARY KEY NOT NULL, ifolderid INTEGER, uid INTEGER, internaldate DATE, modseq INTEGER, flags TEXT, labels TEXT, thrid TEXT, msgid TEXT, envelope TEXT, bodystructure TEXT, size INTEGER, mtime DATE NOT NULL )""") self.dbh.execute( "CREATE UNIQUE INDEX IF NOT EXISTS imsgfrom ON imessages (ifolderid, uid)" ) self.dbh.execute( "CREATE INDEX IF NOT EXISTS imessageid ON imessages (msgid)") self.dbh.execute( "CREATE INDEX IF NOT EXISTS imessagethrid ON imessages (thrid)") self.dbh.execute(""" CREATE TABLE IF NOT EXISTS ithread ( messageid TEXT PRIMARY KEY, sortsubject TEXT, thrid TEXT )""") self.dbh.execute( "CREATE INDEX IF NOT EXISTS ithrid ON ithread (thrid)")
class imap: def __init__(self): try: dbfile = open('.credentials', 'rb') db = pickle.load(dbfile) temp_server = db["server"] if (temp_server == ""): self.server_fail_flag = 1 # declaring that server object of imap is not initialised pass else: try: self.server = IMAPClient(temp_server, use_uid=True) self.server_fail_flag = 0 except: self.server_fail_flag = 1 # declaring that server object of imap is not initialised print( "Couldn't able to sign in. Please try again with valied credentials" ) except: self.server_fail_flag = 1 # declaring that server object of imap is not initialised file = open(".credentials", "w+") file.close() def login(self, id, passwd, server): self.server_name = server self.email = id self.passwd = passwd try: if (self.server_fail_flag == 1): self.server = IMAPClient(self.server_name, use_uid=True) self.server.login(self.email, self.passwd) return 1 print("Login successful") except: return 0 def logout(self): print("Logged out") self.server.logout() def list_folders(self): print("LIST OF FOLDERS") folders = self.server.list_folders() for i in folders: print(i[-1]) return folders print("") print(server.get_gmail_labels(messages)) def createFolder(self, folderName): self.server.create_folder(folderName) print("Folder named - %s - is created successfully..." % folderName) def deleteFolder(self, folderName): self.server.delete_folder(folderName) def deleteEmail(self, messages): self.server.delete_messages(messages) def list_mails(self, folder_name): select_info = self.server.select_folder(folder_name) print('%d messages in %s' % (select_info[b'EXISTS'], folder_name)) # messages = server.search(['FROM', '*****@*****.**']) messages = self.server.search(['ALL']) # messages = self.server.sort(['ARRIVAL']) print("%s messages from %s" % (len(messages), folder_name)) fetched_msgs = self.server.fetch(messages, ['ENVELOPE']).items() return fetched_msgs def search_mails(self, catagory, parameter): if (catagory in ["FROM", "TEXT", "SINCE", "SUBJECT"]): print([catagory, parameter]) messages = self.server.search([catagory, parameter]) print("%s messages from Search catagory -> %s" % (len(messages), catagory)) fetched_msgs = self.server.fetch(messages, ['ENVELOPE']).items() print("fetched Messages are ", fetched_msgs) return fetched_msgs else: print([catagory]) messages = self.server.search([catagory]) print(messages) print("%s messages from Search catagory -> %s" % (len(messages), catagory)) fetched_msgs = self.server.fetch(messages, ['ENVELOPE']).items() print("fetched Messages are ", fetched_msgs) return fetched_msgs def fetch_email_content(self, msg_id): for msgid, data in self.server.fetch(msg_id, 'RFC822').items(): # print("\nMESSAGE", msgid) # print("\nDATA IS => \n", data) # envelope = data[b'ENVELOPE'] msg = email.message_from_bytes(data[b'RFC822']) # print(msgid, email_message.get('From'), email_message.get('Subject')) # print(email_message.get('To'), email_message.get('body')) subject = msg.get('Subject') if msg.is_multipart(): # iterate over email parts for part in msg.walk(): # extract content type of email content_type = part.get_content_type() content_disposition = str(part.get("Content-Disposition")) try: # get the email body body = part.get_payload(decode=True).decode() except: pass if content_type == "text/plain" and "attachment" not in content_disposition: # print text/plain emails and skip attachments print(body) elif "attachment" in content_disposition: # download attachment filename = part.get_filename() if filename: if not os.path.isdir(subject): # make a folder for this email (named after the subject) os.mkdir(subject) filepath = os.path.join(subject, filename) # download attachment and save it open(filepath, "wb").write(part.get_payload(decode=True)) else: # extract content type of email content_type = msg.get_content_type() # get the email body body = msg.get_payload(decode=True).decode() if content_type == "text/plain": # print only text email parts print(body) if content_type == "text/html": # if it's HTML, create a new HTML file and open it in browser if not os.path.isdir(subject): # make a folder for this email (named after the subject) os.mkdir(subject) filename = "{}.html".format(subject[:50]) filepath = os.path.join(subject, filename) # write the file open(filepath, "w").write(body) # some data about mail to = msg.get("To") mail_from = msg.get("From") mail_date = msg.get("Date") mail_subject = msg.get("Subject") print("To =>", to) print("From =>", mail_from) print("Date =>", mail_date) print("=" * 100) # returning the useful values return (filepath, body, to, mail_from, mail_date, mail_subject)
class gmailPy(object): def __init__(self): self.IMAP_SERVER = 'imap.gmail.com' self.ssl = True self.myIMAPc = None self.response = None self.folders = [] def login(self, username, password): self.myIMAPc = IMAPClient(self.IMAP_SERVER, ssl=self.ssl) self.myIMAPc.login(username, password) # Returns a list of all the folders for a particular account def get_folders(self): self.response = self.myIMAPc.list_folders() for item in self.response: self.folders.append(item[2].strip('u')) return self.folders # Returns the total number of messages in a folder def get_mail_count(self, folder='Inbox'): self.response = self.myIMAPc.select_folder(folder, True) return self.response['EXISTS'] # Method to delete messages based on their size def delete_bigmail(self, folder='Inbox'): self.myIMAPc.select_folder(folder, False) # Gets all the message ids of the messages which are not deleted in the folder messages = self.myIMAPc.search(['NOT DELETED']) print "%d messages that aren't deleted" % len(messages) if len(messages) > 0: print "You can exit by entering 0 or pressing CTRL+C \n" else: print "There are no messages in the folder" # Gets the message sizes for all the message ids returned in previous step # Note: Just sends one request for all message ids with a return time < 10 ms self.response = self.myIMAPc.fetch(messages, ['RFC822.SIZE']) # Sorts the dictionary returned by fetch by size in descending order sorted_response = sorted(self.response.iteritems(), key=operator.itemgetter(1), reverse=True) count = 1 try: for item in sorted_response: # Gets the biggest message including headers, body, etc. big_message = self.myIMAPc.fetch(item[0], ['RFC822']) for msgid, data in big_message.iteritems(): msg_string = data['RFC822'] # Parses the message string using email library msg = email.message_from_string(msg_string) val = dict(self.response[msgid])['RFC822.SIZE'] print 'ID %d: From: %s Date: %s' % (msgid, msg['From'], msg['date']) print 'To: %s' % (msg['To']) print 'Subject: %s' % (msg['Subject']) print 'Size: %d bytes \n' % (val) user_del = raw_input("Do you want to delete this message?(Y/N): ") if user_del == 'Y': self.delete_message(msgid) if count == len(sorted_response): print "There are no more messages" else: print "\nMoving on to the next biggest message >>> \n" elif user_del == '0': print "Program exiting" sys.exit() else: if count == len(sorted_response): print "There are no more messages" else: print "\nMoving on to the next biggest message >>> \n" count += 1 except KeyboardInterrupt: print "Program exiting" sys.exit() # Method to delete messages based on their size with a search criteria def delete_bigmail_search(self, folder='Inbox', command='', criteria=''): self.myIMAPc.select_folder(folder, False) # Gets all the message ids from the server based on the search criteria messages = self.myIMAPc.search('%s "%s"' % (command, criteria)) print "%d messages that match --> %s: %s" % (len(messages), command, criteria) if len(messages) > 0: print "You can exit by entering 0 or pressing CTRL+C \n" else: print "There are no messages in that matched your search criteria" # Gets the message sizes for all the message ids returned in previous step # Note: Just sends one request for all message ids with a return time < 10 ms self.response = self.myIMAPc.fetch(messages, ['RFC822.SIZE']) # Sorts the messages in decending order of their sizes sorted_response = sorted(self.response.iteritems(), key=operator.itemgetter(1), reverse=True) count = 1 try: for item in sorted_response: # Gets the entire content for the biggest message identified big_message = self.myIMAPc.fetch(item[0], ['RFC822']) for msgid, data in big_message.iteritems(): msg_string = data['RFC822'] msg = email.message_from_string(msg_string) val = dict(self.response[msgid])['RFC822.SIZE'] print 'ID %d: From: %s Date: %s' % (msgid, msg['From'], msg['date']) print 'To: %s' % (msg['To']) print 'Subject: %s' % (msg['Subject']) print 'Size: %d bytes \n' % (val) user_del = raw_input("Do you want to delete this message?(Y/N): ") if user_del == 'Y': self.delete_message(msgid) if count == len(sorted_response): print "There are no more messages" else: print "\nMoving on to the next biggest message >>> \n" elif user_del == '0': print "Program exiting" sys.exit() else: if count == len(sorted_response): print "There are no more messages" else: print "\nMoving on to the next biggest message >>> \n" count += 1 except KeyboardInterrupt: print "Program exiting" sys.exit() # Deletes a message in the current folder based on msg id def delete_message(self, id): try: self.myIMAPc.delete_messages([id]) self.myIMAPc.expunge() print "Message deleted" except IMAPClient.Error as err: print "Message deletion failed" print err # Renames a folder def rename_folder(self, oldfolder, newfolder): try: self.myIMAPc.rename_folder(oldfolder, newfolder) print "Folder %s renamed to %s" % (oldfolder, newfolder) except IMAPClient.Error as err: print "Folder renaming failed" print err # Creates a new folder def create_folder(self, folder): try: self.myIMAPc.create_folder(folder) print "New folder %s created" % folder except IMAPClient.Error as err: print "Folder creation failed" print err # Deletes a folder def delete_folder(self, folder): try: self.myIMAPc.delete_folder(folder) print "Folder %s deleted" % folder except IMAPClient.Error as err: print "Folder deletion failed" print err # Creates a new folder and copies the content from the two folders that need to be merged # Then deletes the old folders def merge_folders(self, merged_folder, folder_1, folder_2): try: self.create_folder(merged_folder) # Selects the folder with read/write permission self.myIMAPc.select_folder(folder_1, True) messages = self.myIMAPc.search(['NOT DELETED']) print "Moving %d messages from %s to %s" % (len(messages), folder_1, merged_folder) self.myIMAPc.copy(messages, merged_folder) self.myIMAPc.select_folder(folder_2, True) messages = self.myIMAPc.search(['NOT DELETED']) print "Moving %d messages from %s to %s" % (len(messages), folder_2, merged_folder) self.myIMAPc.copy(messages, merged_folder) print "Deleting %s and %s..." % (folder_1, folder_2) self.delete_folder(folder_1) self.delete_folder(folder_2) print "Merge folder operation succeeded" except IMAPClient.Error as err: print "Merge operation failed" print err def logout(self): self.myIMAPc.logout()