Eric Radman : a Journal

Simple Feedback Forms with Python CGI

Simple Job, Simple Script

formmail has worked well for me on several occasions, but I don't like being dependant on a large Perl script to do something as simple as submitting comments via e-mail. If the operation is kept simple then it can be easily adapted to specific requirements, and that's the goal here.

testform.html

I like the idea of embedding the basic paramiters of a form in hidden HTML fields because it puts control in the hands of the web page authors. To pass this information on I simply created a simple page that the webmaster I was working with could copy from.

<html>
<head>
<title></title>
<body>
<form action="/cgi-bin/submit.cgi" method="POST">
<input type="hidden" name="to" value="theman@eradman.com" />
<input type="hidden" name="from" value="sysadmin@teisprint.net" />
<input type="hidden" name="nextpage" value="../thankyou.html" />
<input type="hidden" name="subject" value="Online form submission" />
<table>
<tr><td>Name:</td><td><input type="text" name="name" /></td></tr>
<tr><td>E-mail:</td><td><input type="text" name="email" /></td></tr>
<tr><td colspan="2"><textarea name="message" rows="14"
cols="52"></textarea></td></tr> <tr><td></td><td><input type="submit"
/></td></tr>
</form>

There are a number of hidden fields in the form that you need to modify to make it work for you. from is where bounces will go. to is the destination address you want to send the messages to. subject is title of the messages it sends to your e-mail account. nextpage is the location you want to show after submitting the form. Right now it redirects their browser to ../thankyou.html

submit.cgi

First task is to make this script executable:

% chmod 755 cgi-bin/submit.cgi
#!/usr/bin/env python
import smtplib
import cgi
import os
from datetime import datetime
import string
import urlparse

def debug(message):
    print "Content-type: text/html"
    print """
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html PUBLIC
        "-//W3C/DTD XHTML 1.0 Strict//EN"
        "DTD/xhtml11-strict.dtd">
    <html>
    <head>Form Submission</head>
    <body>
    <pre>
    %s
    </pre>
    </body>
    </html>""" % message

def process_form():
    req_fields = {"from":None, "to":None, "subject":None, "nextpage":None}
    valid_urls = ["mycompany.org", "www.mycompany.org"]
    url = urlparse.urlparse(os.environ["HTTP_REFERER"])
    if url[1] not in valid_urls:
        debug("The site calling this script is not autnorized to send e-mail.")
        return
    form = cgi.FieldStorage()
    """
    Add extra data to the submission:
    """
    field_list = "\ndate: %s\n" % datetime.now().strftime("%A, %B %d, %Y")
    """
    Iterate through submitted form and check for required fields
    """
    for field in form.keys():
        value = form[field].value
        if req_fields.has_key(field):
            req_fields[field] = value
        else:
            field_list = field_list + "%s: %s\n" % (field, value)
    for key in req_fields:
        if req_fields[key] == None:
            debug("A required field is missing: %s" % key)
            return
    """
    Add the From: and To: headers at the start
    """
    msg = ("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n" %
        (req_fields["from"], req_fields["to"], req_fields["subject"]))
    msg = msg + field_list
    server = smtplib.SMTP("localhost")
    server.sendmail(req_fields["from"], req_fields["to"], msg)
    server.quit()
    """
    Output redirection instead of xhtml
    """
    print "Location: %s" % req_fields["nextpage"]
    print

if __name__ == "__main__":
    process_form()

The output of CGI scripts usually limited by the web server, so to diagnose this script run it from the command with a fake environment:

% env HTTP_REFERER="www.mycompany.org/feedback.html" ./submit.cgi

References

Using Python for CGI programming

Five minutes to a Python CGI

Dates and Times

The Simplest CGI Program

$ Thu Jan 29 08:22:53 -0500 2009 $