Read Programming Python Online

Authors: Mark Lutz

Tags: #COMPUTERS / Programming Languages / Python

Programming Python (163 page)

BOOK: Programming Python
6.03Mb size Format: txt, pdf, ePub
ads
New in the Prior Edition (Version 2.0)

In the third
edition, PyMailCGI was upgraded to use the new
mailtools
module package of
Chapter 13
, employ the PyCrypto package for
passwords if it is installed, support viewing and sending message
attachments, and run more efficiently. All these are inherited by
version 3.0 as well.

We’ll meet these new features along the way, but the last two of
these merit a few words up front. Attachments are supported in a
simplistic but usable fashion and use existing
mailtools
package code for much of their
operation:

  • For
    viewing
    attachments, message
    parts are split off the message and saved in local
    files on the server. Message view pages are then augmented with
    hyperlinks pointing to the temporary files; when clicked, they open
    in whatever way your web browser opens the selected part’s file
    type.

  • For
    sending
    attachments, we use the HTML
    upload techniques presented near the end of
    Chapter 15
    . Mail edit pages now have
    file-upload controls, to allow a maximum of three attachments.
    Selected files are uploaded to the server by the browser with the
    rest of the page as usual, saved in temporary files on the server,
    and added to the outgoing mail from the local files on the server by
    mailtools
    . As described in the
    note in the preceding section, sent attachments can only be
    compatibly encoded text in version 3.0, not binary, though this
    includes encodable HTML files.

Both schemes would fail for multiple simultaneous users, but since
PyMailCGI’s
configuration
file
scheme (described later in this chapter) already limits it to a single
username, this is a reasonable constraint. The links to temporary files
generated for attachment viewing also apply only to the last message
selected, but this works if the page flow is followed normally.
Improving this for a multiuser scenario, as well as adding additional
features such as PyMailGUI’s local file save and open options, are left
as exercises.

For efficiency, this version of PyMailCGI also avoids repeated
exhaustive mail downloads. In the prior version, the full text of all
messages in an inbox was downloaded every time you visited the list page
and every time you selected a single message to view. In this version,
the list page downloads only the header text portion of each message,
and only a single message’s full text is downloaded when one is selected
for viewing. In addition, the headers fetch limits added to
mailtools
in the fourth edition of this book
are applied automatically to limit download time (earlier mails outside
the set’s size are ignored).

Even so, the list page’s headers-only download can be slow if you
have many messages in your inbox (and as I confessed in
Chapter 14
, I have thousands in one of mine). A
better solution would somehow cache mails to limit reloads, at least for
the duration of a browser session. For example, we might load headers of
only newly arrived messages, and cache headers of mails already fetched,
as done in the PyMailGUI client of
Chapter 14
.

Due to the lack of state retention in CGI scripts, though, this
would likely require some sort of server-side database. We might, for
instance, store already fetched message headers under a generated key
that identifies the session (e.g., with process number and time) and
pass that key between pages as a cookie, hidden form field, or URL query
parameter. Each page would use the key to fetch cached mail stored
directly on the web server, instead of loading it from the email server
again. Presumably, loading from a local cache file would be faster than
loading from a network connection to the mail server.

This would make for an interesting exercise, too, if you wish to
extend this system on your own, but it would also result in more pages
than this chapter has to spend (frankly, I ran out of time for this
project and real estate in this chapter long before I ran out of
potential
enhancements).

Presentation Overview

Much of
the “action” in PyMailCGI is encapsulated in shared
utility modules, especially one called
commonhtml.py
. As you’ll see in a moment, the
CGI scripts that implement user interaction don’t do much by themselves
because of this. This architecture was chosen deliberately, to make
scripts simple, avoid code redundancy, and implement a common
look-and-feel in shared code. But it means you must jump between files
to understand how the whole system works.

To make this example easier to digest, we’re going to explore its
code in two chunks: page scripts first, and then the utility modules.
First, we’ll study screenshots of the major web pages served up by the
system and the HTML files and top-level Python CGI scripts used to
generate them. We begin by following a send mail interaction, and then
trace how existing email is read and then processed. Most implementation
details will be presented in these sections, but be sure to flip ahead
to the utility modules listed later to understand what the scripts are
really doing.

I should also point out that this is a fairly complex system, and
I won’t describe it in exhaustive detail; as for PyMailGUI and
Chapter 14
, be sure to read the source code along
the way for details not made explicit in the narrative. All of the
system’s source code appears in this chapter, as well as in the book’s
examples distribution package, and we will study its key concepts here.
But as usual with case studies in this book, I assume that you can read
Python code by now and that you will consult the example’s source code
for more details. Because Python’s syntax is so close to “executable
pseudo
code,” systems are sometimes
better described in Python than in English once you have the overall
design in mind.

Running This Chapter’s Examples

The HTML pages
and CGI scripts of PyMailCGI can be installed on any web
server to which you have access. To keep things simple for this book,
though, we’re going to use the same policy as in
Chapter 15
—we’ll be running the Python-coded
webserver.py
script from
Example 16-1
locally, on the same
machine as the web browser client. As we learned at the start of the
prior chapter, that means we’ll be using the server domain name
“localhost” (or the equivalent IP address, “127.0.0.1”) to access this
system’s pages in our browser, as well as in the
urllib.request
module.

Start this server script on your own machine to test-drive the
program. Ultimately, this system must generally contact a mail server
over the Internet to fetch or send messages, but the web page server
will be running locally on your computer.

One minor twist here: PyMailCGI’s code is located in a directory
of its own, one level down from the
webserver.py
script. Because of that, we’ll start the web server here with an
explicit directory and port number in the command line used to launch
it:

C:\...\PP4E\Internet\Web>
webserver.py PyMailCgi 8000

Type this sort of command into a command prompt window on Windows
or into your system shell prompt on Unix-like platforms. When run this
way, the server will listen for URL requests on machine “localhost” and
socket port number 8000. It will serve up pages from the
PyMailCgi
subdirectory one level below the script’s
location, and it will run CGI scripts located in the
PyMailCgi\cgi-bin
directory below that. This works
because the script changes its current working directory to the one you
name when it starts up.

Subtle point: because we specify a unique port number on the
command line this way, it’s OK if you simultaneously run another
instance of the script to serve up the prior chapter’s examples one
directory up; that server instance will accept connections on port 80,
and our new instance will handle requests on port 8000. In fact, you can
contact either server from the same browser by specifying the desired
server’s port number. If you have two instances of the server running in
the two different chapters’ directories, to access pages and scripts of
the prior chapter, use a URL of this form:

http://localhost/languages.html
http://localhost/cgi-bin/languages.py?language=All

And to run this chapter’s pages and scripts, simply use URLs of
this form:

http://localhost:8000/pymailcgi.html
http://localhost:8000/cgi-bin/onRootSendLink.py

You’ll see that the HTTP and CGI log messages appear in the window
of the server you’re contacting. For more background on why this works
as it does, see the
introduction
to network socket addresses in
Chapter 12
and
the discussion of URLs in
Chapter 15
.

If you do install this example’s code on a different server,
simply replace the “localhost:8000/cgi-bin” part of the URLs we’ll use
here with your server’s name, port, and path details. In practice, a
system such as PyMailCGI would be much more useful if it were installed
on a remote server, to allow mail processing from any web
client.
[
66
]

As with PyMailGUI, you’ll have to edit the
mailconfig.py
module’s settings to use this
system to read your own email. As provided, the email server information
is not useful for reading email of your own; more on this in a
moment
.

Carry-On Software

PyMailCGI works as planned and illustrates more CGI and email
concepts, but I want to point out a few caveats up front. This
application was initially written during a two-hour layover in
Chicago’s O’Hare airport (though debugging took a few hours more). I
wrote it to meet a specific need—to be able to read and send email
from any web browser while traveling around the world teaching Python
classes. I didn’t design it to be aesthetically pleasing to others and
didn’t spend much time focusing on its efficiency.

I also kept this example intentionally simple for this book. For
example, PyMailCGI doesn’t provide nearly as many features as the
PyMailGUI program in
Chapter 14
, and it
reloads email more than it probably should. Because of this, its
performance can be very poor if you keep your inbox large.

In fact, this system almost cries out for more advanced state
retention options. As is, user and message details are passed in
generated pages as hidden fields and query parameters, but we could
avoid reloading mail by also using server-side deployment of the
database techniques described in
Chapter 17
. Such extensions might
eventually bring PyMailCGI up to the functionality of PyMailGUI,
albeit at some cost in code complexity. Even so, this system also
suffers from the Python 3.1 attachments limitation described earlier,
which would need to be addressed as well.

Again, you should consider this system a
prototype
and a work in progress; it’s not yet
software worth selling, and not something that you’ll generally want
to use as is for mail that’s critical to you. On the other hand, it
does what it was intended to do, and you can customize it by tweaking
its Python source code—something that can’t be said of all software
sold.

[
66
]
One downside to running a local
webserver.py
script that I noticed during
development for this chapter is that on platforms where CGI scripts
are run in the same process as the server, you’ll need to stop and
restart the server every time you change an imported module.
Otherwise, a subsequent import in a CGI script will have no effect:
the module has already been imported in the process. This is not an
issue on Windows today or on other platforms that run the CGI as a
separate, new process. The server’s classes’ implementation varies
over time, but if changes to your CGI scripts have no effect, your
platform my fall into this category: try stopping and restarting the
locally running web server.

The Root Page

Let’s start off
by implementing a main page for this example. The file shown
in
Example 16-2
is primarily used
to publish links to the Send and View functions’ pages. It is coded as a
static HTML file, because there is nothing to generate on the fly
here.

Example 16-2. PP4E\Internet\Web\PyMailCgi\pymailcgi.html


PyMailCGI Main Page

PyMailCGI


A POP/SMTP Web Email Interface


Version 3.0 June 2010 (2.0 January 2006)





Actions





Overview



alt="[Book Cover]" border=1 hspace=10>

This site implements a simple web-browser interface to POP/SMTP email
accounts. Anyone can send email with this interface, but for security
reasons, you cannot view email unless you install the scripts with your
own email account information, in your own server account directory.
PyMailCgi is implemented as a number of Python-coded CGI scripts that run on
a server machine (not your local computer), and generate HTML to interact
with the client/browser. See the book Programming Python, 4th Edition
for more details.




Notes

Caveats: PyMailCgi 1.0 was initially written during a 2-hour layover at
Chicago's O'Hare airport. This release is not nearly as fast or complete
as PyMailGUI (e.g., each click requires an Internet transaction, there
is no save operation or multithreading, and there is no caching of email
headers or already-viewed messages). On the other hand, PyMailCgi runs on
any web browser, whether you have Python (and Tk) installed on your machine
or not.

Also note that if you use these scripts to read your own email, PyMailCgi
does not guarantee security for your account password. See the notes in the
View action page as well as the book for more information on security policies.

New in Version 2: PyMailCGI now supports viewing and sending
Email attachments for a single user, and avoids some of the prior version's
exhaustive mail downloads. It only fetches message headers for the list page,
and only downloads the full text of the single message selected for viewing.

New in Version 3: PyMailCGI now runs on Python 3.X (only),
and employs many of the new features of the mailtools package: decoding and
encoding of Internationalized headers, decoding of main mail text, and so on.
Due to a regression in Python 3.1's cgi and email support, version 3.0 does
not support sending of binary or incompatibly-encoded text attachments, though
attachments on fetched mails can always be viewed (see Chapter 15 and 16).

Also see:


  • The PyMailGUI program in the Internet directory, which
    implements a more complete client-side Python+Tk email GUI
  • The pymail.py program in the Email directory, which
    provides a simple console command-line email interface
  • The Python imaplib module which supports the IMAP email protocol
    instead of POP





ALT="[Python Logo]" border=0 hspace=15>

[Book]
[O'Reilly]

The file
pymailcgi.html
is the system’s root
page and lives in a
PyMailCgi
subdirectory which is
dedicated to this application and helps keep its files separate from other
examples. To access this system, start your locally running web server as
described in the preceding section and then point your browser to the
following URL (or do the right thing for whatever other web server you may
be using):

http://localhost:8000/pymailcgi.html

If you do, the server will ship back a page such as that captured in
Figure 16-2
, shown rendered in the Google
Chrome web browser client on Windows 7. I’m using Chrome instead of
Internet Explorer throughout this chapter for variety, and because it
tends to yield a concise page which shows more details legibly. Open this
in your own browser to see it live—this system is as portable as the Web,
HTML, and Python-coded CGI scripts.

Figure 16-2. PyMailCGI main page

Configuring PyMailCGI

Now, before you
click on the “View…” link in
Figure 16-2
expecting to read your own email, I
should point out that by default, PyMailCGI allows anybody to send email
from this page with the Send link (as we learned earlier, there are no
passwords in SMTP). It does not, however, allow arbitrary users on the
Web to read their email accounts without either typing an explicit and
unsafe URL or doing a bit of installation and configuration.

This is on purpose, and it has to do with
security constraints; as we’ll see later,
PyMailCGI
is written such that it never
associates your email username and password together without encryption.
This isn’t an issue if your web server is running locally, of course,
but this policy is in place in case you ever run this system remotely
across the Web.

By default, then, this page is set up to read the email account
shown in this book—address
[email protected]
—and
requires that account’s POP password to do so. Since you probably can’t
guess the password (and wouldn’t find its email all that interesting if
you could!), PyMailCGI is not incredibly useful as shipped. To use it to
read your email instead, you’ll want to change its
mailconfig.py
mail configuration file to
reflect your mail account’s details. We’ll see this file later; for now,
the examples here will use the book’s POP email account; it works the
same way, regardless of which account it
accesses.

BOOK: Programming Python
6.03Mb size Format: txt, pdf, ePub
ads

Other books

Krysalis: Krysalis by John Tranhaile
Turn Left at the Cow by Lisa Bullard
Who Killed My Husband? by Sheila Rose
The Darksteel Eye by Jess Lebow
Burn for You by Annabel Joseph
The Bookie's Daughter by Heather Abraham
The Cassandra Sanction by Scott Mariani