8.3.9 Creating a Mailing List

8.3.9  Creating a Mailing List

 A simple electronic mailing list can be implemented with the assistance of a text file that contains a number of e-mail addresses, one per line. The file is associated with a system mail alias. An alias is a(n alternate) name or a short-cut. The mailing list file is tied to an alias that is recognized by the mail program used by the operating system. It is also possible to create mail aliases that are known locally within the context of an individual user’s account. The purpose of creating a system mail alias is that it can be treated just like the name of a user on the system. Assume, we do not have a user with the name assam on
our system, say, pikespeak.uccs.edu. Now, we create a system mail alias assam. After this, we can send an e-mail to the newly created alias as assam@pikespeak.uccs.edu. When anyone sends an e-mail to assam@pikespeak.uccs.edu, the e-mail is automatically forwarded to every e-mail in the mailing list file.

Our discussion is with respect to a machine running Red Hat Linux. The creation of a system alias for mailing purposes is quite similar in other Unix and Unix-like machines including Mac OS X, although the file names may be different. On the Red Hat Linux machine, system aliases are created by placing an entry in the file /etc/aliases. On a Mac OS X machine, the system alias file is also located at the same place. One must have root or super-user access to edit this file. The discussions here do not apply to a Windows machine.

If we have a mailing list that is private and contains only a few email addresses, we can maintain it manually. However, if it is a public list, with say, several hundred or more e-mail addresses, maintaining it becomes a time-consuming chore. In such a case, it makes sense to automate the process of adding and removing addresses from the list. We allow any interested individual to add his or her e-mail address to the mailing list by going to a site on the Web and after providing a little information. We call this subscribing to the mailing list. We also allow an individual to automatically unsubscribe from the mailing list provided the individual can answer a few simple personal
questions whose answers were provided by the individual at the time of subscription. A real mailing list manager must be a lot more complex. The example we discuss here is fairly simple.

We now discuss a modification of the program from the previous sections so that we allow subscription to a mailing list. The program in the previous section simply echoed the information the potential subscriber entered in the form. The form remains the same as before except that we now have an ACTION URL that does additional work. The steps performed for creating a subscription program are discussed below.

•    We create a global mail alias called assam by editing the /etc/aliases file.

•    We present the user with an HTML form. The HTML page is called subscribe.html and looks exactly like the one seen in Figure 8.10 except that the ACTION URL for the form is different. Specifically, the HTML file is located at

/home/kalita/public_html/subscribe.html and is accessible on the Web with the URL

http://pikespeak.uccs.edu/cgi-bin/kalita/subscribe.html.

•    The form data is captured by the CGI program just like we see in the previous section. The CGI program is called assamListSubscribe.pl. The URL for the CGI program is

http://pikespeak.uccs.edu/~kalita/assamListSubscribe.pl. The CGI program stores the captured form data in a text file called assamList.txt using a very simple format where the data fields are separated from each other by a pre-specified field separator string. The text file is located in the same directory as where the CGI program is located.

•    There is a companion program called updateAssamList.pl that updates the actual mailing list file containing the e-mail addresses, one per line. The companion program is located in the same directory as the CGI program. This program reads the file assamList.txt and parses out the e-mail addresses from among all the other details, and creates the actual mailing list file that contains only the e-mail addresses. The mailing list file is located at

/home/kalita/mailing-lists/assam.dis.

•    We use Unix crontab to run updateAssamList.pl the file once every 24 hours. As a result, the mailing list is updated every day. There is an associated Web page for unsubscribing as well. The CGI program for unsubscribing removes any entry from the intermediate data file assamList.txt. Thus, the new additions and deletions are carried out once a day. The crontab facility allows one to periodically run a specified program at certain specific instances
of time. For example, one can run a program every minute, or every hour, or every day, or every week, or every Monday, etc.

In a sophisticated mailing list program, it is likely that one would use a database to store details about a subscriber, and not a text file like assamList.txt. We discuss how databases can be accessed from within a Perl program, whether CGI or not, in Chapter 10. In addition, there must be a way to automatically remove addresses from which e-mails sent bounce and hence, are wrong.

We now go through each step in detail. The discussion is in the context of a Linux machine running Red Hat Linux, and may have to be adjusted for other systems. The first step is to edit the file /etc/aliases and enter a line for the assam alias. The contents of the file after entering this line may look like the following.

 

#

# @(#)aliases 8.2 (Berkeley) 3/5/94

#

#  Aliases in this file will NOT be expanded in the header from

#  Mail, but WILL be visible over networks or from /bin/mail.

#

# >>>>>>>>>> The program "newaliases" must be run after

# >> NOTE >> this file is updated for any changes to

# >>>>>>>>>> show through to sendmail.

#

# Basic system aliases -- these MUST be present.

MAILER-DAEMON:  postmaster

postmaster:  root

# General redirections for pseudo accounts.

bin:  root

daemon:  root

games:  root

ingres:  root

nobody:  root

system:  root

toor:  root

uucp:  root

# Well-known aliases.

manager:  root

dumper:  root

operator:  root

# trap decode to catch security attacks

decode:  root

# Person who should get root's mail

#mailing lists; run `newaliases' every time something is changed below

cs-faculty:  :include:/home/kalita/mailing-lists/cs-faculty.dis

aol:  :include:/home/kalita/mailing-lists/aol.dis

assam:  :include:/home/kalita/mailing-lists/assam-list.dis

 

  The file comes with a few pre-defined aliases for useful or well-known system aliases. The line added for a user-defined alias has the syntax

alias: :include:mailing-list-file

The e-mail addresses for the assam alias are in the file /home/kalita/mailing-lists/assam-list.dis.

The next step is to create an HTML file visible on the Web for potential subscribers to the mailing list. This HTML file looks exactly like the one in Figure 8.10. The only difference is that the form’s ACTION URL has been changed. The new FORM tag looks like the following.

 

<FORM METHOD="POST"

   ACTION="http://pikespeak.uccs.edu/cgi-bin/kalita/assamListSubscribe.pl"

   >

 

 Note that the actual HTML file contains several JavaScript scripts to examine the validity of the data entered. JavaScript runs on the client and thus allows data validation code to be executed on the client itself, obviating the need for data transmission across the Internet. The reader is advised to read a book such as QuickStart to JavaScript [Lin99], JavaScript for the World Wide Web [NS98], and JavaScript : The Definitive Guide [Fla00]. The next step is writing the CGI program referenced in the form’s ACTION URL. The CGI program is given below.

 Program 8.9

#!/usr/bin/perl -Tw
#assamListSubscribe.pl

use CGI qw(:standard);
use CGI::Carp qw(fatalsToBrowser);
use Untaint;
use strict;

##########
$CGI::POST_MAX = 1024; #max 1024 bytes posts
$CGI::DISABLE_UPLOADS = 1; 

#############global declarations
my $assamListDetailsFile = "assamList.txt";
my $separator = ":::";

#print header ();

##########################
my $email = param ("email");
$email = untaint (qr/^[\w.]+@[\w.]+$/, $email);
my $firstName = param ("firstName");
$firstName = untaint (qr/^[a-z]+$/i, $firstName);
my $lastName = param ("lastName");
$lastName = untaint (qr/^[a-zA-Z]+$/, $lastName);
my $address = param ("surfaceAddress");
$address = untaint (qr/^[\d\w\s,.]+$/, $address);
my $telephone = param ("telephoneNumber");
$telephone = untaint (qr/^\d{3} ?\d{3} ?\d{4}$/, $telephone);
my $motherName = param ("motherMaidenName");
$motherName = untaint (qr/^[a-zA-Z]+$/, $motherName);
my $homeTown = param ("homeTown");
$homeTown = untaint (qr/^[a-zA-Z]+$/, $homeTown);

########################
###Read the data file. This is not the mail alias file where the
#email addresses are stored for the mailer. 
open (IN, "$assamListDetailsFile") or 
   warn "Cannot open $assamListDetailsFile: $!";
#   my @allLines = ;
my @allLines = ();
while (){
#    print "line= ", $_, "
"; $_ = untaint (qr/^.{1,200}$/, $_); @allLines = (@allLines, $_); } close IN; my ($selectedLine) = grep /^$email$separator/, @allLines; #print "selected line = $selectedLine
\n"; #######Write to browser print "Content-type: text/html\n\n"; print q{ Subscribe to Assam List

Subscribing to Assam List

}; #If the email already exists in the database if ($selectedLine){ print q{

Unable to Subscribe to Assam List

The e-mail address you have specified is already subscribed to to the Assam mailing list. You have thre options available.
  • If the email address is yours, remove the email address first and resubscribe. Go to the Web page for Unsubscribing and remove the email address first using the form available.
  • Use another email address. Click on the Back button of the browser and change the email address in the form.
  • If you do not know what to do, please write to please write to Jugal Kalita.
}; } else{ #If the email doesn't exist in the database #Process the input data, write it into a file, append to the file my $newLine = "$email" . $separator; $newLine .= "$firstName$separator$lastName$separator"; $newLine .= "$address$separator$telephone$separator"; $newLine .= "$motherName$separator$homeTown\n"; # print "newline = $newLine
"; open (OUT, ">$assamListDetailsFile") or warn "Cannot open $assamListDetailsFile: $!"; # print OUT sort (@allLines, $newLine); @allLines = sort (@allLines, $newLine); print OUT join "\n", @allLines; close OUT; chmod 0666, $assamListDetailsFile; print qq{ This is the data you entered.

Email: $email
First Name: $firstName
Last Name: $lastName
Address: $address
Telephone Number: $telephone
Mother's Maiden Name: $motherName
Home Village/Town/City: $homeTown
It will take a day or so for you to start receiving mail messages. Please be patient. If you do not get mail messages from the list within this time, please write to Jugal Kalita.

}; } print q{ Thank you!

Assam List Administrators

};

The program’s purpose is to create a file called assamList.txt. It uses the separator ::: to concatenate subscriber data before writing a line per user in the file. The $assamListDetailsFile variable is set to the name assamList.txt. We make the assumption that the file was already created with nothing in it to begin with. All data provided by the subscriber are captured. The file is opened, and any lines of data in it are read into the variable
@allLines. Note that in a more sophisticated program, one should use a relational database, instead of a flat text file. If the e-mail address provided by the potential subscriber already exists, the program does not add the line, but writes a message on the returned Web document. This document is shown in Figure 8.12.

 

Figure 8.12:  Subscription Error Response

If the e-mail address does not exist in the file, the $newLine variable is assigned the string obtained by concatenating the data provided by the user. The $newLine string is added to all the lines that were obtained from the data file. THe $assamListDetailsFile is re-written after the lines are sorted alphabetically. The data fields entered by the potential subscriber are echoed back to the browser, just like the way we saw it in the previous section. At this point, the
assamList.txt
file has been updated to reflect the new subscriber. Note that we have used the q and qq operators to quote long strings of multiple-line HTML code instead of using “here documents.” q and qq each takes one argument. q does not interpolate scalar and list variable names within the string whereas qq does. In this respect, they are like single-quoted and double-quoted strings.   

However, the assamList.txt file is the data file or the “database”. One line in the file assamList.txt looks like the following. It has been broken into two lines here.

 

kalita@pikespeak.uccs.edu:::Jugal:::Kalita:::5050 Copernicus Way,

     Colorado Springs CO 80917:::719 574 3656:::Saikia:::Nowgong

 

It is not the mailing list file. The updateAssamList.pl script reads the data file and updates the mailing list file located at

/home/kalita/mailing-lists/assam-list.dis. The script is simple and is given below.

 Program 8.10

#!/usr/bin/perl
#updateAssamList.txt

use strict;

my $separator = ":::";

my $webCreatedFile = "/home/kalita/public_html/cgi-bin/assamList.txt";
my $mailingListFile = "/home/kalita/mailing-lists/assam-list.dis";

open (IN, "$webCreatedFile") or warn "Cannot open file, $webCreatedFile: $!";;
my @allLines = ;
close IN;

my @allEmails = map {/^(.+?)$separator/} @allLines;
@allEmails = join "\n", (sort @allEmails);

#print "allEmails = @allEmails\n";

open OUT, ">$mailingListFile" or warn "Cannot open file $mailingListFile: $!";
print OUT @allEmails;
close OUT;

chmod 0644, $mailingListFile;

system ("/usr/bin/newaliases");

The program culls out only the e-mail addresses from the assamList.txt file and writes them out to the mailing list file. Thus, the mailing list file /home/kalita/mailing-lists/assam-list.dis looks like the following

 

9amit@mica.ac.in

KJDEKA@aol.com

NBa5252203@cs.com

anuz10@usa.net

assamlive@yahoo.com

bora03@aol.com

colorsofdawind@yahoo.com

crazynem@yahoo.com

dkalita123@rediff.com

dmedhi@aazoli.cstp.umkc.edu

gcbora@rocketmail.com

gmedhi@aol.com

howtodo@rediffmail.com

ices77@yahoo.com

inmanas@gw1.dot.net.in

kalita@pikespeak.uccs.edu

 

  After the new mailing list file is created, the /usr/bin/newaliases system command must be run so that the changes made to the global alias takes effect.

  The final detail in this long saga involves adding a command to the crontab command for the user kalita. On the Linux machine, we can run

 

%crontab -e

 

to edit the crontab file for an individual user. The line added to the crontab file is the following.

 

0 0 * * * perl /home/kalita/public_html/cgi-bin/updateAssamList.pl

 

It runs the updateAssamList.pl program once every day at the 0th hour and the 0th minute. Thus, the mailing list gets rejuvenated once a day with the new subscriptions and removals. To know how crontab or newalises work, the reader is advised to read the Unix manual pages on his or her system, or a book such as Unix for Programmers and Users [GA99] or Unix Systems Administration Handbook [NSSH01].