[Tutor] Use python to parse the subject line of emails, listen for and react to commands

Willie Sims willie14228 at outlook.com
Sat Feb 28 04:38:22 CET 2015


Sorry, I should clarify something No one has taught me anything, I have been trying to learn all this on my own. To be honest much of the code I have is taken from examples and modified for what I was trying to do. Talk about learning the Hard Way!!! 

I have actually made everything work
My test.py is simply a print ("it works")
The way I made it work was to execfile the subject +.py, Again this is a small embedded device (BeagleBone Black) that will be using a mobile hotspot for internet, the hotspot has a private ip (Verizon) so I cannot access the server from outside the network. As such and because I am looking for ways to minimize data usage I want to be able interact with the device through email commands...... 
The code is not pretty and I have no doubt that there are thousands of ways for it to be hacked or messed up since there is little to no error checking in it. I don’t know enough to do so yet sorry I am doing the best I can and have only started learning python a week ago. 
I still have to add in a more complex command system that will allow me to change a settings page. So for example if I sent an email to the devices registered email address with the command NEW_OWNER(EMAILADDRESS at EMAIL.COM),(PASSWORD) it would change the Owners email to the one listed in the subject and only accept emails from that email address if the password matches. 
My plan is to have an email template that the script will reply back with that will have the commands listed in html so when the command is clicked from the email it will automatically open the email app and add in the keyword in the subject line to help eliminate typo errors.. 

Each Keyword is an .py script that this script will start it does not yet have a way of doing more complex changes like what I listed above and while I wish I could say that I wrote all this script from scratch the truth is I butchered other scripts from examples and made it work. But It is helping me learn (ALONG WITH GIVING ME A LOT OF GRAY HAIRS) that being said I love how python can be SIMPLE or as complex as you need it!

Sorry for what may seem like dumb questions I really do want to thank all of you for your help! 
 
#!/usr/bin/env python

import sys
import imaplib
import getpass
import email
import email.header


EMAIL_ACCOUNT = "MYEMAIL at gmail.com" # the email account that py will check
EMAIL_FOLDER = "INBOX"
OWNER = "willie14228 at outlook.com"
COMMAND_FILE = open("output.txt","w")


def process_mailbox(M):

    rv, data = M.search(None, "From",(OWNER))
    if rv != 'OK':
        print "No messages found!"
        return

    for num in data[0].split():
        rv, data = M.fetch(num, '(RFC822)')
        if rv != 'OK':
            print "ERROR getting message", num
            return

        msg = email.message_from_string(data[0][1])
        decode = email.header.decode_header(msg['Subject'])[0]
        subject = unicode(decode[0])
        print '%s' % (subject)
        COMMAND_FILE.write('%s' % (subject)+'.py')
        COMMAND_FILE.close()
        EX = '%s' %(subject)+'.py' #save the subject as an name.py
        execfile (EX) # exe name as a py 
        
M = imaplib.IMAP4_SSL('imap.gmail.com')

try:
    rv, data = M.login(EMAIL_ACCOUNT, getpass.getpass())
except imaplib.IMAP4.error:
    print "LOGIN FAILED!!! "
    sys.exit(1)

print rv, data

rv, mailboxes = M.list()
#if rv == 'OK':
    #print "Mailboxes:"
    #print mailboxes

rv, data = M.select(EMAIL_FOLDER)
if rv == 'OK':
    print "Processing mailbox...\n"
    process_mailbox(M)
    M.select('INBOX')  
    M.store("1:*", '+FLAGS', '\\Deleted')  #Flag all Trash as Deleted
    M.expunge()
    M.close()
else:
    print "ERROR: Unable to open mailbox ", rv

M.logout()


-----Original Message-----
From: Danny Yoo [mailto:dyoo at hashcollision.org] 
Sent: Friday, February 27, 2015 7:27 PM
To: willie14228 at outlook.com
Cc: Python Tutor Mailing List
Subject: Re: [Tutor] Use python to parse the subject line of emails, listen for and react to commands

> That's nearly always a bad idea. eval is a big security risk, 
> especially if applied to external input. And as you've discovered, it 
> makes debugging into a bit of a nightmare.

Yes, I concur with Alan.  eval() is definitely the wrong tool here.
It's **extraordinarily** dangerous in the context of consuming arbitrary email input.

Did anyone teach you to use eval()?


An alternative approach to what you're considering is to define a mapping from command name to functionality.  A quick-and-dirty approach uses a dictionary, and may have enough power for what you're
trying to do.   Here's an example to demonstrate: let's say that we'd
like a calculator that takes a sequence of operations, like:

     zero
     inc
     inc
     double

and performs them in turn to zero out memory, increment, increment, and double.  (getting us four).

Here's a brief sketch of what this might look like:

########################################
def zero(n):
    return 0

def double(n):
    return n * 2

def inc(n):
    return n + 1

cmd_mapping = {
    'zero': zero,
    'double': double,
    'inc': inc
}

## Run the calculator:
memory = 0
for cmd_string in 'inc inc inc double double inc'.split():
    cmd = cmd_mapping[cmd_string]
    memory = cmd(memory)
print memory
########################################


Here, we let a string dictate what's being computed, but in a controlled fashion.  The "magic" here is the line:

    cmd = cmd_mapping[cmd_string]

which gets a function, which we can just call later on.  Since cmd_mapping is a dictionary whose contents we control, we know that the only command being looked up has to be in the cmd_mapping.

Compare vs. an eval-based approach.  Unlike an approach that uses eval(), if the command string contains bad values here, nothing too bad will happen: at worst, we'll see a reliable dictionary lookup error.  You'll even get a good line number in the stack trace!  If we were to use eval, we would not.  In the worst case, we might accidentally let an adversary dictate what our computer is going to do, against our wishes.


For more discussion why eval() is almost certainly not the tool you want to use, see:

    http://code.activestate.com/lists/python-tutor/33338/


More information about the Tutor mailing list