acmemail is a webmail application written in Perl. It enables multiple users to check their mail (residing on a POP3 or IMAP mail server) via the web using their web browser. Requirements: a web server, CGI access, Perl.
Quite a few such webmail applications exist -- features which separate acmemail from the competition include the fact that it fully supports MIME messages, that is has a "pretty" but simple user interface, and that security is very important to the development team.
acmemail doesn't aim to compete with Hotmail or any other such free email site at the moment because you need to have an existing POP3 or IMAP email account, CGI access on a web server, and currently quite a bit of spare time to set it up. This may change in the future.
The motivation for developing acmemail came from the fact that the company I was working for at the time had a very restrictive firewall. This meant that I couldn't check my mail from the outside. In this case both the POP3 server and the web server that acmemail was running on were behind the firewall -- which didn't let POP3 out, but did however let the web server serve pages to the outside world. Hence the need for a light-weight webmail solution.
acmemail's target market is small companies, departments, universities and even ISPs that wish to provide a webmail solution for their users.
The 2.0.x acmemail release (quite old now) had fairly limited capabilities: it was single user, could only handle POP3 servers, was hard to configure, and had little documentation.
The 2.2.x acmemail release is much more capable: it is multiuser, can use files or a real database to handle sessions, can handle IMAP servers and there have been a large number of bug fixes, as well as performance and security improvements.
However, it is still quite hard to customize acmemail and a great many changes are planned for the next version, code-named "Project Sparkle". Read about it in the section named "The future: Project Sparkle". We live in very exciting times.
And remember, it's "acmemail", not "Acmemail"!
acmemail has the following features:
The last one may not be true.
acmemail currently requires a number of programs to be installed. In fact, it mostly needs services rather than specific programs, so when necessary we'll list programs that acmemail has been developed with.
The most common platform used to develop acmemail is Linux, Apache, the University of Washington IMAP server, and sendmail or Exim. There is no real reason why acmemail shouldn't run under a non-Unix system such as Windows or MacOS -- we just haven't tried it ourselves. Feel free to do so and tell us how it went!
acmemail is freely available from its web site.
Installing acmemail is unfortunately quite a hard and long task. As we don't believe in reinventing the wheel, we use a lot of Perl modules from CPAN. All of these have to be installed, including the rather troublesome "Mail::Cclient". We haven't described a general method of installation -- instead we explain how to set acmemail up starting from a fresh Red Hat Linux 6.1 box.
If your setup isn't exactly a Red Hat 6.1 box then this may not quite work. We're in the process of automating this procedure, so this chapter will hopefully disappear some time soon. However, since everyone has a slightly different system and file layout, please read and understand this section -- sorry.
This will get everything working. You may want to change some of the way we've done things. You may want database support, not POS. This isn't the most efficient way of installing either. Still, at the very least this should prove as a guide. In the following text '(yak yak yak)' means the computer responds with about a couple of hundred lines of useless of uninteresting code you can ignore...
Download a copy of acmemail-2.2.4.tar.gz. From the directory acmemail is downloaded to do the following to extract the files and put them in the right place. Substitute the paths on your system as appropriate.
[mark@slave mark]$ su Password: [root@slave mark]# cd /home/httpd/cgi-bin/ [root@slave mark]# tar xvfz /home/mark/acmemail-2.2.4.tar.gz [root@slave cgi-bin]# rm -f acmemail-2.2.4.tar.gz [root@slave cgi-bin]# mv acmemail-2.2.4 acme [root@slave cgi-bin]# cd acme [root@slave acme]# chown nobody.nobody dope mime-tmp [root@slave acme]# mv mime-tmp ../../html [root@slave acme]# mv graphics/ ../../html/acmegraphics |
Okay, now reconfigure acmemail to run correctly by editing AcmemailConf.pm using the text editor of your choice and alter the methods to do the following...
sub image_path() { return '/acmegraphics/'; } sub smtphost() { return 'localhost'; } sub local_domain() { return 'example.com'; # you need to change this to your own domain } sub session_type() { return "POS"; # using files and Persistant::Object::Simple # return "Database"; # using a real database } # Where is the temporary mime directory? sub temporary_mime_directory() { return "../../html/mime-tmp/"; } # Where is the temporary mime directory? (in relation to the web server) sub web_temporary_mime_directory() { return "/mime-tmp/"; } |
To save and exit in emacs do a Ctrl-X Ctrl-S Ctrl-X Ctrl-C -- but I should hope you know that already... Likewise it's Esc, then :qw for vi.
I use the CPAN module whenever possible for several reasons. One, I don't have to guess what the distribution's package is. Two, CPAN takes care of package dependencies correctly. Three, local CPAN mirrors are just as fast as local Debian package mirrors. Four, distribution packages don't exist for every CPAN module, and are not always current.
While connected to the Internet do the following:
[root@slave acme]# perl -MCPAN -e shell; |
At this point if it's your first time running CPAN you'll need to answer a whole host of questions. On a Red Hat 6.1 box you can normally hit return for all questions but the ones on geography. Be sure to select follow.
cpan> install Bundle::CPAN |
This installs the latest version of CPAN, making your and my life easier, and also happens to install some of the modules that we want to install for acmemail anyhow. While you have the CPAN module running, install the rest of the required modules. Most of these modules should be installed already, so this will just ensure that the latest and greatest versions are installed.
cpan> reload cpan (yak yak yak) cpan> install CGI HTML::Entities Mail::Internet Mail::Cclient MIME::Entity (yak yak yak) cpan> install MIME::Parser Net::SMTP URI::Escape URI::WithBase CGI::Carp (yak yak yak) cpan> install Persistence::Object::Simple Date::Format Date::Parse cpan> get HDIAS/Mail-Cclient-1.5.tar.gz (yak yak yak) cpan> exit Lockfile removed. |
Now we have to install Mail::Cclient. Depending on your system, this could be either an easy or hard task. Installing this module requires that the header files for the c-client libraries be present on your system. There are two ways of getting them: as a small package included with your distribution, or with the IMAP server source distribution. If you are running a Linux distribution such as Debian, you can run 'apt-get install libc-client2001-dev' to install all the necessary libraries and header files. Other distributions and operating systems may or may not have similiar packages. Doing a search for 'c-client.h' may reveal which package it's in.
[root@slave /root]# cd ~/.cpan/build/Mail-Cclient-1.5 [root@slave /root]# perl Makefile.PL --client_dir=/usr/lib --with-cclient-includes=/usr/include/c-client --with-shared_cclient [root@slave /root]# make (yak yak yak) [root@slave /root]# make install |
If you don't have the headers and libraries for c-client installed, you will need to download and compile the UW IMAP server source code (1.8MB): Now get the (1.8MB) source distribution that this module relies on. This may already be on your distributions source CD-Roms, but I find it easiest to just download it from the U of W's FTP server. Once it's installed, Mail::Cclient can be compiled.
[root@slave /root]# wget ftp://ftp.cac.washington.edu/mail/imap-2001a.tar.Z [root@slave /root]# gunzip -c imap-2001a.tar.Z | tar -xf - [root@slave /root]# cd imap-2001a [root@slave imap-2001a]# make slx (yak yak yak) [root@slave /root]# cd ~/.cpan/build/Mail-Cclient-1.5 [root@slave Mail-Cclient-1.5]# perl Makefile.PL --client_dir=../imap-4.7b/c-client/ (yak yak yak) [root@slave Mail-Cclient-1.5]# make (yak yak yak) [root@slave Mail-Cclient-1.5]# make install (yak yak yak) |
Note: If you get lots of "sv_undef undeclared" errors, add "POLLUTE=1" to the "perl Makefile.PL..." command.
Okay, that should have installed everything. We'd better clear up after ourselves, but you might want to leave these installation files around till you're sure everything has worked, and come back and delete them at the end.
[root@slave Mail-Cclient-1.5]# cd [root@slave /root]# rm -rf imap-2001a |
Phew! In theory, you should be almost ready to test your acmemail installation. If you notice Perl errors in your Apache server error logs about not being able to find some modules, you can easily install them using the CPAN module. For example, if it complains that Missing::ModuleName could not be loaded, do this:
[root@slave /root]# perl -MCPAN -e shell; cpan> install Missing::ModuleName (yak yak yak) |
Your system probably isn't set up for IMAP, even if you did install the right RPMs at install time. You'll need to edit your inetd file like so...
[root@slave acme]# emacs /etc/inetd.conf & |
You're looking for the line which reads
#imap stream tcp nowait root /usr/sbin/tcpd imapd |
Remove the hash (the '#') from the front, save and exit emacs, and then restart your server with this command :
root@slave init.d]# /etc/rc.d/init.d/inet restart Stopping INET services: [ OK ] Starting INET services: [ OK ] |
In order to clear up after yourself you need to periodically clear house on the old and out of date files. To do this you need to add the following lines to /etc/cron.daily/tmpwatch:
/usr/sbin/tmpwatch -m 20 /home/httpd/html/mime-tmp /usr/sbin/tmpwatch -m 20 /home/httpd/cgi-bin/acme/dope |
Boot up your browser of choice and go to: http://127.0.0.1/cgi-bin/acme/acmemail.cgi (Or maybe that should be https:// if you are running this under SSL/TLS) And try thing out. Good luck.
If all goes to plan you should see a login prompt. Try typing in your user name and password (you have set up a mail account on the server haven't you?) and you should display a list of messages in your inbox. If you don't have any messages then either:
Then list the messages again. Now click on one of the subject lines and, hopefully, the message should be displayed. Try sending yourself some test messages, ones with an image, a binary file or a web page attached. Try multiple attachments. Try sending yourself a forwarded message. If all these work then you're definitely getting somewhere. Try replying, forwarding and just plain sending a message. Try attachments. Try life, Try a great big TV. Try apologizing for ripping off Trainspotting adverts.
Annnnywaaaay. Back on the plot.
There are quite a few temporary files in acmemail, and we would like to restrict direct viewing of these files / directories. In Apache this can be done by adding the following lines to the Apache configuration file (probably httpd.conf):
<Directory /home/httpd/html/mime-tmp> Options None # no options means no indices/browsing </Directory> |
Note that as of version 2.2.4, the only files that get stored in mime-tmp are in-line images (as opposed to attached images) but still, you may want to protect them a bit, right?
Above we've just set up acmemail to use POS (Persistant::Object::Simple) sessions. Unfortunately this doesn't scale very well, so if you want to have more than a couple of acmemail users, you should use a database to store the sessions.
We're not going to explain how to configure or install a database -- that's way outside the scope of this document. Acmemail current ships with scripts to set up the database tables for MySQL and PostgreSQL. Scripts for other databases will be similar.
Note that for the following you'll need to have a username/password which can create a database and tables. You may have to amend the scripts.
With MySQL (given a username/password), something like the following should do:
% mysqladmin create acmemail Database "acmemail" created. % mysql acmemail < mysql.sql |
With PostgreSQL (given a username/password), something like the following should do:
% su - postgres [postgres@leonsplace pgsql]$ createdb acmemail [postgres@leonsplace pgsql]$ psql acmemail < postgresql.sql [postgres@leonsplace pgsql]$ exit |
Once that has been done, you have to change various parameters in AcmemailConf.pm. An example fragment showing the options that need to be changed:
# What kind of sessions are we going to use? sub session_type() { # return "POS"; # using files and Persistant::Object::Simple return "Database"; # using a real database } # If using the Database session type... # What is the datasource for our database? sub db_datasource() { return "dbi:mysql:acmemail:localhost"; # for MySQL # return "dbi:Pg:dbname=acmemail"; # for PostgreSQL } # If using the Database session type... # What is the username for access to the database sub db_username() { return "acme"; } # If using the Database session type... # What is the password for access to the database sub db_password() { return "thisisasecretpassword"; } |
Problem: You get weird errors about undefined values in Database.pm. Solution: You haven't set up the database correctly, check it and try again.
Problem: You keep getting "can't log in" messages. Solution: check that you've set the right mail server and that you have actually got an account there and that you've typed the username and password in properly.
Problem: You get a web server error with something like "Can't locate Joe/Bloggs.pm in @INC". Solution: This means you're missing the Joe::Bloggs module. Go find it on CPAN and install it.
Problem: You're tired and can't think of any more 'common problems to write'. Solution: Post documentation you've just written to mailing list and hope for the best (laziness, impatience and hubris etc. etc.)
Problem: You get lots of "sv_undef undeclared" errors while installing Mail::Cclient. Solution: Add "POLLUTE=1" to the "perl Makefile.PL..." command.
Security is very important aspect of a webmail program -- Hotmail, for example, has consistently had security problems in the past. Bugtraq (a security mailing list) notes that many webmail programs are vulnerable to trivial exploits. Acmemail attempts to be as secure as possible (well, as secure as most people will tolerate, what with security and usability often being at odds) by default, although it will allow you to do unsecure things if it is more convenient for you (or to enforce more secure rules if your users will let you get away with that: look for the phrase "SECURITY" in the list of settings in AcmemailConf.pm).
There are actually quite a few different aspects of security involved with a webmail program. I'll try and cover everything in as much depth as possible.
Let's make this quite clear: the server side is the web server and the mail server that acmemail is running on or accessing -- these may even be the same machine. We need a username and password to connect to the mail server, so we store this as a session in either a POS file or a database.
The risk here is that you may have users on the web server. If you are simply using POS sessions, the usernames and passwords are visible to anyone in the DOPE directory. There are ways of restricting this, but we much rather prefer database sessions -- the database takes care of the security aspect for us.
With previous versions of acmemail, the usernames and passwords were kept in the clear inside the database (or DOPE/POS files). Thus if the database or DOPE directories were compromised, so would be all your usernames and passwords. No more. Well, unless you change the setting for encrypt_password(). As of version 2.2.4, acmemail by default uses a one-time-pad like approach to protecting the stored passwords. acmemail will attempt to set a cookie in the user's browser (or otherwise manipulate the URLs) so that anyone who breaks into the database (or DOPE directories) won't be able to decipher the passwords, or, in fact, even know their exact lengths. The cookie approach is generally considered more secure than the URL manipulation, so this is one reason you might choose to force_cookies().
Note that the installation instructions put the DOPE directory outside the web server root -- this is so that web users will not be able to access passwords or other sensitive information. As of version 2.2.4, most attachments are written to the DOPE directory (even if using database sessions) and only displayed through acmemail itself, for better security.
You should consider running acmemail on a secure server (SSL) -- that way the username and password isn't sent over the network whenever a user logs on.
Currently, emails are unpacked onto disk before being displayed if they are larger than a certain size (1 MB -- see acme_mem_parse_buffer()). You might consider this a problem if you have users on that machine. This is going to be replaced with decoding on the fly in the next major release.
Ideally, the web server that acmemail is running on should be user-less. This solves many other problems.
The main problem with the client side of webmail programs is to never disclose the session ID. Classically, exploits achieve this by looking at the 'referer' field when a user clicks on a link or views a graphic embedded in a mail message.
One way to reduce this threat is to not keep the session ID as a CGI parameter but instead as a cookie on the client acmemail makes sure to only set cookies which do not have an expiration date -- this means the browser never saves them to disk. The cookie is expired when the user logs out. acmemail has a force_cookies() option to force people to use cookies in this way. This is enabled by default.
As an additional precaution, acmemail now "anonymizes" all regular hyperlinks in email messages. But not image references. So clicking on links is generally safe, but simply reading HTML messages can reveal important information unless you have set force_escape_html() to something more secure (and annoying) than its default value of "0".
There is the risk that JavaScript may be embedded into a mail message somehow -- the code would retrieve the session ID and then do something evil. Historically, it has been very tricky trying to filter away Javascript, so acmemail goes the whole way and can force you to disable JavaScript completely with the force_nojavascript() option. This is enabled by default.
However, forcing people to disable JavaScript is quite a strong option - your users will probably complain. It is for this reason that we have the force_defang_html() option. This will attempt to disable malicious HTML, although note that this may not be 100% effective. This is enabled by default.
Also, as of version 2.2.4, acmemail has introduced two new concepts: the "control" value and the "messagekey". The control value is not presented (passed as a cookie or included in the URL) when reading a message or displaying an attachment. This prevents an attacker from doing nasty things like sending emails against your will. The messagekey is used to further limit what an attacker who sends a hostile message can do. Not only can they not do dangerous things like send email on your behalf; they cannot even read other messages inyour mail folders.
acmemail hasn't gone under a lot of performance testing, but it is sufficiently fast on normal hardware for small groups (say a couple hundred people in total). If you wish to scale beyond this, there are various things you should have a look at.
Here we're going to talk about basic acmemail support under normal CGI. There are a number of performance limitations:
IMAP is known to be significantly slower than POP3 so finding a quick IMAP server is fairly important. The IMAP server bundled with Red Hat 6.1 for example, is the University of Washington IMAP server. An alternative server which is known to be more scalable is the Cyrus IMAP server. However, we haven't benchmarked these -- if you do, please let us know!
Luckily, there
mod_perl embeds a Perl interpreter into Apache server -- this avoids the overhead of starting an external interpreter and the penalty of Perl start-up time. It even caches the compiled Perl bytecode, giving us a great speedup. This alone should make acmemail from about two to ten times faster (but please do your own benchmarks and send them in!).
In addition to mod_perl you'll also want Apache::DBI, a Perl module available on CPAN. This lets you have persistent database connections, thus saving you from any slow database connections. That is: the slow part in talking to a database is actually connecting to it (getting the database handle) -- once connected acmemail only does simple queries so these can be quite fast. Apache::DBI effectively has a pool of database handles and hands these out instead of connecting every time.
Installing mod_perl is a bit challenging as it needs to be compiled in with the Apache server -- see the mod_perl developer guide for that. Installing Apache::DBI should be fairly easy -- it's just another CPAN module.
Enabling mod_perl and Apache::DBI is done by simply adding the following to your Apache configuration file. Note that you should also change 'acmemail.cgi' to 'acmemail.pl'.
PerlModule Apache::DBI <FilesMatch "\.pl$"> SetHandler perl-script PerlHandler Apache::Registry Options ExecCGI PerlSendHeader On </FilesMatch> |
Note: There is a major disadvantage to mod_perl -- your Apache processes will use up a great deal more memory. You should plan for this. Also note that mod_perl is a complex program and that tuning Apache and mod_perl for optimum performance is a tricky thing to do, but at least this will help!
Summary: with a bit of work and some higher memory usage, acmemail is able to scale much higher than its original limit. There still remains the problem of IMAP connections -- it's possible that connection pooling will be implemented in a future release.
Well, like any other CGI program acmemail is a state machine. Like a normal program CGI programs must store their state as GET or POST variables or in a persistent objects.
This is in no way meant to be complete or totally accurate documentation of the internal workings of acmemail but it's a start if you want to start looking into the code.
Displays the login box.
Lists messages in the mailbox you have selected. For POP3 this is always the INBOX but for IMAP that could be any of the mailboxes you're subscribed to.
Each line gives information about a message; whether or not you've read this before, who it came from, whether or not it has an attachment, the time it was sent and gives you the option to delete it either individually or en masse.
The subject line is a link to show the message and the name of the person who sent it is a link to compose a message to that person.
Takes either an individual message or a list of messages, deletes them and then lists messages again.
Shows an individual message by recursively MIME decoding each
section if there are any. If it's an image (such as a GIF) it saves
it and decodes it, saves and then display it inline (
There are links to reply, reply to all and forward the message and
the name of the sender and other people on the Cc list are turned
into links to compose to that person. (Note: this is
Displays all the usual boxes plus one for attachments. Currently no-one can think of a decent way of doing multiple attachments. Bruno Daniels has produced a quick patch that just displays multiple attachment boxes. We'd prefer not to pass round file attachments as parameters (oooh, baaaaaad overheads) or storing the uploads as temporary files but... there's a pint for the first person to come up with something good. Time to look to see how other people do it.
Gets the message body, adds quote marks, sets the to or cc parameters and then calls compose.
MIME encodes what it needs to encodes, sends the mail, and then displays your list of mails.
Of course there are plenty of other auxiliary functions for mangling HTML links, recursively decoding MIME etc. etc.
One of the big problems currently is that HTML formatting is done within lots of different functions which makes it a pain to change the layout and formatting. Hopefully this will change soon. Which leads us neatly onto ...
The future is bright. The future is Sparkle. Ever since he got bored at work one day, had a couple of pints at lunchtime and got ideas above his station (grin) Mark Fowler has been working on a new development tree of acmemail called, for reasons known only to himself, "Project Sparkle". Basically acmemail suffers from its original purpose in that it was never designed to be a totally web based, fully-functional email client. Whilst it's been ripped to shreds and reinvented itself so many times even Madonna's taking notice, it's about time acmemail had a complete rewrite.
The plan is to make it much more modular so that adding features will be easier rather than the current system of shoe-horning them into the existing structure. Things planned for this are:
Basically, you think acmemail needs a feature, write it, send in a patch to the mailing list, and it may or may not be included. Something broken? Ditto. Looking for ideas? Take a gander at the list above or check out the other web-based email clients listed below and steal / be inspired by their feature list.
Coding not your idea of fun? Help with the documentation. Or try get it running on as many different systems and configurations as possible then tell us how you did it and how well it runs.
If we ever get them implemented then write stuff for different languages or write different themes. The list goes on.
"We will fight them on the beaches, we will fight them on the sons of beaches" -- Miguel Churchill, Winston's bastard Mexican brother.
Not really. We don't actually hate people who've written alternatives to acmemail so don't get any funny ideas about hunting them down like dogs. For those people who even considered it for the merest second, find a pony, stroke it and repeat after me "Free Software does not mean brutally slaying people who are writing apps similar to mine". Or something. Remember Open Source(tm) and competition are good things. Although try telling that to Microsoft.
Arrowmail first appeared looking suspiciously like acmemail, even down to the non-transparent GIFs. Now being sold for large quantities of money.
AtDot seems quite spartan, but the new development release shows promise.
IMHO seems simple to install and lots of features. Written for the Roxen web server.
IMP seems quite popular. Written in PHP.
TWIG has turned into a groupware product. Very low bandwidth and simple. Written in PHP.
WebMail seems quite cool. Written in Java.
WING seems very professional and scalable -- currently being used at Oxford with thousands of users. Functional. Written in Perl and for mod_perl.
Please insert names, URLs, and descriptions here. We need some more reviews, and it would be good if they were in depth too. Why should people choose acmemail over any of these?
acmemail is Copyright (c) 1997-2002 Leon Brocard and others. All rights reserved.
You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
Leon Brocard wrote the original acmemail. Some of the developers live in the UK (Leon, Mark, Pete, Simon) while others are scattered around the globe. Development is carried out via a developer mailing list, so it doesn't really matter what timezone you're in!
The full list of developers and contributors in alphabetical order follows -- write in if you think you've been missed! Note that a couple people have pushed acmemail in the right direction but haven't actually written code. They are the unsung heroes. We salute them.
See the ChangeLog file distributed with acmemail.
This documentation was originally written by Simon Wistow. The new installation section was written by Mark Fowler. Leon Brocard has amended, reformatted, rephrased and added the security, and performance sections. Wim and Peter have updated the whole enchilada for the 2001 code changes. Some others have submitted small patches in 2002.