#!/usr/bin/env python # ------------------------------------------------------------------------------------------------------------------------- # # ----------------------------------------------------------------------------------------------------------------------- # # # # File Name : RboxRelay_Parse.py # # # # Author Name : Rick Saporta # # Author Email : RickSaporta@gmail.com # # Author URL : www.github.com/rsaporta # # # # Packages Called : imaplib, email, re, os, time # # # # ----------------------------------------------------------------------------------------------------------------------- # # ------------------------------------------------------------------------------------------------------------------------- # ''' Reads an email and sends info contained in the email's body to OSX notifier. Will check a designated imap email address Download all [unread] messages in an indicated mailbox Parse the body for an argument-string to send use with terminal-notifier Then call terminal-notifier with those arguments This should be scheduled as a crontab. Something like * * * * * /usr/bin/python /Full/Path/To/Here/RboxRelay_Parse.py >/dev/null 2>&1 ''' import imaplib, email, re, os, time ## PARAMETERS server ='imap.gmail.com' username='rboxrelay@gmail.com' password='rstats is great' # <~~~ CHANGE mailfolder='inbox' useOnlyUnread=True ## Notifier location ## Normally, one of these three (with possibly different V number) # notifier = "terminal-notifier" # notifier = "/usr/local/bin/terminal-notifier" notifier = "/usr/local/Cellar/terminal-notifier/1.5.1/terminal-notifier.app/Contents/MacOS/terminal-notifier" ## These are the flags used in the email relay to ## indicate the start/end of the command string start_flag = '' end_flag = '' ## Function to clean quoted strings def shellCleanQuotes(x, using_quotes): ## shorthand for single & double quotes s = "'" d = '"' ## us := 'using' ## nu := 'not using' ## options are only s, d. Anything else is an error. if using_quotes == s: us = s nu = d elif using_quotes == d: us = d nu = s else: raise NameError("using_quotes must be either single (\') or double (\") quotes") # going to wrap any (us) in (nu us nu) # then need to close the prev (us) and open the next (us) on the outside of the wrap replaceWith = us + nu+us+nu + us return x.replace(us, replaceWith) def checkAndParseEmail(): if useOnlyUnread: useThese = "UNSEEN" else: useThese = "ALL" ## Connect to server M = imaplib.IMAP4_SSL(server) ## Login M.login(username, password) ## Select folder to use. M.select(mailfolder) ## Get all the unique ids for the emails in the folder typ, ids_flat = M.uid('search', None, useThese) ## ids_flat come as a flat single string, eg ['23 25 26 32']. ## Split on space to ['23', '25', '26', '32'] ids = ids_flat[0].split() ## each id represents one email for nextid in ids: result, data = M.uid('fetch', nextid, '(RFC822)') ## Collect the body of the email. ## an email can have multiple payloads, and if so, must iterate msgs = [] bod = email.message_from_string(data[0][1]) if bod.is_multipart(): # print "MULTI\n" for payload in bod.get_payload(): msgs.append(payload.get_payload()) else: # print "SINGLE \n" msgs.append(bod.get_payload()) ## Generally, there should be just one msg per email. ## If there is more than one for msg in msgs: ## Find the start and end flags start = msg.find(start_flag) + len(start_flag) end = msg.find(end_flag) ## Load from start-to-end, trimming white space arg_string = msg[start:end].strip() ## Only execute command if there is an actual arg in the message if len(arg_string) > 0: ## x #### args is already coming in clean, so I'm adding duplicate quotes here ## x ## arg_string = shellCleanQuotes(arg_string, "'") cmd = notifier + " " + arg_string os.system(cmd) # Delay so that multiple messages do not come all at once time.sleep(1.5) ## // End of for-loop on ids print "\n====================\n processed " + str(len(ids)) + " emails\n====================\n" if __name__ == "__main__": checkAndParseEmail()