Webmail Client
Although I’m a supporter and user of the Squirrelmail webmail package, I was given an assignment for csci4131 – Internet Programming during the spring of 2006 to implement a pop3-ssl/smtp-ssl webmail client in Python/CGI.
#!/soft/python-2.4-bin/python import cgitb cgitb.enable() import smtplib, getpass, sys, poplib, time, os, cgi, email, email.Message if os.environ.get('SSL_PROTOCOL', '') == '': print 'Location: https://' + os.environ['SERVER_NAME'] + os.environ['REQUEST_URI'] + "\\n\\n" ######## support functions def printHeaders(title, scriptname): print "Content-Type: text/html" print """ <?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>%s</title> <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=iso-8859-1" /> <style type="text/css"> body { font-family: Arial, Helvetica, Sans-Serif; font-size: 13px; } h1 { text-align: center; } h2 { color: #990000; } div#headers { background-color: grey; } div#headers span { display: block; float: left; width: 15%%; text-align: right; font-weight: bold; } div#headers span + span { display: block; float: left; width: 85%%; text-align: left; font-weight: normal; } </style> <script type=\\"text/javascript\\"> <!--""" % (title) if scriptname == "loginScript": print loginScript elif scriptname == "updateForm": print "var table = [" for record in table: print "['%s %s. %s', '%s', '%s', '%s, %s', '%s']," % (record[1], record[2], record[3], record[4], record[5], record[6], record[7], record[8]) print "]" print updateForm print """ --> </script> </head> <body> <h1>Csci4131 Lab11 - David R. Hedges, #2836226</h1>""" def printFooters(): print """ </body> </html>""" def connectPop(u_server, u_name, u_pass): try: pop = poplib.POP3_SSL(u_server) pop.user(u_name) pop.pass_(u_pass) return pop except: print "<h2>Unable to connect to server.</h2>" printPg1("none") return 0 ## page 1 ## this function prints the content of the first page (login). the one variable ## 'error' is used to set the display: property of the error message for the ## login page. acceptable values are "inline" (if the error message should be ## displayed), or "none" (if the error message should not be diaplayed). ################ def printPg1(error): print"""<form action="webmail.cgi" method="post" onsubmit="if (!validateInput()) {return false;}"> <h2>Login <span style="display: %s;">(Error: Invalid username/password)</span></h2> <div style="width: 250px; text-align: right; line-height: 24px;"> Server: <input type="text" name="server" size="20" value="jinxx060.email.umn.edu" /><br /> Username: <input type="text" name="username" size="20" value="jinxx060" /><br /> Password: <input type="password" name="password" size="20" /><br /> <input type="hidden" name="postPageNumber" value="1" /> <input type="submit" name="submit" value="Login" /> <input type="reset" name="Reset" value="Clear" /> </div> </form>""" % (error) ## print inbox ## the generic function to connect to a pop server(ssl) and print the list of ## messages contained in the inbox ############# def printInbox(u_server, u_name, u_pass): try: pop = poplib.POP3_SSL(u_server) pop.user(u_name) pop.pass_(u_pass) except: print "<h2>Unable to connect to server.</h2>" printPg1("none") else: numMessages = len(pop.list()[1]) msgList = [] msg = email.Message j = 0 print """<form action="webmail.cgi" method="post"> <input type="submit" name="Compose" value="Compose" /> <input type="submit" name="Delete" value="Delete" /> <input type="submit" name="Logout" value="Logout" /> <table style="width: 100%;"> <thead> <tr style="background-color: #114477; color: white;"> <th>Check</th> <th>From</th> <th>Subject</th> <th>Date</th> <th>Size</th> </tr> </thead> <tbody>""" for i in range(numMessages): msgList.append(pop.top(i+1,0)[1]) msgid = pop.uidl(i+1) ptr = msgid.index(str(i+1)) msgid = msgid[ptr+2:] #####3 # hack to skip using unique ids for the moment #### msgid = i+1 msgString = "" for k in msgList[j]: msgString += k + '\\n' msg = email.message_from_string(msgString) msgList[j] = msg print """ <tr> <td><input type="checkbox" name="delete" value="%s" /></td> <td>%s</td> <td><input type="submit" name="%s" value="%s" style="background-color: transparent; border: 0; border-bottom: 1px dotted black; color: blue;" /></td> <td>%s</td> <td>%s B</td> </tr>""" % (msgid, cgi.escape(msg.get("From"), True), msgid, msg.get("Subject"), msg.get("Date"), pop.top(i+1,0)[2]) j += 1 print """ </tbody> </table> <input type="hidden" name="postPageNumber" value="2" /> <input type="hidden" name="server" value="%s" /> <input type="hidden" name="username" value="%s" /> <input type="hidden" name="password" value="%s" /> </form>""" % (u_server, u_name, u_pass) pop.quit() def readMsg(u_server, u_name, u_pass, msgid): try: pop = poplib.POP3_SSL(u_server) pop.user(u_name) pop.pass_(u_pass) except: print "<h2>Unable to connect to server.</h2>" printPg1("none") else: msg = pop.retr(msgid) msgtext = "" for i in msg[1]: msgtext += i + "\\n" pop.quit() #now the message is stored in msgtext in a format that from_string() will like emsg = email.message_from_string(msgtext) print """<div style="width: 100%%;"> <form action="webmail.cgi" method="post"> <div style="width: 100%%; background-color: #114477; color: white;"><input type="submit" name="Inbox" value="Inbox" style="background-color: transparent; color: white; border: 0; border-bottom: 1px dotted white;" /> <input type="submit" name="Reply" value="Reply" style="background-color: transparent; color: white; border: 0; border-bottom: 1px dotted white;" /></div> <div id="headers"><span>Subject: </span> <span>%s</span><input type="hidden" name="subject" value="%s" /><br /> <span>From: </span> <span>%s</span><input type="hidden" name="from" value="%s" /><br /> <span>To: </span> <span>%s</span><br /> <span>Date: </span> <span>%s</span><br /> <span>Size: </span> <span>%s Bytes</span><br /> </div>""" % (cgi.escape(emsg.get("Subject", "No Subject"), True), cgi.escape(emsg.get("Subject", "No Subject"), True), cgi.escape(emsg.get("From", ""), True), cgi.escape(emsg.get("From", ""), True), cgi.escape(emsg.get("To", ""), True), emsg.get("Date"), msg[2]) if emsg.is_multipart(): multimsg = email.message_from_string(str(emsg.get_payload(0))) if multimsg.is_multipart(): multimsg = email.message_from_string(str(multimsg.get_payload(0, True))) if multimsg.get("Content-Transfer-Encoding") == "base64": print """ <pre>%s</pre><textarea name="body" rows="1" cols="76" style="display: none;">%s</textarea>""" % (multimsg.get_payload().decode("base64"), multimsg.get_payload()) else: print """ <pre>%s</pre><textarea name="body" rows="1" cols="76" style="display: none;">%s</textarea>""" % (multimsg.get_payload(), multimsg.get_payload()) else: print " <pre>%s</pre>" % emsg.get_payload() print """ <input type="hidden" name="postPageNumber" value="3" /> <input type="hidden" name="server" value="%s" /> <input type="hidden" name="username" value="%s" /> <input type="hidden" name="password" value="%s" /> </form>\\n</div>""" % (u_server, u_name, u_pass) def composeMsg(u_server, u_name, u_pass, msg_addr, msg_subject, msg_body): if u_name.find("@") == -1 and u_server.find("umn.edu") > -1: u_name += "@umn.edu" if msg_subject == None: msg_subject = "" print """<div style="width: 100%%;"> <form action="webmail.cgi" method="post"> <div style="width: 100%%; background-color: #114477; color: white;"><input type="submit" name="Inbox" value="Inbox" style="background-color: transparent; color: white; border: 0; border-bottom: 1px dotted white;" /> <input type="submit" name="Send" value="Send" style="background-color: transparent; color: white; border: 0; border-bottom: 1px dotted white;" /></div> <div id="headers"><span>To: </span> <span><input type="text" name="to" value="%s" size="40" style="border: 1px solid black;" /></span><br /> <span>From: </span> <span><input type="text" name="from" value="%s" size="40" style="border: 1px solid black;" /></span><br /> <span>Subject: </span> <span><input type="text" name="subject" value="%s" size="40" style="border: 1px solid black;" /></span><br /> <div style="clear: both; height: 1px"> </div> </div>""" % (cgi.escape(msg_addr, True), u_name, cgi.escape(msg_subject, True)) print """ <div style="width: 100%%; margin-top: 20px;"><textarea name="body" rows="10" cols="76">%s</textarea><br /><input type="submit" name="Send" value="Send" /></div>""" % msg_body print """ <input type="hidden" name="postPageNumber" value="4" /> <input type="hidden" name="server" value="%s" /> <input type="hidden" name="username" value="%s" /> <input type="hidden" name="password" value="%s" /> </form>\\n</div>""" % (u_server, u_name, u_pass) def sendMessage(u_server, u_name, u_pass, msg_to, msg_from, msg_subject, msg_body): from email.MIMEText import MIMEText from email.MIMEBase import MIMEBase from email.MIMEMultipart import MIMEMultipart from email import Utils, Encoders #hack to set smtp server to smtp.umn.edu if the user is using a umn email addy if u_server.find("email.umn.edu") > -1: smtp_server = "smtp.umn.edu" else: smtp_server = u_server msg = MIMEMultipart() msg['To'] = msg_to msg['From'] = msg_from msg['Subject'] = msg_subject msg['Date'] = Utils.formatdate(localtime = 1) msg['Message-ID'] = Utils.make_msgid() text = MIMEText(msg_body, _subtype='plain') #binary = MIMEBase('text', 'plain') #binary.set_payload(msg_body) #Encoders.encode_base64(binary) msg.attach(text) #msg.attach(binary) try: smtp = smtplib.SMTP(smtp_server) smtp.starttls() smtp.ehlo() smtp.login(u_name, u_pass) smtp.sendmail(msg_from, msg_to, msg.as_string()) except: print """<h2>Sending message failed.</h2><div>Please <a href="javascript:history.back()" title="back">go back</a> and try again.</div>""" else: print """<form action="webmail.cgi" method="post"> <h2>Message sent</h2> <div>Click <input type="submit" name="here" value="here" style="background-color: transparent; border: 0; border-bottom: 1px dotted black; color: blue;" /> to go back to the inbox.</div> <input type="hidden" name="postPageNumber" value="1" /> <input type="hidden" name="server" value="%s" /> <input type="hidden" name="username" value="%s" /> <input type="hidden" name="password" value="%s" /> </form>""" % (u_server, u_name, u_pass) ######## end support functions ##################### ################## ## scripts global loginScript loginScript = " function validateInput() {\\n if (document.forms[0].username.value == '') {\\n alert(\\"Please enter a username.\\");\\n return false;\\n }\\n if (document.forms[0].password.value == '') {\\n alert(\\"Please enter a password.\\");\\n return false;\\n }\\n return true;\\n}" ##################### ## end scripts form = cgi.FieldStorage() postPageNumber = form.getvalue("postPageNumber") if postPageNumber == None: postPageNumber = "0" if postPageNumber == "0": printHeaders("Login", "loginScript") printPg1("none") printFooters() elif postPageNumber == "1": u_server = form.getvalue("server") u_name = form.getvalue("username") u_pass = form.getvalue("password") printHeaders("Webmail - Inbox", "") printInbox(u_server, u_name, u_pass) printFooters() elif postPageNumber == "2": u_server = form.getvalue("server") u_name = form.getvalue("username") u_pass = form.getvalue("password") #check to see which button user clicked if form.getvalue("Compose") == "Compose": action = "compose" elif form.getvalue("Delete") == "Delete": action = "delete" elif form.getvalue("Logout") == "Logout": action = "logout" else: action = "read" ########### ## READ ########### if action == "read": for val in form: #msg id will be the name of the first populated form value msgid = val break printHeaders("Webmail - Read Message", "") readMsg(u_server, u_name, u_pass, msgid) printFooters() ########### ## DELETE ########### elif action == "delete": printHeaders("Webmail - Delete", "") pop = connectPop(u_server, u_name, u_pass) if pop != 0: for val in form.getlist("delete"): pop.dele(val) pop.quit() print """<form action="webmail.cgi" method="post"> <h2>Messages successfully deleted.</h2> <div>Click <input type="submit" name="here" value="here" style="background-color: transparent; border: 0; border-bottom: 1px dotted black; color: blue;" /> to go back to the inbox.</div> <input type="hidden" name="postPageNumber" value="1" /> <input type="hidden" name="server" value="%s" /> <input type="hidden" name="username" value="%s" /> <input type="hidden" name="password" value="%s" /> </form>""" % (u_server, u_name, u_pass) printFooters() ########### ## COMPOSE ########### elif action == "compose": printHeaders("Webmail - Compose", "") composeMsg(u_server, u_name, u_pass, "", "", "") printFooters() ############ ## LOGOUT ############ elif action == "logout": printHeaders("Logout Successful", "") print """<h2>Logout Successful</h2><div>You have been logged out of the webmail system. Click <a href="webmail.cgi">here</a> to log in again.</div>""" printFooters() elif postPageNumber == "3": u_server = form.getvalue("server") u_name = form.getvalue("username") u_pass = form.getvalue("password") #check to see which button user clicked if form.getvalue("Inbox") == "Inbox": action = "inbox" elif form.getvalue("Reply") == "Reply": action = "reply" if action == "inbox": printHeaders("Webmail - Inbox", "") printInbox(u_server, u_name, u_pass) printFooters() ########### ## REPLY ########### elif action == "reply": msg_from = form.getvalue("from") msg_subject = form.getvalue("subject") msg_body = form.getvalue("body") printHeaders("Webmail - Reply", "") composeMsg(u_server, u_name, u_pass, msg_from, msg_subject, msg_body) printFooters() elif postPageNumber == "4": u_server = form.getvalue("server") u_name = form.getvalue("username") u_pass = form.getvalue("password") #check to see which button user clicked if form.getvalue("Inbox") == "Inbox": action = "inbox" else: action = "send" if action == "inbox": printHeaders("Webmail - Inbox", "") printInbox(u_server, u_name, u_pass) printFooters() elif action == "send": msg_to = form.getvalue("to") msg_from = form.getvalue("from") msg_subject = form.getvalue("subject") msg_body = form.getvalue("body") printHeaders("Webmail - Sending Mail", "") sendMessage(u_server, u_name, u_pass, msg_to, msg_from, msg_subject, msg_body) printFooters()
Download this code: webmail.cgi