def remove_attachments(host, username, password, folder_uids): server = IMAPClient(host) server.login(username, password) # trash_folder = server.find_special_folder(imapclient.TRASH) for folder_name, uids in folder_uids.items(): server.select_folder(folder_name) to_fetch = ["RFC822", "FLAGS", "INTERNALDATE"] fetched = server.fetch(uids, to_fetch) for uid, msg in fetched.items(): email_message = email.message_from_bytes(msg[b"RFC822"]) final_msg = set_email_payload(email_message) # server.move(uid, trash_folder) # server.expunge(uid) server.delete_messages(uid) server.append( folder="INBOX", msg=final_msg.as_string().encode(), flags=msg[b"FLAGS"], msg_time=msg[b"INTERNALDATE"], ) server.unselect_folder() server.logout()
def parse(self): use_ssl = True if self.config["EMAIL"]["useSSL"] else False server = IMAPClient(self.config["EMAIL"]["servername"], ssl=use_ssl) server.login(self.config["EMAIL"]["username"], self.config["EMAIL"]["password"]) logging.getLogger().debug("connected to IMAP server") select_info = server.select_folder("INBOX") # get list of fitting messages messages = server.search(["NOT", "DELETED", "SUBJECT", self.config["EMAIL"]["subject"]]) logging.getLogger().info("%d email message(s) found" % len(messages)) # loop through all messages for msgid in messages: # download it response = server.fetch(msgid, ["RFC822"]) msg = email.message_from_bytes(response[msgid][b"RFC822"]) self.__process_message(msg) # delete messages? if len(messages) > 0 and int(self.config["EMAIL"]["deleteAfterProcessing"]): if int(self.config["EMAIL"]["deleteAfterProcessing"]) > 1: messages = messages[:-1] server.delete_messages(messages) if self.config["EMAIL"]["expungeMailbox"]: server.expunge() logging.getLogger().info("Deleted email message(s) from server") server.logout()
def getMail(): # SECRET = getSecret() SECRET = "{0}".format(getSecret()) # server = IMAPClient("imap.gmail.com", use_uid=True, ssl=True) server = IMAPClient("imap.comcast.net", use_uid=True, ssl=True) server.login(username, SECRET) select_info = server.select_folder('INBOX') # print('%d messages in INBOX' % select_info['EXISTS']) # messages = server.search(['NOT', 'DELETED']) # print("%d messages that aren't deleted" % len(messages)) theMsgs = [] response = server.fetch(messages, ['RFC822']) for messagegId,data in response.iteritems(): messageString = data['RFC822'] msgStringParsed = email.message_from_string(messageString) messageFrom = msgStringParsed['From'] messageSubj = msgStringParsed['Subject'] bodytext='' for part in msgStringParsed.walk(): if part.get_content_type() == "text/plain": bodytext=part.get_payload().strip() theMsgs.append({'from':messageFrom, 'subj':messageSubj.strip(), 'body':bodytext}) server.delete_messages(response.keys()) server.logout() return theMsgs
def DeleteMail(): client = IMAPClient('imap.googlemail.com', use_uid=True, ssl=True) client.login(FROM, Decode(PASSMAIL)) folders = [ 'INBOX', '[Gmail]/Drafts', '[Gmail]/Important', '[Gmail]/Sent Mail', '[Gmail]/Spam', '[Gmail]/Starred', '[Gmail]/Trash' ] #for f in folders: fold = client.select_folder(folders[3]) print(client.search()) res = client.delete_messages(client.search()) res = client.expunge() client.close_folder() fold = client.select_folder(folders[6]) print(client.search()) res = client.delete_messages(client.search()) res = client.expunge() client.close_folder() #Google automatically will move deleted messages to "All Mail" folder. #Now we can remove all messages from "All Mail" client.select_folder("[Gmail]/All Mail") client.set_gmail_labels(client.search(), '\\Trash') client.delete_messages(client.search()) client.expunge() client.logout() print("Sent mails are deleted!")
class GmailImapClient(object): """Imap client with some specific methods for working with gmail""" IMAP_SERVER = "imap.gmail.com" IMAP_SERVER_PORT = "993" def __init__(self, email_address, password): self.client = IMAPClient(self.IMAP_SERVER, use_uid=True, ssl=True) self.email_address = email_address self.password = password self.messages_for_this_session = [] self._login() def search(self, from_address, to_address, subject, since=datetime.utcnow()-timedelta(minutes=1)): """Search for emails on an IMAP server""" return self.emails_from_messages( self.client.search( [ 'FROM "%s"' % (from_address,), 'TO "%s"' % (to_address,), 'SUBJECT "%s"' % (subject,), 'SINCE %s' % (since.strftime('%d-%b-%Y'),), ], ) ) def _login(self): """Login to imap server""" self.client.login(self.email_address, self.password) self.client.select_folder("INBOX") def delete_seen_messages(self): """Delete messages that have been accessed with this client""" self.client.delete_messages(self.messages_for_this_session) self.client.expunge() def gmail_search(self, query): """Search the gmail imap server using gmail queries""" self.client.logout() self.client = IMAPClient(self.IMAP_SERVER, use_uid=True, ssl=True) self._login() # Can use full gmail queries like 'has:attachment in:unread' messages = self.client.gmail_search(query) self.messages_for_this_session.append(messages) # We recreate a whole connection after querying gmail because # otherwise it caches our search results forever self.client.logout() self.client = IMAPClient(self.IMAP_SERVER, use_uid=True, ssl=True) self._login() return self.emails_from_messages(messages) def emails_from_messages(self, messages): """Convert a list of IMAP messages into email objects""" response = self.client.fetch(messages, ["RFC822"]) return [ email.message_from_string(data["RFC822"]) for _, data in response.items() ]
def random_mail(logged_in_client: IMAPClient, config): ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ssl_context.verify_flags = ssl.CERT_OPTIONAL # send message server: smtplib.SMTP = smtplib.SMTP(config["hostname"], config["smtp_port"]) if config["ssl"]: server.starttls(context=ssl_context) next_uid = logged_in_client.select_folder("INBOX", readonly=True)[b"UIDNEXT"] server.login("*****@*****.**", "test0") message = """\\ Subject: Hi there This message is sent from Python.""" server.sendmail("*****@*****.**", "*****@*****.**", message) wait_till_mail_appears(logged_in_client, uid=next_uid) yield next_uid logged_in_client.select_folder(EmailFolders.INBOX) logged_in_client.delete_messages(next_uid) logged_in_client.expunge()
def check_photo_request(hostname, username, password, boss): from imapclient import IMAPClient import email from email.utils import parseaddr server = IMAPClient(hostname, use_uid=True, ssl=True) server.login(username, password) select_info = server.select_folder('Inbox') msg_count = select_info[b'EXISTS'] if msg_count == 0: return False command_photo = False messages = server.search() for msgid, data in server.fetch(messages, [b'RFC822']).items(): msg = email.message_from_bytes(data[b'RFC822']) subject = str(msg['Subject']) mfrom = str(parseaddr(msg['From'])[1]) if 'photo' == subject.strip().lower() and boss == mfrom.strip().lower( ): command_photo = True break server.delete_messages(messages, silent=True) server.expunge(messages) server.logout() return command_photo
def fetch_test_submissions(previous_history, config): """ fetch emails from IMAP server using the given configuration each email is parsed to see whether it matches a submission if so, its token is extracted and checked against the given history. if found, the email is deleted from the server and the entry is removed from the history. any entries left in the history are returned """ context = create_default_context() context.check_hostname = False context.verify_mode = False server = IMAPClient(config['imap_host'], use_uid=True, ssl=True, ssl_context=context) server.login(config['imap_user'], config['imap_passwd']) server.select_folder('INBOX') history = previous_history.copy() candidates = server.fetch(server.search(criteria='NOT DELETED SUBJECT "Drop ID"'), ['BODY[HEADER.FIELDS (SUBJECT)]']) for imap_id, message in candidates.items(): subject = message.get('BODY[HEADER.FIELDS (SUBJECT)]', 'Subject: ') try: drop_id = find_drop_id.findall(subject)[0] except IndexError: # ignore emails that are not test submissions continue print "Found submission '%s'" % drop_id server.delete_messages([imap_id]) try: del history[drop_id] except KeyError: pass # TODO: log this? server.logout() return history
class GmailImapClient(object): """Imap client with some specific methods for working with gmail""" IMAP_SERVER = "imap.gmail.com" IMAP_SERVER_PORT = "993" def __init__(self, email_address, password): self.client = IMAPClient(self.IMAP_SERVER, use_uid=True, ssl=True) self.email_address = email_address self.password = password self.messages_for_this_session = [] self._login() def search(self, from_address, to_address, subject, since=datetime.utcnow() - timedelta(minutes=1)): """Search for emails on an IMAP server""" return self.emails_from_messages( self.client.search([ 'FROM "%s"' % (from_address, ), 'TO "%s"' % (to_address, ), 'SUBJECT "%s"' % (subject, ), 'SINCE %s' % (since.strftime('%d-%b-%Y'), ), ], )) def _login(self): """Login to imap server""" self.client.login(self.email_address, self.password) self.client.select_folder("INBOX") def delete_seen_messages(self): """Delete messages that have been accessed with this client""" self.client.delete_messages(self.messages_for_this_session) self.client.expunge() def gmail_search(self, query): """Search the gmail imap server using gmail queries""" self.client.logout() self.client = IMAPClient(self.IMAP_SERVER, use_uid=True, ssl=True) self._login() # Can use full gmail queries like 'has:attachment in:unread' messages = self.client.gmail_search(query) self.messages_for_this_session.append(messages) # We recreate a whole connection after querying gmail because # otherwise it caches our search results forever self.client.logout() self.client = IMAPClient(self.IMAP_SERVER, use_uid=True, ssl=True) self._login() return self.emails_from_messages(messages) def emails_from_messages(self, messages): """Convert a list of IMAP messages into email objects""" response = self.client.fetch(messages, ["RFC822"]) return [ email.message_from_string(data["RFC822"]) for _, data in response.items() ]
def fetch_test_submissions(previous_history, config): """ fetch emails from IMAP server using the given configuration each email is parsed to see whether it matches a submission if so, its token is extracted and checked against the given history. if found, the email is deleted from the server and the entry is removed from the history. any entries left in the history are returned """ server = IMAPClient(config['imap_host'], use_uid=True, ssl=True) server.login(config['imap_user'], config['imap_passwd']) server.select_folder('INBOX') history = previous_history.copy() candidates = server.fetch( server.search(criteria=['NOT DELETED', 'SUBJECT "Drop ID"']), ['BODY[HEADER.FIELDS (SUBJECT)]']) for imap_id, message in candidates.items(): subject = message.get('BODY[HEADER.FIELDS (SUBJECT)]', 'Subject: ') try: drop_id = find_drop_id.findall(subject)[0] except IndexError: # ignore emails that are not test submissions continue print "Found submission '%s'" % drop_id server.delete_messages([imap_id]) try: del history[drop_id] except KeyError: pass # TODO: log this? server.logout() return history
def parse(self): server = IMAPClient(self.config['EMAIL']['servername']) server.login(self.config['EMAIL']['username'], self.config['EMAIL']['password']) logging.getLogger().debug("connected to IMAP server") select_info = server.select_folder('INBOX') # get list of fitting messages messages = server.search(['NOT DELETED', 'SUBJECT "' + self.config['EMAIL']['subject'] + '"']) logging.getLogger().info("%d email message(s) found" % len(messages)) # loop through all messages for msgid in messages: # download it response = server.fetch(msgid, ['RFC822']) msg = email.message_from_bytes(response[msgid][b'RFC822']) self.__process_message(msg) # delete messages? if len(messages) > 0 and int(self.config['EMAIL']['deleteAfterProcessing']): if int(self.config['EMAIL']['deleteAfterProcessing']) > 1: messages = messages[:-1] server.delete_messages(messages) if self.config['EMAIL']['expungeMailbox']: server.expunge() logging.getLogger().info("Deleted email message(s) from server") server.logout()
def delete_unsub_email(host, sender, password, to): server = IMAPClient(host) server.login(sender, password) sent_folder = server.find_special_folder(imapclient.SENT) server.select_folder(sent_folder) messages = server.search(['TO', to]) server.delete_messages(messages) server.logout
def clear_email_for_address(self, email_address, content_filter=None): from imapclient import IMAPClient server = IMAPClient(IMAP_HOST, ssl=True) messages_to_delete = [] for m_id, parsed_headers, body_text in self.all_emails(server): if email_address in parsed_headers['To']: if content_filter is None or content_filter in body_text: messages_to_delete.append(m_id) server.delete_messages(messages_to_delete)
def fetch_incidents(client: IMAPClient, last_run: dict, first_fetch_time: str, include_raw_body: bool, with_headers: bool, permitted_from_addresses: str, permitted_from_domains: str, delete_processed: bool, limit: int, save_file: bool) -> Tuple[dict, list]: """ This function will execute each interval (default is 1 minute). The search is based on the criteria of the SINCE time and the UID. We will always store the latest email message UID that came up in the search, even if it will not be ingested as incident (can happen in the first fetch where the email messages that were returned from the search are before the value that was set in the first fetch parameter). This is required because the SINCE criterion disregards the time and timezone (i.e. considers only the date), so it might be that in the first fetch we will fetch only email messages that are occurred before the first fetch time (could also happen that the limit parameter, which is implemented in the code and cannot be passed as a criterion to the search, causes us to keep retrieving the same email messages in the search result) The SINCE criterion will be sent only for the first fetch, and then the fetch will be by UID We will continue using the first fetch time as it may take more than one fetch interval to get to the mail that was actually received after the first fetch time Args: client: IMAP client last_run: The greatest incident created_time we fetched from last fetch first_fetch_time: If last_run is None then fetch all incidents since first_fetch_time include_raw_body: Whether to include the raw body of the mail in the incident's body with_headers: Whether to add headers to the search query permitted_from_addresses: A string representation of list of mail addresses to fetch from permitted_from_domains: A string representation list of domains to fetch from delete_processed: Whether to delete processed mails limit: The maximum number of incidents to fetch each time save_file: Whether to save the .eml file of the incident's mail Returns: next_run: This will be last_run in the next fetch-incidents incidents: Incidents that will be created in Demisto """ uid_to_fetch_from = last_run.get('last_uid', 1) time_to_fetch_from = parse(last_run.get('last_fetch', f'{first_fetch_time} UTC'), settings={'TIMEZONE': 'UTC'}) mails_fetched, messages, uid_to_fetch_from = fetch_mails( client=client, include_raw_body=include_raw_body, time_to_fetch_from=time_to_fetch_from, limit=limit, with_headers=with_headers, permitted_from_addresses=permitted_from_addresses, permitted_from_domains=permitted_from_domains, save_file=save_file, uid_to_fetch_from=uid_to_fetch_from) incidents = [] for mail in mails_fetched: incidents.append(mail.convert_to_incident()) uid_to_fetch_from = max(uid_to_fetch_from, mail.id) next_run = {'last_uid': uid_to_fetch_from} if delete_processed: client.delete_messages(messages) return next_run, incidents
def delete_all_inbox(): try: speak('deleting all mails sir') session = IMAPClient(reciever_host, ssl=True, port=993) session.login(user, password) session.select_folder('Inbox') delmail = session.search('ALL') session.delete_messages(delmail) main_page(mainpagetext3) except: error1()
def mail_check(): # login to mailserver server = IMAPClient(HOSTNAME, use_uid=True, ssl=True) server.login(USERNAME, PASSWORD) # select our MAILBOX and looked for unread messages unseen = server.folder_status(MAILBOX, ['UNSEEN']) newmail_count = (unseen[b'UNSEEN']) print('%d unseen messages' % newmail_count) select_info = server.select_folder('INBOX') print('%d messages in INBOX' % select_info[b'EXISTS']) messages_from_kerem = server.search(['FROM', FROM_KEREM]) print("%d messages from Kerem" % len(messages_from_kerem)) messages_from_thomas = server.search(['FROM', FROM_THOMAS]) print("%d messages from Thomas" % len(messages_from_thomas)) if len(messages_from_kerem) > 0: for mail_id, data in server.fetch(messages_from_kerem, ['ENVELOPE', 'BODY[TEXT]']).items(): envelope = data[b'ENVELOPE'] body = data[b'BODY[TEXT]'] print("%d messages from Kerem" % len(messages_from_kerem)) print('ID #%d: "%s" ' % (mail_id, envelope.subject.decode())) if envelope.subject.decode() == "Temp": cmd_beginning = 'echo Temp = ' cmd_end = 'C | msmtp ' + FROM_KEREM cmd_temp = read_temp() cmd = cmd_beginning + cmd_temp + cmd_end os.system(cmd) server.delete_messages(mail_id, False) print("Mail deleted") if len(messages_from_thomas) > 0: for mail_id, data in server.fetch(messages_from_thomas, ['ENVELOPE', 'BODY[TEXT]']).items(): envelope = data[b'ENVELOPE'] body = data[b'BODY[TEXT]'] print("%d messages from Thomas" % len(messages_from_thomas)) print('ID #%d: "%s" ' % (mail_id, envelope.subject.decode())) if envelope.subject.decode() == "Temp": cmd_beginning = 'echo Temp = ' cmd_end = 'C | msmtp ' + FROM_THOMAS cmd_temp = read_temp() cmd = cmd_beginning + cmd_temp + cmd_end os.system(cmd) server.delete_messages(mail_id, False) print("Mail deleted")
def _pop_email_for_client_once(self, email_address, content_filter=None): from imapclient import IMAPClient message = None messages_to_delete = [] server = IMAPClient(IMAP_HOST, ssl=True) for m_id, parsed_headers, body_text in self.all_emails(server): if email_address in parsed_headers['To']: body_text = body_text.replace('\r', '') body_text = body_text.replace('=\n', '') if content_filter is None or content_filter in body_text: message = (parsed_headers['From'], parsed_headers['To'], parsed_headers['Subject'], body_text) messages_to_delete.append(m_id) server.delete_messages(messages_to_delete) return message
def main(): mail = IMAPClient(config['mail']['host'], use_uid=True) mail.login(config['mail']['user'], config['mail']['password']) mail.select_folder('INBOX') messages = mail.search(['ALL']) if len(messages) > 0: response = mail.fetch(messages, ['BODY.PEEK[HEADER.FIELDS (TO)]', 'RFC822']) mandrill_client = mandrill.Mandrill(config['mandrill']['password']) for msgnum, data in response.items(): do_forward(mandrill_client, data[b'BODY[HEADER.FIELDS (TO)]'], data[b'RFC822']) mail.delete_messages(messages) mail.expunge() return True else: print('No messages') return False
def fetch_incidents(client: IMAPClient, last_run: dict, first_fetch_time: str, include_raw_body: bool, permitted_from_addresses: str, permitted_from_domains: str, delete_processed: bool, limit: int, save_file: bool) -> Tuple[dict, list]: """ This function will execute each interval (default is 1 minute). Args: client: IMAP client last_run: The greatest incident created_time we fetched from last fetch first_fetch_time: If last_run is None then fetch all incidents since first_fetch_time include_raw_body: Whether to include the raw body of the mail in the incident's body permitted_from_addresses: A string representation of list of mail addresses to fetch from permitted_from_domains: A string representation list of domains to fetch from delete_processed: Whether to delete processed mails limit: The maximum number of incidents to fetch each time save_file: Whether to save the .eml file of the incident's mail Returns: next_run: This will be last_run in the next fetch-incidents incidents: Incidents that will be created in Demisto """ # Get the last fetch time, if exists last_fetch = last_run.get('last_fetch') # Handle first time fetch if last_fetch is None: latest_created_time = parse(f'{first_fetch_time} UTC') else: latest_created_time = datetime.fromisoformat(last_fetch) mails_fetched, messages = fetch_mails( client=client, include_raw_body=include_raw_body, first_fetch_time=latest_created_time, limit=limit, permitted_from_addresses=permitted_from_addresses, permitted_from_domains=permitted_from_domains, save_file=save_file) if mails_fetched: latest_created_time = max(mails_fetched, key=lambda x: x.date).date incidents = [mail.convert_to_incident() for mail in mails_fetched] next_run = {'last_fetch': latest_created_time.isoformat()} if delete_processed: client.delete_messages(messages) return next_run, incidents
def _pop_email_for_client_once(self, email_address, content_filter=None): from imapclient import IMAPClient message = None messages_to_delete = [] server = IMAPClient(IMAP_HOST, ssl=True) for m_id, parsed_headers, body_text in self.all_emails(server): if email_address in parsed_headers['To']: body_text = body_text.replace('\r', '') body_text = body_text.replace('=\n', '') if content_filter is None or content_filter in body_text: message = ( parsed_headers['From'], parsed_headers['To'], parsed_headers['Subject'], body_text ) messages_to_delete.append(m_id) server.delete_messages(messages_to_delete) return message
class ReadManager: def __init__(self, config_dict): self.conn = IMAPClient(host="imap.gmail.com") self.conn.login(config_dict['incoming username'], config_dict['incoming password']) self.conn.select_folder('INBOX') def check_emails(self, who_from): new_messages = self.conn.search([['FROM', who_from]]) emails = [] for msgid, raw_email in self.conn.fetch(new_messages, 'RFC822').items(): emails.append(ReadEmail(msgid, raw_email)) self.conn.delete_messages(new_messages) self.conn.expunge() self.conn.noop() return emails def logout(self): self.conn.logout()
def delete_mail(event, context): # TODO implement email_id = os.environ['Email_ID'] mail_list = MailList() mail_list = mail_list.spam_mail_list obj = IMAPClient('imap.gmail.com', ssl=True) obj.login(email_id, DECRYPTED) select_info = obj.select_folder('Inbox') mails_before_deletion = select_info[b'EXISTS'] print('%d mails in INBOX before deletion' % mails_before_deletion) for i in mail_list: msg_ids = obj.search(['FROM', i]) if (len(msg_ids)) != 0: print('%d mails deleted from %s' % (len(msg_ids), i)) obj.delete_messages(msg_ids) select_info1 = obj.select_folder('Inbox') mails_after_deletion = select_info1[b'EXISTS'] print('%d mails in INBOX after deletion' % mails_after_deletion) print('Total number of mails deleted : %d' % (mails_before_deletion - mails_after_deletion)) obj.expunge() obj.logout() return {'statusCode': 200, 'body': msg_ids}
def delete_msg(unseen_for_days=0): mailbox = IMAPClient('imap.gmail.com', ssl=True, port=993) mailbox.login(EMAIL_ADRESS, EMAIL_PASSWORD) inbox_mails = mailbox.select_folder('INBOX') print('You have total of %d mails in your inbox' % inbox_mails[b'EXISTS']) seen_msg = mailbox.search('SEEN') mailbox.delete_messages(seen_msg) print(f'{len(seen_msg)} already seen messages has been deleted') unseen_msg = mailbox.search('UNSEEN') no_unseen_deleted = 0 unseen_del = [] for id, data in mailbox.fetch(unseen_msg, ['INTERNALDATE']).items(): date_of_recipt = data[b'INTERNALDATE'] delta = (datetime.now() - date_of_recipt).days if delta > unseen_for_days: unseen_del.append(id) no_unseen_deleted += 1 if no_unseen_deleted > 0: mailbox.delete_messages(unseen_del) print( f'{no_unseen_deleted} unseen for more than {unseen_for_days} days mails deleted.' ) mailbox.logout()
class SpamTrapMREC(): def __init__(self, imapHost=None, imapUser=None, imapPass=None, imapFolder='INBOX', smtpHost=None, smtpUser=None, smtpPass=None, emailFrom=None): # Useful pre-loaded lists self.IMAPTAGS = ['INTERNALDATE', 'ENVELOPE', 'RFC822'] self.CRITERIA = ['NOT', 'DELETED'] # Services self.storage = Storage() self.util = Util() # yeah, this could be better. self.ironports = { 'iron1': IronportSSH(host='someironporthost'), 'iron2': IronportSSH(host='anotherironporthost') } # TODO: Validate self.emailFrom = emailFrom self.imapHost = imapHost self.imapUser = imapUser self.imapPass = imapPass self.smtpHost = smtpHost self.smtpUser = smtpUser self.smtpPass = smtpPass self.imapFolder = imapFolder # Setup IMAP print("[INFO] Setting up IMAP") self.client = IMAPClient(host=self.imapHost) self.client.login(self.imapUser, imapPass) # pprint(self.client.list_folders()) # self.client.select_folder('Junk') self.client.select_folder(self.imapFolder) print("[INFO] IMAP Ready for {} Folder".format(self.imapFolder)) self.storage.updateExecutionTime() def finish(self): self.client.logout() print() def displayMessageDetails(self, message=None, id=None): if message is None: m = self.msg id = self.msgid else: m = message[id] e = m[b'ENVELOPE'] print("[INFO] Message ID # {} Details:".format(id[0])) for fromItem in e.from_: print( "[INFO] FROM : {}".format(fromItem)) # TODO: needs more work if hasattr(e.subject, 'decode'): print("[INFO] SUBJECT: {}".format(e.subject.decode('utf-8'))) def listMessages(self, folder=None): if folder is not None: self.client.select_folder(folder) ids = self.client.search(self.CRITERIA) msgs = self.client.fetch(ids, self.IMAPTAGS) print("[INFO] {} messages - Criteria: {}".format( len(msgs), self.CRITERIA)) for id in ids: self.msg = msgs[id] self.msgid = [id] self.displayMessageDetails() def getOneMessage(self, spam=False): if spam is True: print("[INFO] Selecting SPAM Folder") self.client.select_folder('Spam') try: self.msgid = [self.client.search(self.CRITERIA)[0]] except: self.msgid = None if self.msgid is None: print("[INFO] No messages.") return (None) print("[INFO] Got one message (ID # {})".format(self.msgid[0])) try: self.msg = self.client.fetch(self.msgid, self.IMAPTAGS)[self.msgid[0]] except: print("[ERR ] No such msg ID # {}. Exiting.".format(self.msgid[0])) sys.exit(1) self.getEnvelope() return (self.msg) def getEnvelope(self): self._from = str(self.msg[b'ENVELOPE'].from_[0]) def analyzeMessage(self): print('[INFO] Analyzing message...') rfc822 = self.msg[b'RFC822'] assassin = SpamAssassin(rfc822) if (assassin.is_spam()): # TODO: set self.spam, self.phishing, etc self.msg_is_spam = True print("[INFO] SpamaAssassin claims its SPAM") def deleteMessage(self, ask=False): delmsg = True if ask: x = self.util.input_sn('Eliminar el mensaje?', default='s') if x is False: delmsg = False if delmsg: self.client.delete_messages(self.msgid) def refreshCiscoDictionaries(self): for spammer in self.storage.getSendersDict(): for host in self.ironports.keys(): print("[INFO:IronPort:{}] Adding {}".format(host, spammer)) self.ironports[host].add_to_dictionary(dictname=IRONDICT, what=spammer, verbose=True) def actOnMessage(self): print('[INFO] Acting on message') self.storage.increment_from(self._from) spammer = self.util.extract_address(self._from) # TODO: may need fixing print('[INFO] Spammer is {}'.format(spammer)) for host in self.ironports.keys(): self.ironports[host].add_to_dictionary(dictname=IRONDICT, what=spammer, verbose=True) self.sendEmail(to=CISCO_ADDR['spam'], subject='SPAMTRAP-received email - RFC822 attached') self.storage.updateTrappedTime() def sendEmail(self, to=None, subject=None): if to is None or subject is None: sys.exit(2) msg = MIMEMultipart() msg['From'] = self.emailFrom msg['To'] = to msg['Subject'] = subject body = """ Hello Team. This is spamtrap service at blahblah Please see attached for spamtrap-caught unwanted email. You might contact a human being at INFOSEC <*****@*****.**> Thanks. Sincerely, SPAMTRAP Service at blah example """ msg.attach(MIMEText(body, 'plain')) filename = "unwanted_email_id_{}.txt".format(self.msgid[0]) attachment = self.msg[b'RFC822'] part = MIMEBase('application', 'octet-stream') part.set_payload(attachment) encoders.encode_base64(part) part.add_header('Content-Disposition', "attachment; filename={}".format(filename)) msg.attach(part) try: server = smtplib.SMTP(self.smtpHost, 25) server.starttls() server.login(self.smtpUser, self.smtpPass) text = msg.as_string() server.sendmail(self.emailFrom, to, text) server.quit() except smtplib.SMTPException as e: print(str(e)) print("[ERROR] Cannot send email") return print("[INFO] Email sent") print("[INFO] From={}".format(self.emailFrom)) print("[INFO] To={}".format(to)) print("[INFO] Subject={}".format(subject))
<html> <head> </head> <ul style="font-family: trebuchet;"> <h2>Hi! Here's your workout for today:</h2> <ul style="border: 1px solid black; padding: 40px;"> {} </ul> </body> </html> '''.format(items) print('formatted email') list1 = MIMEText(list1, 'html') email(email=n, content=list1.as_string()) print('email sent') srvr.delete_messages(hh) print('deleted') whichone.close() whichone = open('workout.txt', 'w') whichone.write('1') whichone.close() srvr.logout() time.sleep(10) else: print('chose workout') items = ["\n <li>{}</li>".format(s) for s in wk[1]] items = "".join(items) list1 = '''\ <html> <head> </head>
'FROM "*****@*****.**"', 'SINCE %s' % cutoff.strftime('%d-%b-%Y') ]) ## Fetch the messages if verbose: print 'Fetching e-mails...' response = server.fetch(messages, ['RFC822']) for msgid, data in response.iteritems(): msg = data['RFC822'] if verbose: mail = email.message_from_string(msg) print '...got e-mail: %s' % mail['Subject'] ## Processing/Success/Failure e-mail check if msg.find('"' + crippledname + '" was successfully uploaded to the system') > 0: if verbose: print 'This is a processing e-mail, just delete it' server.delete_messages(msgid) elif msg.find('Congratulations! Your uploaded file "' + crippledname + '" was processed successfully.') > 0: if verbose: print 'This is a success e-mail, got the URL' start = msg.find('?key=') end = msg.find('&fixedfile=1') url = 'http://cloud.netfabb.com/download.php' + msg[start:end] server.delete_messages(msgid) go = False # Don't break now, let this forloop end, so all messages are deleted elif msg.find('Unfortunately, your uploaded file "' + crippledname + '" was not processed successfully.') > 0: if verbose: print 'This is a failure e-mail' start = msg.find('The system logged the short error message') end = msg[start:].find('If you have further questions') print >> sys.stderr, msg[start:start + end -
sender = email_message.get('From') subject = email_message.get('Subject') print(sender, ' ', subject) #If we find the email, we stop looking and mark NJ as being completed if sender.find(TargetEmailAddress) != -1 and subject.find( TargetEmailSubject) != -1: print('Found the specified email', subject) EmailWasFound = True break else: print('Not a Match') #NOW WE DELETE ALL EMAILS - we do this so the next time we search, the email alert will not already be in there. server.delete_messages(messages) server.expunge() #We close the connection and disconnect from the IMAP server server.logout() #We've failed checking for emails except BaseException as e: print(e) #Send an email saying this failed and then exit sendcheckfailemail() sys.exit(1) #If we received the email, we exit and do nothing if EmailWasFound: print('Yay, We found it!')
server.login(USERNAME, PASSWORD) select_info = server.select_folder('INBOX') ## Search for relevant messages messages = server.search(['FROM "*****@*****.**"', 'SINCE %s' % cutoff.strftime('%d-%b-%Y')]) ## Fetch the messages if verbose: print 'Fetching e-mails...' response = server.fetch(messages, ['RFC822']) for msgid, data in response.iteritems(): msg = data['RFC822'] if verbose: mail = email.message_from_string(msg) print '...got e-mail: %s' % mail['Subject'] ## Processing/Success/Failure e-mail check if msg.find('"'+crippledname+'" was successfully uploaded to the system') > 0: if verbose: print 'This is a processing e-mail, just delete it' server.delete_messages(msgid) elif msg.find('Congratulations! Your uploaded file "'+crippledname+'" was processed successfully.') > 0: if verbose: print 'This is a success e-mail, got the URL' start = msg.find('?key=') end = msg.find('&fixedfile=1') url = 'http://cloud.netfabb.com/download.php'+msg[start:end] server.delete_messages(msgid) go = False # Don't break now, let this forloop end, so all messages are deleted elif msg.find('Unfortunately, your uploaded file "'+crippledname+'" was not processed successfully.') > 0: if verbose: print 'This is a failure e-mail' start = msg.find('The system logged the short error message') end = msg[start:].find('If you have further questions') print >> sys.stderr, msg[start:start+end-3] # -3 deletes whitesapce at the end server.delete_messages(msgid) exitus = True # Don't exit now, let this forloop end, so all messages are deleted if exitus: exit(1)
class EmailClient(object): def __init__(self, config): """ Create an email client abstraction configured for an account. config is a dict with keys: HOST USERNAME PASSWORD USE_SSL default=True FOLDER default='INBOX' SELECTORS default=['NOT DELETED'] """ self.config = {'USE_SLL': True, 'FOLDER': 'INBOX', 'SELECTORS': ['NOT DELETED']} self.config.update(config) def connect(self): self.server = IMAPClient(self.config['HOST'], use_uid=True, ssl=self.config['USE_SSL']) self.server.login(self.config['USERNAME'], self.config['PASSWORD']) select_info = self.server.select_folder(self.config['FOLDER']) def process_new_messages(self, debug=False): """ Get mesages from the server. Note: new information on existing uids will be ignored. For example, if the rfc_size changes (which is a strangely common occurrence), the new value will be ignored. """ if debug: print "searching" messages = self.server.search(self.config['SELECTORS']) if debug: print "done searching" self._process_messages(messages, debug=debug) def _process_messages(self, uids, move=False, debug=False): if debug: print "fetching" response = self.server.fetch(uids, ['FLAGS', 'RFC822', 'RFC822.SIZE']) for msg_uid, data in response.iteritems(): if debug: print "processing %s" % msg_uid with transaction.commit_on_success(): # extract data flags = data['FLAGS'] rfc_size = data['RFC822.SIZE'] raw_body = data['RFC822'] seq = data['SEQ'] # save objects email, _ = EmailMessage.objects.get_or_create( uid = msg_uid, username = self.config['USERNAME'], host = self.config['HOST'], defaults = { 'raw_body': raw_body, 'rfc_size': rfc_size, 'seq': data['SEQ'], } ) email.save() for flag in flags: EmailFlag.objects.get_or_create(email=email, flag=flag)[0].save() # move message if move: self.server.copy([msg_uid], 'auto_processed') self.server.delete_messages([msg_uid])
class MailPuller(object): def __init__(self, host, user, password): self._host = host self._user = user self._password = password self._server = IMAPClient(host, ssl=False) def login(self): try: self._server.login(self._user, self._password) except MailLoginError as err: raise MailLoginError( 'imapclient login error.Login info: host:{host}, user=:{user}.' ' Message: {err}'.format(host=self._host, user=self._user, err=err)) def pull_msgids(self, subject): """返回一个字典,字典key为messageid, value为发件人.若没有获取到则为空字典{}""" try: self._server.select_folder('INBOX') msgids = self._server.search(['UNDELETED', 'SUBJECT', subject]) envelopes = self._server.fetch(msgids, ['ENVELOPE']) except Exception as err: raise IMAPOperationError( "MailPuller.pull_msgids() run error. Message: {err}".format( err=err)) msgids_with_sender = {} for i in msgids: msgids_with_sender.update({ i: (envelopes[i][b'ENVELOPE'].sender[0].mailbox.decode('utf-8') + '@' + envelopes[i][b'ENVELOPE'].sender[0].host.decode('utf-8')) }) return msgids_with_sender def download(self, msgid): """返回 RFC822 格式的 str :param msgid: int :return: str 下载(fetch)后,邮件被标记为 SEEN""" try: return self._server.fetch( msgid, ['RFC822'])[msgid][b'RFC822'].decode('utf-8') except Exception as err: raise IMAPOperationError( "MailPuller.download() run error. Message: {err}".format( err=err)) def delete(self, msgids): """将邮件标记为 DELETED, 并未真正删除 :param msgids: int or list that item is int""" self._server.delete_messages(msgids) def logout(self): try: self._server.logout() except Exception: pass def __del__(self): # 对象被回收时,自动关闭邮箱服务器的链接 try: self._server.logout() except Exception: pass
#!/home/rajesh/projects/scrapping/web_crawling/bin/python3 from imapclient import IMAPClient import config mail = IMAPClient('imap.gmail.com', ssl=True, port=993) mail.login(config.getMailID(), config.getPasswd()) totalMail = mail.select_folder('Inbox') #Shows how many messages are there - both read and unread print('You have total %d messages in your folder' % totalMail[b'EXISTS']) delMsg = mail.search(('UNSEEN')) mail.delete_messages(delMsg) #Shows number of unread messages that have been deleted now print('%d unread messages in your folder have been deleted' % len(delMsg)) mail.logout()
class CuckooRequest(object): def __init__(self, message): self.message = message '''cuckooinbox config variables''' config = Config(cfg=os.path.join(CUCKOO_ROOT,"cuckooinbox","cuckooinbox.conf")) config = config.get('cuckooinbox') self.username = config['username'] self.passwd = config['passwd'] self.imap = config['imap'] self.imap_ssl = config['imap_ssl'] self.smtp_server = config['smtp'] self.interval = config['interval'] self.archive_folder = config['archive_folder'] self.email_whitelist = config['email_whitelist'] self.url_limit = config['url_limit'] self.attachment_limit = config['attachment_limit'] self.zip_reports = config['zip_reports'] self.zip_password = config['zip_password'] self.url_blacklist = config['url_blacklist'] self.url_file_backlist = config['url_file_backlist'] self.machine = config['machine'] '''imap variables''' self.server = IMAPClient(self.imap, use_uid=True, ssl=self.imap_ssl) self.server.login(self.username, self.passwd) self.attachment_counter = 0 '''message variables''' self.msg = MIMEMultipart() self.response_msg = MIMEMultipart() self.response_urls = [] self.response_attachments = [] self.sender = '' self.subject = '' self.cc_list = [] '''logging object''' self.log_entry = Logger('cuckooinbox.log') '''cuckoo variables''' self.taskids = [] self.db = Database() self.url_counter = 0 # tracks url count to not exceed url_limit def fetch(self, message): '''set retrieve folder''' select_info = self.server.select_folder('INBOX') '''fetch mail''' response = self.server.fetch(self.message, ['RFC822']) '''parse received email''' for msgid, data in response.iteritems(): msg_string = data['RFC822'] self.msg = email.message_from_string(msg_string) '''parse 'Name <*****@*****.**>' format''' if '<' in self.msg['From']: self.sender = self.msg['From'].split('<'[0])[-1][:-1] else: self.sender = self.msg['From'] self.subject = self.msg['Subject'] '''print and log successful receive''' self.log_entry.logEvent('[+] Received email ID: %d from %s [%s]' % (msgid, self.msg['From'], self.msg['Subject'])) '''save CC info for reply later''' if self.msg['Cc']: for address in self.msg['Cc'].split(', '): self.cc_list.append(address) self.log_entry.logEvent( '[*] Email \"%s\" from %s cc\'d the following addresses: %s' % (self.msg['Subject'],self.msg['From'],', '.join(str(copies) for copies in self.cc_list))) file_whitelist = ['exe', 'doc', 'docx', 'xls', 'xlsx', 'pdf', 'zip'] '''parse message elements''' for part in self.msg.walk(): if part.get_content_type() == 'text/plain': self.log_entry.logEvent( '[*] Email ID: %d has a plain text object.' % msgid) content = part.get_payload() self.processText(content) elif part.get_content_type() == 'text/html': self.log_entry.logEvent('[*] Email ID: %d has a html object.' % msgid) content = part.get_payload() self.processText(content) elif 'application' in part.get_content_type(): # email attachment has no filename if not part.get_param('name'): return 0 # cuckoo file analysis whitelist if not part.get_param('name').split('.'[0])[-1] in file_whitelist: break # increment and break if limit is reached if (self.attachment_limit != 0 and self.attachment_counter == self.attachment_limit): break self.attachment_counter += 1 self.log_entry.logEvent('[*] Email ID: %d has an attachment object.' % msgid) content = part.get_payload() file_name = part.get_param('name') self.processAttachment(content, file_name) '''archive email when done submitting cuckoo tasks''' try: self.archive(self.message) except: self.server.delete_messages(self.message) self.server.expunge() def processText(self, content): '''reformat quoted string mail to plain html''' body = quopri.decodestring(content) soup = BeautifulSoup(body) # todo analyze href spoof '''parse and analyze hyperlinks''' for url in soup.findAll('a'): # strip mailto links if url['href'].split(':'[0])[0] == 'mailto' : continue # strip blacklist links for item in self.url_blacklist.split(','): if item in url['href']: return 0 # strip blacklist link filetypes for item in self.url_file_backlist.split(','): if item in url['href'].split('.'[0])[-1]: return 0 else: self.response_urls.append(url['href']) if self.machine: task_id = self.db.add_url(url['href'], package="ie", timeout=15, machine=self.machine) else: task_id = self.db.add_url(url['href'], package="ie", timeout=15) if task_id: self.taskids.append(task_id) self.log_entry.logEvent('[+] URL \"%s\" added as task with ID %d' % (url['href'],task_id)) # increment counter and exit loop if limit is reached self.url_counter += 1 if (self.url_limit != 0 and self.url_counter == self.url_limit): return 0 else: self.log_entry.logEvent("[!] Error: adding task to database" % (url['href'],task_id)) break def processAttachment(self, content, filename): '''create temp file for analysis''' temp_file = tempfile.NamedTemporaryFile(prefix=filename.split('.'[0])[0], suffix='.' + filename.split('.'[0])[1]) temp_file.write(content) self.response_attachments.append(filename) '''add to cuckoo tasks''' task_id = self.db.add_path(temp_file.name, timeout=10, package=filename.split('.'[0])[1]) temp_file.flush() if task_id: self.taskids.append(task_id) self.log_entry.logEvent('[+] File \"%s\" added as task with ID %d' % (filename,task_id)) else: self.taskids.append(task_id) self.log_entry.logEvent("[!] Error adding task to database") '''make sure file gets submitted before we toss it''' timeout = time.time() + 120 while time.time() < timeout: if os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(task_id),"reports","report.html")): continue time.sleep(.25) temp_file.close() def archive(self, message): select_info = self.server.select_folder('INBOX') '''cleanup mailbox''' self.server.copy(self.message,self.archive_folder) self.server.delete_messages(self.message) self.server.expunge() def expunge(self, message): select_info = self.server.select_folder('INBOX') '''expunge cuckooinbox request''' self.server.delete_messages(self.message) self.server.expunge() def zipResults(self,): '''create temporary zip file''' temp_zip = tempfile.TemporaryFile(prefix='report',suffix='.zip') zip_file = zipfile.ZipFile(temp_zip, 'w') if self.zip_password: zip_file.setpassword(self.zip_password) '''set zip to compress''' try: import zlib compression = zipfile.ZIP_DEFLATED except: compression = zipfile.ZIP_STORED modes = { zipfile.ZIP_DEFLATED: 'deflated', zipfile.ZIP_STORED: 'stored',} '''wait for reports to finish then add to list''' for id in self.taskids: # timeout error handling if not os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","report.html")): self.log_entry.logEvent('cuckooinbox error: report timeout reached on task ID %d.' % id) else: zip_file.write(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","report.html"),\ arcname = 'report' + str(id) + '.html', compress_type=compression) zip_file.close() '''attach zip to email message''' temp_zip.seek(0) email_file = MIMEBase('application', 'zip') email_file.set_payload(temp_zip.read()) Encoders.encode_base64(email_file) email_file.add_header('Content-Disposition', 'attachment; filename="report.zip"') self.response_msg.attach(email_file) def sendReport(self,): '''create email header''' assert type(self.cc_list)==list assert type(self.taskids)==list self.response_msg['From'] = self.username self.response_msg['To'] = self.sender self.response_msg['Cc'] = ", ".join(self.cc_list) self.response_msg['Date'] = formatdate(localtime=True) self.response_msg['Subject'] = 'cuckooinbox report: ' + self.subject '''attach cuckooinbox email body''' for id in self.taskids: '''wait for reports to finish before sending''' timeout = time.time() + 120 while time.time() < timeout: if os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","report.html")): continue time.sleep(.25) if os.path.exists(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","inbox.html")): file = open(os.path.join(CUCKOO_ROOT,"storage","analyses",str(id),"reports","inbox.html")) body = '<html>' + \ '<div class="section-title">'+ \ '<h2>Task ID %d <small></small></h2>' % id + \ '</div>'+ \ '<table class="table table-striped table-bordered">'+ \ file.read() + \ '</html>' file.close() response_text = ''.join(body) self.response_msg.attach(MIMEText(response_text,'html')) else: print '[!] Could not find cuckoobox report files.' '''wait for analysis to finish and zip the reports''' self.zipResults() '''send the message''' if '@gmail.com' in self.username: smtp = smtplib.SMTP('smtp.gmail.com',587) smtp.starttls() smtp.login(self.username, self.passwd) else: smtp = smtplib.SMTP(self.smtp_server) try: smtp.login(self.username,self.passwd) except: self.log_entry.logEvent('[!] SMTP login failed.') try: smtp.sendmail(self.username, self.sender, self.response_msg.as_string()) except: self.log_entry.logEvent('SMTP message %s failed to send.' % self.subject) smtp.close() self.log_entry.logEvent('[-] Sent "%s" report to %s' % (self.subject, self.sender)) self.server.logout()
class Imapmail(object): ''' 定义类Imapmail实现代理登录邮箱,监听,获取往期邮件等功能 ''' def __init__(self): # 初始化数据 self.ID = 0 self.server_address = None # imap地址 例如imap.163.com self.user = None # 邮箱账号 self.password = None # 邮箱密码 self.prot = None self.ssl = None self.timeout = None # 连接超时最大时间 self.server = None # imap客户端 用于与imap服务器交互 self.result = list() # 某标签(ALL,UNSEEN等)的全部邮件 self.size = 0 # 邮件的数量 self.previous = 0 # 上一次扫描邮件的数量 self.messageObj = None # 存储单封邮件的内容 self.received_mails = {'垃圾邮件': list(), '正常邮件': list()} # 存储往期邮件 global white_list global black_list # 获取与该用户绑定的个人白名单和黑名单 # 加载本地白名单 黑名单 pickle_file_white = open('white_list.pkl', 'rb') white_list = pickle.load(pickle_file_white) pickle_file_black = open('black_list.pkl', 'rb') black_list = pickle.load(pickle_file_black) def client(self): # 链接imap服务器 得到server try: self.server = IMAPClient(self.server_address, self.prot, self.ssl, timeout=self.timeout) return self.server except BaseException as e: return "ERROR: >>> " + str(e) def login(self): # 邮箱登录 try: self.server.login(self.user, self.password) global save_paths # 加载附件下载地址 pickle_file_save_path = open('save_paths.pkl', 'rb') save_paths = pickle.load(pickle_file_save_path) # 附件下载地址 if self.user not in save_paths.keys(): save_paths.update({self.user: '******'}) pickle_file = open('save_paths.pkl', 'wb') pickle.dump(save_paths, pickle_file) pickle_file.close() except BaseException as e: return 0 def get_mail_dir(self): # 获取邮箱目录 暂不使用 # 获取目录列表 [((), b'/', 'INBOX'), ((b'\\Drafts',), b'/', '草稿箱'),] dir_list = self.server.list_folders() return dir_list def init(self): # 监听机制初始化 设置初始邮件数量 self.server.select_folder('INBOX', readonly=False) # 选择目录 readonly=True 只读,不修改,这里只选择了 收件箱 self.result = self.server.search('all') # 获取所有邮件总数目 [1,2,3,....] self.previous = len(self.result) def get_result(self): # 循环监听 更改邮件数量 # self.server.select_folder('INBOX', readonly=False) # 选择目录 readonly=True 只读,不修改,这里只选择了 收件箱 self.result = self.server.search('all') # 获取所有邮件总数目 [1,2,3,....] self.size = len(self.result) return self.size def if_exist_attach(self, mg): msg_dict = self.server.fetch(mg, ['BODY[]']) # 获取邮件内容 mail_body = msg_dict[mg][b'BODY[]'] # 获取邮件内容 message = pyzmail.PyzMessage.factory(mail_body) flag = 0 for part in message.mailparts: if part.filename: flag = 1 if flag == 1: return 1 else: return 0 def get_attach(self, mg): # 获取附件 global save_paths if not os.path.exists(save_paths[self.user]): # 判断下载目录是否存在,不存在就创建一个 os.mkdir(save_paths[self.user]) msg_dict = self.server.fetch(mg, ['BODY[]']) # 获取邮件内容 mail_body = msg_dict[mg][b'BODY[]'] # 获取邮件内容 message = pyzmail.PyzMessage.factory(mail_body) num = 0 for part in message.mailparts: if part.filename: num += 1 filename_save = message.get_address('from')[1] + '_' + part.filename down_path = os.path.join(save_paths[self.user], filename_save) # print('附件保存地址为:%s' % down_path) with open(down_path, 'wb') as f: f.write(part.get_payload()) # print('下载完毕') def get_content(self, mg): data = self.server.fetch(mg, ['ENVELOPE']) envelope = data[mg][b'ENVELOPE'] dates = envelope.date msg_dict = self.server.fetch(mg, ['BODY[]']) # 获取邮件内容 mail_body = msg_dict[mg][b'BODY[]'] # 获取邮件内容 ip = (re.search( r'(?:(?:[01]?\d?\d?|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d?\d?|2[0-4]\d|25[0-5])', str(mail_body))).group() self.messageObj = pyzmail.PyzMessage.factory(mail_body) subject = self.messageObj.get_subject() send = str(self.messageObj.get_addresses('from')[0][1]) send_time = str(dates) message_Content = '内容为空' mail = {'垃圾': 0, '主题': subject, '发件人': send, '时间': send_time, 'IP地址': ip, '主要内容': message_Content, '邮件': None, '附件': 0} if self.if_exist_attach(mg): mail['附件'] = 1 else: mail['附件'] = 0 self.ID += 1 if self.messageObj.text_part is not None: message_Content = self.messageObj.text_part.get_payload().decode(self.messageObj.text_part.charset) mail['主要内容'] = message_Content # if self.messageObj.html_part is not None: # message_Content = self.messageObj.html_part.get_payload().decode(self.messageObj.text_part.charset) # mail['主要内容'] = message_Content else: pass return mail def get_new_mail(self,normDict, spamDict,health_dic, spam_dic, health_sum, spam_sum): # 监听最新邮件 count = 0 self.get_result() mails = list() temp = self.previous # 11 count = len(self.result) - self.previous self.previous = len(self.result) if count == 0: print('邮件总数:' + str(self.size)) else: print('邮件总数:' + str(self.size)) for each_mail in self.result[temp:self.size]: mail = self.get_content(each_mail) mail['邮件'] = each_mail if mail['发件人'] in white_list: pass elif mail['发件人'] in black_list: # self.previous -= 1 mail['垃圾'] = 1 mails.append(mail) self.send_back(mail) else: # 由公共黑名单或者算法进行判断 # 根据结果更新词条垃圾的值 # 云端判断邮件垃圾与否 chnum, ennum, allnum, chp = self.number(mail['主要内容']) if chp > 0.9: div = filter2.Get_Email_Div(mail['主要内容']) result = filter2.Get_Bayes_Num(div, spamDict, normDict, 7063, 7775) else: result = filter2.Bayes(mail['主要内容'], ennum,health_dic, spam_dic, health_sum, spam_sum) if result == 1: mail['垃圾'] = 1 # self.send_back(mail) else: pass mails.append(mail) return mails def delete_mail(self, mail): self.server.delete_messages(mail) def get_all_mails(self, normDict, spamDict,health_dic, spam_dic, health_sum, spam_sum): self.get_result() if self.size == 0: print('收件箱为空') else: for each_mail in self.result: mail = self.get_content(each_mail) mail['邮件'] = each_mail temp = mail.copy() temp.pop('邮件') temp.pop('垃圾') if temp in Lgmail.extra_list: mail['垃圾'] = 0 self.received_mails['正常邮件'].append(mail) elif mail['发件人'] in white_list: self.received_mails['正常邮件'].append(mail) elif mail['发件人'] in black_list: mail['垃圾'] = 1 self.received_mails['垃圾邮件'].append(mail) else: # 由公共黑名单或者算法进行判断 # 由公共黑名单或者算法进行判断 # 根据结果更新词条垃圾的值 chnum, ennum, allnum,chp = self.number(mail['主要内容']) if chp>0.8: # div = filter2.Get_Email_Div(mail['主要内容']) # result = filter2.Get_Bayes_Num(div, spamDict, normDict, 7063, 7775) pass else: # result = filter2.Bayes(mail['主要内容'],ennum,health_dic, spam_dic, health_sum, spam_sum) pass result = 1 if result == 1: mail['垃圾'] = 1 self.received_mails['垃圾邮件'].append(mail) else: self.received_mails['正常邮件'].append(mail) # self.get_attach(each_mail) return self.received_mails def number(self, content): allnum = 0 chnum = 0 ennum = 0 for i in content: if '\u4e00' <= i <= '\u9fff': chnum += 1 allnum += 1 if (i >= u'\u0041' and i <= u'\u005a') or (i >= u'\u0061' and i <= u'\u007a'): ennum += 1 allnum += 1 chp = chnum / allnum return chnum, ennum, allnum, chp def close(self): # 断开连接 self.server.logout() def add_white(self, name): # 添加本地白名单 global white_list if name not in white_list: white_list.append(name) pickle_file = open('white_list.pkl', 'wb') pickle.dump(self.white_list, pickle_file) pickle_file.close() def add_black(self, name): # 添加本地黑名单 global black_list if name not in black_list: black_list.append(name) pickle_file = open('white_list.pkl', 'wb') pickle.dump(self.black_list, pickle_file) pickle_file.close() def send_back(self, mail): # 自动恢复垃圾邮件 sender_user = self.user # 自动回复的发件人 sender_password = self.password # 密码 sender_smtp = 'smtp.'+self.user.split('@')[-1] # 发送方的smtp地址 receive_user = mail['发件人'] # 收件人的邮箱地址 message = MIMEText('你这个辣鸡', 'plain', 'utf-8') # 邮件对象 message['From'] = sender_user # 设置发件人 message['TO'] = receive_user # 设置收件人 message['Subject'] = '测试邮件' # 设置主题 with SMTP_SSL(host=sender_smtp, port=465) as smtp: # 连接smtp服务器 smtp.login(user=sender_user, password=sender_password) smtp.sendmail(from_addr=self.user, to_addrs=receive_user, msg=message.as_string()) smtp.quit()
class IMAPBot(object): IMAPBotError = IMAPBotError def __init__(self, host, username, password, ssl=True): self.server = IMAPClient(host, use_uid=True, ssl=ssl) self.server.login(username, password) if 'IDLE' not in self.server.capabilities(): raise IMAPBotError('Sorry, this IMAP server does not support IDLE.') # the folder where processed emails go self.processed_folder = 'imapbot_processed' self.idle_timeout = 5 # seconds self._is_idle = False self._run = True self._create_folder(self.processed_folder) def check_mail(self): select_info = self.server.select_folder('INBOX') print '%d messages in INBOX' % select_info['EXISTS'] messages = self.server.search(['UNSEEN']) messages = self.server.search(['NOT DELETED']) print "%d messages that haven't been seen" % len(messages) if not messages: return #response = self.server.fetch(messages, ['FLAGS', 'INTERNALDATE', 'RFC822.SIZE', 'ENVELOPE', 'RFC822.TEXT']) response = self.server.fetch(messages, ['FLAGS', 'ENVELOPE', 'RFC822.TEXT']) for message_id, data in response.iteritems(): message = Message(message_id, data['ENVELOPE'], data['RFC822.TEXT'], data['FLAGS']) self.process(message) def complete(self, message): message_ids = [message.id] self.server.copy(message_ids, self.processed_folder) self.server.delete_messages(message_ids) self.server.expunge() def _create_folder(self, name): # make sure the folder doesn't already exist if self.server.folder_exists(name): return self.server.create_folder(name) def handle_message(self, message): print 'message id: {}, from: {}:'.format(message.id, message.envelope.get_email('from')) with open('message.txt', 'ab') as fh: fh.write('{}\n\n'.format(message.text)) print message.plain or message.html or 'no message' def idle(self): if self._is_idle: return self.server.idle() self._is_idle = True return True # this actually changed state def unidle(self): if not self._is_idle: return self.server.idle_done() self._is_idle = False return True # this call actually changed state def process(self, message): self.handle_message(message) self.complete(message) def run(self): # process any mail that was in the inbox before coming online self.check_mail() # put the connection in idle mode so we get notifications self.idle() # loop forever looking for stuff while self._run: for message in self.server.idle_check(timeout=self.idle_timeout): if message[0] == 'OK': continue with Unidle(self): self.check_mail() def quit(self): self._run = False self.unidle() print self.server.logout()
def main(): # -options- parser = OptionParser("python %prog [options] CONFIG_FILE") parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False) (options, args) = parser.parse_args() # -settings- if len(args) < 1: parser.print_help() exit() if not os.path.exists(args[0]): raise IOError(ENOENT, 'Archivo de configuracion no encontrado', args[0]) config = RawConfigParser() config.read(args[0]) # put read config options (from the .ini) into global namespace and in uppercase for name, value in config.items('chkemail'): globals()[name.upper()] = value # -workflow- # create, connect, and login to server server = IMAPClient(HOST, use_uid=True) try: server.login(USER, PASSWORD, port=PORT) except NameError: # if PORT is not defined server.login(USER, PASSWORD) inbox = server.select_folder('INBOX') if options.verbose: print '%d messages in INBOX (included deleted)' % inbox['EXISTS'] messages = server.search(['NOT DELETED', 'HEADER Content-Type mixed']) if options.verbose: print "%d messages with possible attch" % len(messages) # fetch data from messages, put each message (Mess object) into the msgs list scan = server.fetch(messages, ['BODYSTRUCTURE', 'ENVELOPE']) msgs = dict() for mid, response in scan.iteritems(): # Mess class only works with mulipart messages if response['BODYSTRUCTURE'].is_multipart: msgs[mid] = Mess(mid, response['ENVELOPE'], response['BODYSTRUCTURE']) # Select the messages with attachements I want, put them in group_msgs group_msgs = dict() for msg in msgs.itervalues(): group_msgs[msg.id] = list() for part_num, part_info in msg.parts.iteritems(): if part_info.filename: filename = part_info.filename.lower() if filename.endswith('.pdf') or filename.endswith('.xml') or \ filename.endswith('.zip'): group_msgs[msg.id] += [part_num] if not group_msgs[msg.id]: del group_msgs[msg.id] # fetch all interesting parts for msg_id, parts in group_msgs.iteritems(): request = ['BODY['+str(part)+']' for part in parts] response = server.fetch(msg_id, request) for body_part in response[msg_id].iterkeys(): if 'BODY' in body_part: msgs[msg_id].parts[body_part[5:-1]].data = response[msg_id][body_part] # move messages to trash if len(group_msgs.keys()) > 0: server.copy(group_msgs.keys(), 'INBOX.Trash') server.delete_messages(group_msgs.keys()) server.logout() # ensure there's an OUTPUT_DIR directory pdf_dir = os.path.join(OUTPUT_PDF, strftime('%Y-%m')) ensure_dir(pdf_dir) ensure_dir(OUTPUT_DIR) # decode and write data to file num_attch = 0 for msg in msgs.itervalues(): for part in msg.parts: if part.data: filename = part.filename.lower() if filename.endswith('.pdf') or filename.endswith('.xml'): if filename.endswith('.pdf'): ensure_dir(os.path.join(pdf_dir, str(msg.envelope))) attachment_filename = generate_filename(os.path.join(pdf_dir, str(msg.envelope), os.path.basename(part.filename))) else: attachment_filename = generate_filename(os.path.join(OUTPUT_DIR, os.path.basename(part.filename))) with open(attachment_filename, 'wb') as file_: if part.encoding == 'quoted-printable': file_.write(decodestring(part.data)) elif part.encoding == 'base64': file_.write(b64decode(part.data)) num_attch += 1 elif filename.endswith('.zip') and part.encoding == 'base64': with tempfile.TemporaryFile() as tmp_zip: tmp_zip.write(b64decode(part.data)) zip_file = ZipFile(tmp_zip) for f_info in zip_file.infolist(): if f_info.filename.lower().endswith('.xml'): attachment_filename = generate_filename(os.path.join(OUTPUT_DIR, os.path.basename(f_info.filename))) elif f_info.filename.lower().endswith('.pdf'): ensure_dir(os.path.join(pdf_dir, str(msg.envelope))) attachment_filename = generate_filename(os.path.join(pdf_dir, str(msg.envelope), os.path.basename(f_info.filename))) else: continue with open(attachment_filename, 'wb') as file_: file_.write(zip_file.read(f_info)) num_attch += 1 if options.verbose: print '%d files extracted' % num_attch
class SourceDriverMail(SourceDriver): def __init__(self, instanceName: str, settings: Settings, parser: MessageParser) -> None: super().__init__("mail", instanceName, settings, parser) # Settings self.__server = self.getSettingString("server", "") self.__user = self.getSettingString("user", "") self.__password = self.getSettingString("password", "") self.__ssl = self.getSettingBoolean("ssl", True) self.__fix_weak_dh = self.getSettingBoolean("fix_weak_dh", False) self.__allowlist = self.getSettingList("allowlist", []) self.__denylist = self.getSettingList("denylist", []) self.__cleanup = self.getSettingString("cleanup", "") self.__archive_folder = self.getSettingString("archive_folder", "Archive") if self.__cleanup == "Delete": self.print("Cleanup strategy is delete") elif self.__cleanup == "Archive": self.print("Cleanup strategy is archive") elif self.__cleanup == "": self.print("Cleanup is disabled") else: self.fatal("Unknown cleanup strategy") # Internal self.__healthy = False self.__connect() def retrieveEvent(self) -> Optional[SourceEvent]: try: if self.isDebug(): self.print("Checking for new mails") messages = self.__imap_client.search('UNSEEN') for uid, message_data in self.__imap_client.fetch( messages, "RFC822").items(): message = email.message_from_bytes(message_data[b"RFC822"], policy=policy.default) sender = parseaddr(message.get("From"))[1] sourceEvent = SourceEvent() sourceEvent.source = SourceEvent.SOURCE_MAIL sourceEvent.timestamp = datetime.datetime.strptime( message.get('Date'), "%a, %d %b %Y %H:%M:%S %z").strftime( SourceEvent.TIMESTAMP_FORMAT) sourceEvent.sender = sender sourceEvent.raw = message.get_body(('plain', )).get_content() if self.isSenderAllowed(allowlist=self.__allowlist, denylist=self.__denylist, sender=sender): parsedSourceEvent = self.parser.parseMessage( sourceEvent, None) # type: ignore[union-attr] self.__do_cleanup(uid) return parsedSourceEvent else: self.error("Received unhandled message (ignored sender)") return UnhandledEvent.fromSourceEvent( sourceEvent, UnhandledEvent.CAUSE_IGNORED_SENDER) except (timeout, OSError) as e: self.error("Connection to mailserver timed out") self.__healthy = False self.__connect() def getSourceState(self) -> SourceState: if self.__healthy: return SourceState.OK return SourceState.ERROR def __connect(self): if self.__fix_weak_dh: context = ssl.SSLContext( ssl.PROTOCOL_TLSv1_2) # Workaround for weak dh key context.set_ciphers('DEFAULT@SECLEVEL=1') else: context = ssl.SSLContext() try: if self.isDebug(): self.print("Connecting to server {}".format(self.__server)) self.__imap_client = IMAPClient(self.__server, use_uid=True, ssl=self.__ssl, ssl_context=context, timeout=1.0) except gaierror: self.error("Failed to connect to Mail Server") except ssl.SSLError: self.fatal("Failed to connect to Mail Server (TLS Error)") else: try: if self.isDebug(): self.print("Login as user {}".format(self.__user)) self.__imap_client.login(self.__user, self.__password) except LoginError: self.error("Mail Server login failed") else: if self.isDebug(): self.print("Login successful") self.__healthy = True self.__imap_client.select_folder('INBOX', readonly=False) def __create_imap_folder(self, folder): if not self.__imap_client.folder_exists(folder): self.print("Folder {} does not exist creating") self.__imap_client.create_folder(folder) def __do_cleanup(self, uid): if self.__cleanup == "Archive": self.__create_imap_folder(self.__archive_folder) self.__imap_client.copy(uid, self.__archive_folder) if self.__cleanup == "Delete" or self.__cleanup == "Archive": self.__imap_client.delete_messages(uid) self.__imap_client.expunge(uid)
class EmailClient(object): def __init__(self, config): """ Create an email client abstraction configured for an account. config is a dict with keys: HOST USERNAME PASSWORD USE_SSL default=True FOLDER default='INBOX' SELECTORS default=['NOT DELETED'] """ self.config = { 'USE_SLL': True, 'FOLDER': 'INBOX', 'SELECTORS': ['NOT DELETED'] } self.config.update(config) def connect(self): self.server = IMAPClient(self.config['HOST'], use_uid=True, ssl=self.config['USE_SSL']) self.server.login(self.config['USERNAME'], self.config['PASSWORD']) select_info = self.server.select_folder(self.config['FOLDER']) def process_new_messages(self, debug=False): """ Get mesages from the server. Note: new information on existing uids will be ignored. For example, if the rfc_size changes (which is a strangely common occurrence), the new value will be ignored. """ if debug: print "searching" messages = self.server.search(self.config['SELECTORS']) if debug: print "done searching" self._process_messages(messages, debug=debug) def _process_messages(self, uids, move=False, debug=False): if debug: print "fetching" response = self.server.fetch(uids, ['FLAGS', 'RFC822', 'RFC822.SIZE']) for msg_uid, data in response.iteritems(): if debug: print "processing %s" % msg_uid with transaction.commit_on_success(): # extract data flags = data['FLAGS'] rfc_size = data['RFC822.SIZE'] raw_body = data['RFC822'] seq = data['SEQ'] # save objects email, _ = EmailMessage.objects.get_or_create( uid=msg_uid, username=self.config['USERNAME'], host=self.config['HOST'], defaults={ 'raw_body': raw_body, 'rfc_size': rfc_size, 'seq': data['SEQ'], }) email.save() for flag in flags: EmailFlag.objects.get_or_create(email=email, flag=flag)[0].save() # move message if move: self.server.copy([msg_uid], 'auto_processed') self.server.delete_messages([msg_uid])
commstr = commstr.strip() logging.debug('COMMAND: ' + commstr) comm = commstr.split(' ') comm[0] = comm[0].lower() if comm[0] == 'quit': for i in range(2): inst_queue.put([['quit'], listener, talker, passw, 0]) ch = 1 break else: inst_queue.put([comm, listener, talker, passw, 0]) if ch == 1: inst_queue.join() break imapobj.delete_messages(UIDs) UIDs = [] try: smtpobj = smtplib.SMTP('smtp.gmail.com', 587) smtpobj.ehlo() smtpobj.starttls() smtpobj.login(listener, passw) smtpobj.sendmail(listener, talker, 'Subject:ALFRED OFFLINE. THANK YOU\n') imapobj.logout() smtpobj.quit() except smtplib.SMTPAuthenticationError: print 'incorrect login credentials' logging.debug('listener logging failed')
class EmailOperation(object): def __init__(self, user_name, pwd): print("使用imapclient,操作邮件...") self.server = IMAPClient('imap.139.com', use_uid=True, ssl=False) self.username = user_name self.password = pwd def logout(self): self.server.logout() # 删除邮件 def _del(self, messages): # print('del message') self.server.delete_messages(messages) self.server.expunge() def _mv(self, message, folder): self.server.copy(message, folder) time.sleep(1) self._del(message) def _into(self, box): # 'INBOX','草稿箱','已发送','已删除','100' self.server.select_folder(box) def _get_uids(self): # 获取序列 uids = self.server.search(['NOT', 'DELETED']) return uids def email_body(self, mss): # 获取某序列id的原始信息 raw_messages = self.server.fetch([mss], ['BODY[]', 'FLAGS']) # pprint.pprint(rawMessages) # 使用pyzmail,返回主体信息 message = pyzmail.PyzMessage.factory(raw_messages[mss][b'BODY[]']) # 如果信息为空,返回None if not message: return None # 获取正文内容 if message.text_part != None: lines = message.text_part.get_payload().decode( message.text_part.charset) str = '' # 去除内容中的回车 for line in lines: if line not in ['\n', '\r']: str += line print(str) # body自动 body = { 'subject': message.get_subject(), 'from': message.get_address('from'), 'to': message.get_address('to'), 'mainbody': str } return body def del_all_message(self, folder): '''清空某个文件夹下的所有邮件''' self._into(folder) uids = self._get_uids() if len(uids) == 0: return else: self._del(uids) def del_new_message(self, fforlder): '''把最近一封新邮件已到目的目录''' self._into(fforlder) uids = self._get_uids() if len(uids) == 0: return else: self._del(uids[-1]) def move_all_message_to_folder(self, fforlder, tforlder): '''把maessage/messages 从 ffolder 移动到 tforlder''' self._into(fforlder) uids = self._get_uids() # 邮件数量为空 if len(uids) == 0: print("%s 数量为:0,该操作无效" % fforlder) return True self._mv(uids, tforlder) def check_new_message(self): '''判断最新一封邮件,是否包含某个字段,显示邮件数量''' self._into("INBOX") uids = self._get_uids() print('current INBOX email: %s' % str(len(uids))) if len(uids) in [0, 1]: print("不执行,目前邮件数量为:%r" % len(uids)) return if self.email_body(uids[-1])['subject'] == 'testReceive': self._del(uids[-1]) def delete_newest_mail(self): '''删除最新的一封邮件''' try: is_true = False self.server.login(self.username, self.password) self.del_new_message('INBOX') is_true = True except BaseException as error: print(error) print("删除邮件可能出现错误") finally: self.logout() return is_true def clear_forlder(self, l=[]): '''清空邮箱某个文件夹''' ''' sample: clearForlder(['100', 'INBOX']) ''' is_true = False if len(l) == 0: return is_true try: self.server.login(self.username, self.password) for f in l: print("clear Forlder: %s" % f) self.del_all_message(f) time.sleep(1) is_true = True except BaseException as error: print(error) print("删除邮件可能出现错误") finally: self.logout() return is_true def move_forlder(self, l=[]): '''移动邮件 sample: moveForlder(['100', 'INBOX']) ''' is_true = False if len(l) == 0: return is_true try: self.server.login(self.username, self.password) self.move_all_message_to_folder(l[0], l[1]) print("移动邮件成功:%s => %s" % (l[0], l[1])) is_true = True except BaseException as error: print(error) print("清空邮箱某个文件夹可能出现错误") finally: self.logout() return is_true def check_inbox_cnt(self): '''获取邮件数量''' try: is_true = 0 self.server.login(self.username, self.password) self._into("INBOX") uids = self._get_uids() # 数量为 0 if len(uids) == 0: return 0 # 判断 if len(uids) == 100: print("100封邮件") return 0 elif len(uids) < 100: print('邮件数量少于100封') return 0 else: cnt = len(uids) - 100 print('需要删除邮件数量为:%d' % cnt) is_true = cnt except BaseException as error: print(error) print("删除邮件可能出现错误") finally: self.logout() return is_true def check_inbox(self): '''确保收件箱有100封邮件''' try: is_true = True self.server.login(self.username, self.password) self._into("INBOX") uids = self._get_uids() all = len(uids) # 数量为 0 if all == 0: return False # 判断 if all == 100: print("100封邮件") return is_true elif all < 100: print('邮件数量少于100封') return False else: print('需要删除邮件数量为:%d' % (all - 100)) # print(Uids[100:]) self._del(uids[100:]) return is_true except BaseException as error: print(error) print("删除邮件可能出现错误") is_true = False finally: self.logout() return is_true def seen(self): '''将收件箱邮件,标记已读''' self.server.login(self.username, self.password) self._into("INBOX") # 搜索 未读邮件 typ = self.server.search([u'UNSEEN']) # 把邮件改为已读 for num in typ: print(num) self.server.set_flags(num, [u'Seen'])
class IMAP(): """ Central class for IMAP server communication """ Retval = namedtuple('Retval', 'code data') def __init__(self, logger, username, password, server='localhost', port=143, starttls=False, imaps=False, tlsverify=True, test=False, timeout=None): self.logger = logger self.username = username self.password = password self.server = server self.port = port self.imaps = imaps self.starttls = starttls self.timeout = timeout self.sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) # TODO add proto arg if tlsverify: self.sslcontext.verify_mode = ssl.CERT_REQUIRED else: self.sslcontext.verify_mode = ssl.CERT_NONE # TODO improve? self.test = test self.conn = None def do_select_mailbox(func): """ Decorator to do a fresh mailbox SELECT """ def wrapper(*args, **kwargs): if len(args) != 1: raise AttributeError( 'Size of *args tuple "{0}" isn\'t 1. It looks like you haven\'t specified all ' 'method arguments as named arguments!'.format( args)) mailbox = None for key in ['mailbox', 'source']: if key in kwargs.keys(): mailbox = kwargs[key] break if mailbox is None: raise KeyError('Unable to SELECT a mailbox, kwargs "{0}" doesn\'t contain a mailbox name'.format(kwargs)) result = args[0].select_mailbox(mailbox) if not result.code: raise RuntimeError(result.data) return func(*args, **kwargs) return wrapper def process_error(self, exception, simple_return=False): """ Process Python exception by logging a message and optionally showing traceback """ trace_info = exc_info() err_msg = str(exception) if isinstance(exception, IMAPClient.Error): err_msg = Helper().byte_to_str(exception.args[0]) self.logger.error('Catching IMAP exception %s: %s', type(exception), err_msg) if self.logger.isEnabledFor(loglevel_DEBUG): print_exception(*trace_info) del trace_info if simple_return: return exception else: return self.Retval(False, err_msg) def connect(self, retry=True, logout=False): """ Connect to IMAP server and login """ if self.starttls: self.logger.debug('Establishing IMAP connection using STARTTLS/%s to %s and logging in with user %s', self.port, self.server, self.username) elif self.imaps: self.logger.debug('Establishing IMAP connection using SSL/%s (imaps) to %s and logging in with user %s', self.port, self.server, self.username) login = '' err_return = None try: self.conn = IMAPClient(host=self.server, port=self.port, use_uid=True, ssl=self.imaps, ssl_context=self.sslcontext, timeout=self.timeout) if self.starttls: self.conn.starttls(ssl_context=self.sslcontext) login = self.conn.login(self.username, self.password) login_response = Helper().byte_to_str(login) # Test login/auth status login_success = False noop = self.noop() if noop.code and noop.data: login_success = True if logout: return self.disconnect() elif login_success: return self.Retval(True, login_response) else: return self.Retval(False, login_response) # pragma: no cover except Exception as e: err_return = self.process_error(e) if err_return.data == '[AUTHENTICATIONFAILED] Authentication failed.': return err_return if retry: self.logger.error('Trying one more time to login') sleep(2) return self.connect(retry=False, logout=logout) return err_return def noop(self): """ Do a noop to test login status """ try: noop = self.conn.noop() noop_response = Helper().byte_to_str(noop[0]) noop_resp_pattern_re = regex_compile('^(Success|NOOP completed)') login_success = noop_resp_pattern_re.match(noop_response) return self.Retval(True, login_success) except IMAPClient.Error as e: return self.process_error(e) def disconnect(self): """ Disconnect from IMAP server """ result = self.conn.logout() response = Helper().byte_to_str(result) return self.Retval(response == 'Logging out', response) def list_mailboxes(self, directory='', pattern='*'): """ Get a listing of folders (mailboxes) on the server """ try: raw_list = self.conn.list_folders(directory, pattern) nice_list = [] for mailbox in raw_list: flags = [] for flag in mailbox[0]: flags.append(flag.decode('utf-8')) nice_list.append({'name': mailbox[2], 'flags': flags, 'delimiter': mailbox[1].decode("utf-8")}) return self.Retval(True, nice_list) except IMAPClient.Error as e: return self.process_error(e) def select_mailbox(self, mailbox): """ Select a mailbox to work on """ self.logger.debug('Switching to mailbox %s', mailbox) try: result = self.conn.select_folder(mailbox) response = {} for key, value in result.items(): unicode_key = Helper().byte_to_str(key) if unicode_key == 'FLAGS': flags = [] for flag in value: flags.append(Helper().byte_to_str(flag)) response[unicode_key] = tuple(flags) else: response[unicode_key] = value return self.Retval(True, response) except IMAPClient.Error as e: return self.process_error(e) def add_mail(self, mailbox, message, flags=(), msg_time=None): """ Add/append a mail to a mailbox """ self.logger.debug('Adding a mail into mailbox %s', mailbox) try: if not isinstance(message, Mail): message = Mail(logger=self.logger, mail_native=message) message_native = message.get_native() #self.conn.append(mailbox, message, flags, msg_time) self._append(mailbox, str(message_native), flags, msg_time) # According to rfc4315 we must not return the UID from the response, so we are fetching it ourselves uids = self.search_mails(mailbox=mailbox, criteria='HEADER Message-Id "{0}"'.format(message.get_header('Message-Id'))).data[0] return self.Retval(True, uids) except IMAPClient.Error as e: return self.process_error(e) @do_select_mailbox def search_mails(self, mailbox, criteria='ALL', autocreate_mailbox=False): """ Search for mails in a mailbox """ self.logger.debug('Searching for mails in mailbox %s and criteria=\'%s\'', mailbox, criteria) try: return self.Retval(True, list(self.conn.search(criteria=criteria))) except IMAPClient.Error as e: return self.process_error(e) @do_select_mailbox def fetch_mails(self, uids, mailbox, return_fields=None): """ Retrieve mails from a mailbox """ self.logger.debug('Fetching mails with uids %s', uids) return_raw = True if return_fields is None: return_raw = False return_fields = [b'RFC822'] mails = {} try: for uid in uids: result = self.conn.fetch(uid, return_fields) if not result: continue if return_raw: mails[uid] = result[uid] else: #mails[uid] = Mail(logger=self.logger, uid=uid, mail_native=email.message_from_bytes(result[uid][b'RFC822'])) mails[uid] = Mail(logger=self.logger, mail_native=email.message_from_bytes(result[uid][b'RFC822'])) return self.Retval(True, mails) except IMAPClient.Error as e: return self.process_error(e) @do_select_mailbox def get_mailflags(self, uids, mailbox): """ Retrieve flags from mails """ try: result = self.conn.get_flags(uids) flags = {} for uid in uids: flags[uid] = [] if uid not in result.keys(): self.logger.error('Failed to get flags for mail with uid=%s: %s', uid, result) return self.Retval(False, None) for flag in result[uid]: flags[uid].append(flag.decode('utf-8')) return self.Retval(True, flags) except IMAPClient.Error as e: return self.process_error(e) @do_select_mailbox def set_mailflags(self, uids, mailbox, flags=[]): """ Set and retrieve flags from mails """ if self.test: self.logger.info('Would have set mail flags on message uids "%s"', str(uids)) return self.Retval(True, None) else: self.logger.debug('Setting flags=%s on mails uid=%s', flags, uids) try: result = self.conn.set_flags(uids, flags) _flags = {} for uid in uids: _flags[uid] = [] if uid not in result.keys(): self.logger.error('Failed to set and get flags for mail with uid=%s: %s', uid, result) return self.Retval(False, None) for flag in result[uid]: _flags[uid].append(flag.decode('utf-8')) return self.Retval(True, _flags) except IMAPClient.Error as e: return self.process_error(e) @do_select_mailbox def add_mailflags(self, uids, mailbox, flags=[]): """ Add and retrieve flags from mails """ if self.test: self.logger.info('Would have added mail flags on message uids "%s"', str(uids)) return self.Retval(True, None) else: self.logger.debug('Adding flags=%s on mails uid=%s', flags, uids) try: result = self.conn.add_flags(uids, flags) _flags = {} for uid in uids: _flags[uid] = [] if uid not in result.keys(): self.logger.error('Failed to add and get flags for mail with uid=%s: %s', uid, result) return self.Retval(False, None) for flag in result[uid]: _flags[uid].append(flag.decode('utf-8')) return self.Retval(True, _flags) except IMAPClient.Error as e: return self.process_error(e) @do_select_mailbox def move_mail(self, message_ids, source, destination, delete_old=True, expunge=True, add_flags=None, set_flags=None): """ Move a mail from a mailbox to another """ return self.copy_mails(message_ids=message_ids, source=source, destination=destination, delete_old=delete_old, expunge=expunge, add_flags=add_flags, set_flags=set_flags) @do_select_mailbox def copy_mails(self, source, destination, message_ids=None, delete_old=False, expunge=False, add_flags=None, set_flags=None): """ Copies one or more mails from a mailbox into another """ if self.test: if delete_old: self.logger.info('Would have moved mail Message-Ids="%s" from "%s" to "%s", skipping because of beeing in testmode', message_ids, source, destination) else: self.logger.info('Would have copied mails with Message-Ids="%s" from "%s" to "%s", skipping because of beeing in testmode', message_ids, source, destination) return self.Retval(True, None) else: try: if delete_old: self.logger.debug('Moving mail Message-Ids="%s" from "%s" to "%s"', message_ids, source, destination) else: self.logger.debug('Copying mail Message-Ids="%s" from "%s" to "%s"', message_ids, source, destination) #if message_ids is None: # message_ids = [] # result = self.fetch_mails(uids=uids, mailbox=source) # if not result.code: # self.logger.error('Failed to determine Message-Id by uids for mail with uids "%s"', uids) # return result # message_ids.append(result.data.keys()) if not self.mailbox_exists(destination).data: self.logger.info('Destination mailbox %s doesn\'t exist, creating it for you', destination) result = self.create_mailbox(mailbox=destination) if not result.code: self.logger.error('Failed to create the mailbox %s: %s', source, result.data) # pragma: no cover return result # pragma: no cover uids = [] for message_id in message_ids: result = self.search_mails(mailbox=source, criteria='HEADER Message-Id "{0}"'.format(message_id)) if not result.code or len(result.data) == 0: self.logger.error('Failed to determine uid by Message-Id for mail with Message-Id "%s"', message_id) return self.Retval(False, result.data) uids.append(result.data[0]) result = self.select_mailbox(source) if not result.code: return result # pragma: no cover self.conn.copy(uids, destination) if delete_old: result = self.delete_mails(uids=uids, mailbox=source) if not result.code: self.logger.error('Failed to remove old mail with Message-Id="%s"/uids="%s": %s', message_ids, uids, result.data) # pragma: no cover return result # pragma: no cover if expunge: # TODO don't expunge by default result = self.expunge(mailbox=source) if not result.code: self.logger.error('Failed to expunge on mailbox %s: %s', source, result.data) # pragma: no cover return result # pragma: no cover dest_uids = [] for message_id in message_ids: result = self.search_mails(mailbox=destination, criteria='HEADER Message-Id "{0}"'.format(message_id)) if not result.code: self.logger.error('Failed to determine uid by Message-Id for mail with Message-Id "%s"', message_id) # pragma: no cover return result # pragma: no cover dest_uids.append(result.data[0]) if isinstance(set_flags, list): self.set_mailflags(uids=dest_uids, mailbox=destination, flags=set_flags) if add_flags: self.add_mailflags(uids=dest_uids, mailbox=destination, flags=add_flags) return self.Retval(True, dest_uids) except IMAPClient.Error as e: return self.process_error(e) def _append(self, folder, msg, flags=(), msg_time=None): # TODO """ FORKED FORM IMAPCLIENT """ if msg_time: if not msg_time.tzinfo: # pragma: no cover msg_time = msg_time.replace(tzinfo=FixedOffset.for_system()) # pragma: no cover time_val = '"{0}"'.format(msg_time.strftime("%d-%b-%Y %H:%M:%S %z")) time_val = imapclient.imapclient.to_unicode(time_val) else: time_val = None return self.conn._command_and_check('append', self.conn._normalise_folder(folder), imapclient.imapclient.seq_to_parenstr(flags), time_val, Helper.str_to_bytes(msg), unpack=True) @do_select_mailbox def expunge(self, mailbox): """ Expunge mails form a mailbox """ self.logger.debug('Expunge mails from mailbox %s', mailbox) try: return self.Retval(True, b'Expunge completed.' in self.conn.expunge()) except IMAPClient.Error as e: # pragma: no cover return self.process_error(e) # pragma: no cover def create_mailbox(self, mailbox): """ Create a mailbox """ self.logger.debug('Creating mailbox %s', mailbox) try: return self.Retval(True, self.conn.create_folder(mailbox) == b'Create completed.') except IMAPClient.Error as e: return self.process_error(e) def mailbox_exists(self, mailbox): """ Check whether a mailbox exists """ try: return self.Retval(True, self.conn.folder_exists(mailbox)) except IMAPClient.Error as e: # pragma: no cover return self.process_error(e) # pragma: no cover @do_select_mailbox def delete_mails(self, uids, mailbox): """ Delete mails """ self.logger.debug('Deleting mails with uid="%s"', uids) try: result = self.conn.delete_messages(uids) flags = {} for uid in uids: flags[uid] = [] if uid not in result.keys(): self.logger.error('Failed to get flags for mail with uid=%s after deleting it: %s', uid, result) return self.Retval(False, None) for flag in result[uid]: flags[uid].append(flag.decode('utf-8')) return self.Retval(True, flags) except IMAPClient.Error as e: return self.process_error(e)
class Miner: """create a new email miner instance that can be used to traverse mails""" imap: IMAPClient = None def __init__(self, hostname: str, username: str, password: str, port: int = imaplib.IMAP4_SSL_PORT, use_ssl: bool = True, verify: bool = True, log_level: int = None): """ Create a new instance of the miner. :param hostname: the hostname of the imap server to connect to :param username: the user to login as :param password: :param port: the port to connect to. (defaults to 993) :param use_ssl: whether to use SSL to connect (defaults to True) :param verify: whether to verify the SSL certificates (defaults to False) """ if log_level is not None: logging.basicConfig( format='%(asctime)s - %(levelname)s: %(message)s', level=log_level) ssl_context = ssl.create_default_context() if not verify: # disable hostname check. certificate may not match hostname. ssl_context.check_hostname = False # disable certificate authority verification. certificate maybe issued by unknown CA ssl_context.verify_mode = ssl.CERT_NONE self.imap = IMAPClient(host=hostname, port=port, ssl=use_ssl, ssl_context=ssl_context) self.imap.login(username, password) @contextlib.contextmanager def folder(self, folder_name: str, read_only: bool = True): """ Switch to a specific folder. :param folder_name: name of the folder to switch to :param read_only: read-only mode will not mark emails as read even after retrieval :return: """ try: yield self.imap.select_folder(folder_name, read_only) finally: self.imap.close_folder() @contextlib.contextmanager def inbox(self, read_only: bool = True): """ Switch to the inbox folder. :param read_only: read-only mode will not mark emails as read even after retrieval :return: """ try: yield self.imap.select_folder('inbox', read_only) finally: self.imap.close_folder() def mark_as_unread(self, message_ids: List[int]): """ Mark the given message IDs as unread by removing the SEEN flag. :param message_ids: :return: """ self.imap.remove_flags(message_ids, [SEEN]) def mark_as_read(self, message_ids: List[int]): """ Mark the given message IDs as read by adding the SEEN flag. :param message_ids: :return: """ self.imap.add_flags(message_ids, [SEEN]) def delete(self, message_ids: List[int]): """ Delete the given message IDs :param message_ids: :return: """ self.imap.delete_messages(message_ids, True) def archive(self, message_ids: List[int]): """ Archive the given message IDs :param message_ids: :return: """ self.imap.copy(message_ids, br'\Archive') self.delete(message_ids) def get_emails(self, unread_only: bool = True, with_body: bool = False, keep_as_unread: bool = False, in_memory: bool = True) -> List[Email]: """ Get emails from the selected folder. :param keep_as_unread: keep any retrieved emails as unread in the mailbox. :param unread_only: choose only to retrieve unread mails :param with_body: read-only mode will not mark emails as read even after retrieval :param in_memory: store the parsed attachments in-memory as bytes or to a temp file locally :return: """ ids = self.imap.search('(UNSEEN)' if unread_only else 'ALL') flags = ['ENVELOPE', 'FLAGS', 'UID', 'INTERNALDATE'] if with_body: flags.append('BODY[]') response = self.imap.fetch(ids, flags) try: if keep_as_unread: self.mark_as_unread(ids) else: self.mark_as_read(ids) except Exception: # will throw an exception if folder in read-only mode. so ignore. pass return parse_emails(response, in_memory) def __enter__(self): """ return the instance of the miner for use as a context manager. :return: """ return self def __exit__(self, *args): """ Close folder and logout on exit when used as a context manager. :param args: :return: """ if self.imap is not None: try: self.imap.close_folder() except: pass self.imap.logout()
) originalFromName = data[b"ENVELOPE"].from_[0].name if ( originalFromName is None ): # from_ is a tuple of Address objects that represent one or more addresses from the “From” header, or None if header does not exist. originalFromName = data[b"ENVELOPE"].from_[0].mailbox.decode("utf-8") else: originalFromName = originalFromName.decode("utf-8") encodedText = data[b"BODY[TEXT]"].decode() if fromAddress in MAILING_LIST_USERS or fromAddress in TOLERATED_ALTERNATE_ADDRESSES: sendToAllUsers(data[b"ENVELOPE"].subject.decode("utf-8"), encodedText, fromAddress, originalFromName) else: sendToAdmin(data[b"ENVELOPE"].subject, encodedText, fromAddress) logging.warning( "{} tried to sent to the list but is not authorized. Forwarded to admin instead".format(fromAddress) ) allNewIds.append(msgid) # save for later deletion if len(allNewIds): logging.info("deleted {} messages".format(len(allNewIds))) server.delete_messages(allNewIds) server.expunge() server.logout() # quit imap mailserver.quit() # quit smtp now = datetime.datetime.now() print("Written to log. Last run was @ ", now.isoformat())
def fetchEMail(credentials): """ Fetch all emails and delete old messages and other messages """ from imapclient import IMAPClient rgx = re.compile( r"(\d+) crowdin entries linted for ([a-z]{2}(-[a-zA-Z]{2})?)") server = IMAPClient(credentials["host"], use_uid=True, ssl=True) server.login(credentials["user"], credentials["password"]) select_info = server.select_folder('INBOX') print('{0} messages in INBOX'.format(select_info[b'EXISTS'])) #Fetch list of emails messages = server.search(['NOT', 'DELETED']) msgmap = collections.defaultdict(list) # Fetch, filter and parse messages response = server.fetch(messages, [ 'BODY.PEEK[HEADER.FIELDS (SUBJECT)]', 'BODY.PEEK[HEADER.FIELDS (DATE)]', 'RFC822' ]) for msgid, data in response.items(): try: subject = data[b'BODY[HEADER.FIELDS (SUBJECT)]'].decode("utf-8") except KeyError: continue if subject.startswith("Subject: "): subject = subject[len("Subject: "):] subject = subject.strip() # Date date = data[b'BODY[HEADER.FIELDS (DATE)]'].decode("utf-8").strip() if date.startswith("Date: "): date = date[len("Date: "):] if date.endswith("(PST)"): date = date[:-len("(PST)")].strip() if date.endswith("(PDT)"): date = date[:-len("(PDT)")].strip() if date.endswith("(UTC)"): date = date[:-len("(UTC)")].strip() if date.endswith("(CEST)"): date = date[:-len("(CEST)")].strip() if date.endswith("(EST)"): date = date[:-len("(EST)")].strip() try: date = datetime.strptime(date, "%a, %d %b %Y %H:%M:%S %z") except ValueError: date = datetime.strptime(date, "%d %b %Y %H:%M:%S %z") # match = rgx.match(subject) if not match: # Delete message print(' Deleting "{1}"'.format(msgid, subject)) server.delete_messages(msgid) else: msgmap[match.group(2)].append( KALintMail(msgid, subject, date, data[b"RFC822"].decode("utf-8"))) # Filter duplicates and sort by date msgmap = valmap( lambda vs: sorted(unique(vs, key=operator.attrgetter("msgid")), key=operator.attrgetter("date")), msgmap) # Delete old messages msgidsToDelete = set() for lang, values in msgmap.items(): msgidsToDelete.update([v.msgid for v in values[:-1]]) server.delete_messages(msgidsToDelete) print("Deleted {0} messages".format(len(msgidsToDelete))) # Remove old messages from msgmap (keep only latest) return valmap(operator.itemgetter(-1), msgmap)
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()