WebDeveloper.com �: Where Web Developers and Designers Learn How to Build Web Sites, Program in Java and JavaScript, and More!   
Web Developer Resource Directory WebDev Jobs
Animated GIFs
CSS Properties
HTML 4.01 Tags
Site Management
WD Forums

    Web Video
    Expression Web



    Forum, Blog, Wiki & CMS

 Site Management
    Domain Names
    Search Engines
    Website Reviews

 Web Development
  Business Issues

    Business Matters

    The Coffee Lounge
    Computer Issues

Forms to E-Mail Using Tcl

by J.M. Ivler

Code Review

What follows here is a copy of the code with internal editorial comments. Header information and standard comments that are embedded in the code have been stripped from here. In place of those comments are expanded details into how the code functions and what the code is doing. This will permit you to change the code with a full understanding of its functionality. The original version of the code can be found at ftp://ftp.net-quest.com/users/ivler/tcl/email.tcl.

Comments about the code are again printed in italics. In some cases, a sample piece of replacement code has been provided. This code appears as part of the comments section, but can be inserted into the code as described.


Sometimes referred to the bang-line, this is the line that stipulates the code is running as a Tcl shell program.

set localonly false
set sendvar true

These two variables were added in V2.0. localonly is used to disallow the use of Internet address specifications. This forces the email to be sent only to an address on the local system. Although the default is false, it is recommended that it be set true if you will be allowing any user to create forms that use this procedure. If this is kept false, it will allow the Internet server to be utilized as an anonymous remailer.

The sendvar variable is designed to allow flexibility for the forms designer. Earlier in the article it was discussed when making the choice on sending "value-data pairs" versus sending "data" alone. Setting the value as true will force pair sending.

puts "Content-type: text/HTML\n"
puts "Email Response Status"

These lines are what will be displayed to the user after submission. Error or not, these lines are needed. Note that the first line must be exactly as shown. That includes the blank return that follows.

foreach envvar [lsort [array names env] ] {
 if {[regexp {^WWW_} $envvar]} {
  set varname [join [lrange [split [lindex [split $envvar=] 0] _] 1 end ] _]
  if {$varname != ""} {
   set var($varname) $env(WWW_$varname)

In version 1.0, an exec was used to obtain all the environment variables. Then these were run through the regexp one at a time. The exec process added quite a bit of time to the processing. In 2.0, that was replaced by the foreach and if. Now this process will search all the variable names in the array env (which is where Tcl places all environment variables).

As an example, the variable information for the environment variable PATH is stored in the Tcl variable env(PATH). This process will get each array value (ex: PATH) and then check to see if it starts with WWW_ (the prefix assigned to form variables after they have been run through uncgi).

A form variable name translated by uncgi into WWW_name is found by this routine as env(WWW_name). Once found, the data is extracted into the internal variable var(name). This will continue until all environment variables have been processed.

set knt 0
set msub false
set mailto false

Set some initial flags... an internal counter... there is no passed-in mail subject... there is no passed-in mailto address.

if {[info exists env(WWW_sendvar)]} {
 set sendvar $env(WWW_sendvar)

Earlier we said that the user had control of the sendvar variable. This is where it gets reset by the user-issued command.

if {[info exists env(WWW_msub)]} {
 set msub true

If the form designer wants to send a user-defined subject... this will do it. NOTE: this is a possible security hole in the program. If the user sends a subject with a ";" in it, the UNIX system may assume that the command line is complete and then the email command will complete and the information that follows will be issued as a command on the system (a worst case scenario, msub = "Hello;rm -rf /" ). To avoid this, add the following line to secure the subject line (insert the line after the "set" above):

regsub -all \; env(WWW_msub) "" env(WWW_msub)

The above line will remove all semicolons from the subject line of the email message. The worst case example above would then look like msub = "Hellorm -rf /" -- a totally useless subject phrase.

if {[info exists env(WWW_mailto)]} {
 set mailto true
 set fname [pid].txt
 set f1 [open /tmp/$fname w]

In some cases the form designer may not want to send mail, but will want to test the operation of the form. The form designer, by omitting the mailto reference in the form, can force the information to be displayed back to the browser. The /tmp area is used for writing the temporary mail file, and the user's process id is used for the filename.

foreach vname [array names var] {
 incr knt

At this point you could insert an if statement to not include WWW_mailto, WWW_msub and WWW_sendvar in the output variables.

if {![regexp "mailto|msub|sendvar" $vname]}
{remember to close the brace at the end of this code block }
 if {$sendvar} {
  set ostring($knt) "$vname = $var($vname)"
 } else {
  set ostring($knt) $var($vname)
 if {$mailto} {
  puts $f1 "$ostring($knt)"
 } else {
  puts "$ostring($knt) 
" } }

The above code block will build the message -- either to the screen or to a temporary file that will be sent via mail. Insertion of the if statement to eliminate variables should be closed by a brace at the end of this code block.

  if {$mailto} {
   puts $f1 "\n\nThis was generated from a form at: $env(PATH_TRANSLATED)"
   close $f1

If we're mailing it, write out the form information at the foot of the message and close the temporary file. You could also use this opportunity to add a disclaimer if you are using this code with Internet mail (anonymous mail) set on. A sample disclaimer might be: "\n\nThis code was generated via a World-Wide Web based form. The site mysite.com takes no responsibility for the opinions expressed in this email. The user nobody at this site is the default name for WWW users. The form used to send this email was: $env(PATH_TRANSLATED)." While that may not save you from the Secret Service visit, it will make it clear that the site had no control over the contents of the message.

  if {$localonly} {
   if {[regexp "@|!|%" $env(WWW_mailto)]} {
    puts "<center><h1>An invalid form of email notation \
           from this server has been used</h1>"
    puts "Please use the back key to exit.</center>"

This section enforces the rule of internal email only. @ ! and % are used when sending mail off the internal system to a foreign system. This rule eliminates that capability. If running on VAX/VMS add a check for :: as well. Again, it can't be stressed strongly enough that this filtering is preferred.

    if {$msub} {
     exec mailx -s "$env(WWW_msub)" $env(WWW_mailto) < /tmp/$fname
    } else {
     exec mailx -s "from the CGI automailer @ $env(SERVER_NAME)" \
        $env(WWW_mailto) </tmp/$fname

Send the email. Note that a subject is supplied by default if none is provided. Also, this processor is designed to use the mailx email interface from Unix; your mailer may be different, and may require a different syntax.

  exec rm /tmp/$fname
  puts "<center><h1>Mail sent to $env(WWW_mailto)</h1>"
  puts "<h2>Thank you for your participation $var(name)."\
"</h2>Your answers have been processed,please use the back"\
"key to exit the survey.</center> <hr><P> <address>©"\
"Copyright 1995, Infobahn Xpress, Los Alamitos, CA. All"\
"Rights Reserved.</address>" }

Last, but never least, clean up and tell the user what you did.

Sample Session

In this section a form will be developed, and then user input will be described. The final outcome will be sample mail messages that would be received.

This first form is designed to ask what someone is interested in, and request an e-mail address. The user can select an area of interest from the selection list, along with a level of interest indicator. The indicator is a radio button between 1 and 10.

   <title>Sample 1</title>
   <h1>Sample 1</h1>
Thanks for taking the time to respond to this simple ques-
tionnaire. This information will be used to provide you
detailed information on the subject of your selection.
   Please respond to the questions in the next section. Once
completed, enter your email and then press the submit
button. Thanks for helping out.
   <input type=hidden name=mailto value=ivler>
   <input type=hidden name=msub value="Area of interest">
   <h2>Sports Information Selection</h2>
    <select name=intr>
   <option> Golf
   <option> Tennis
   <option> Boating
   <option> Chess
   <option> TV
   <option> Football
   <option> Soccer
   <option> Sailing
   <h2>Interest Level</h2>
   <p> 1 is low, 10 is high.<p>
   1 <input name=m1 Type=radio value="1">
   2 <input name=m1 Type=radio value="2">
   3 <input name=m1 Type=radio value="3">
   4 <input name=m1 Type=radio value="4">
   5 <input name=m1 Type=radio value="5">
   6 <input name=m1 Type=radio value="6">
   7 <input name=m1 Type=radio value="7">
   8 <input name=m1 Type=radio value="8">
   9 <input name=m1 Type=radio value="9">
   10 <input name=m1 Type=radio value="10">
   <input name="name"> Email<p>
   To submit the answers, press this button: <INPUT
TYPE="submit" VALUE="Submit Feedback">.<br>
   Use the back key to exit, and the reload option to clear
and restart.
Did you remember to submit?
   <HR> <P>
   <address>J. M. Ivler - email: ivler@i-xpress.com<br>
   © Copyright 1995, Infobahn Xpress, Los Alamitos, CA.
All Rights Reserved.</address>

The second form is the same as the first with the following changes:

sendvar has been turned off:
<input type=hidden name=msub value="Area of interest">
<input type=hidden name=sendvar value="false">

The values for the m1 variable have been changed from numerics to phrases. If 5 was selected in the second example it would generate the phrase: "I am not really interested in this topic." and a 10 would generate "I have a great interest in this topic".

In this sample session the user will pick Football as the pulldown selection, and 8 as the interest level. The user's name is ivler@i-xpress.com. The following are the two mail messages that would be generated by the user's selection.

Mail Message 1

To: ivler
From: nobody@site.com
Subject: Area of interest

intr = football mailto = ivler msub = Area of interest m1 = 8 name = ivler@i-xpress.com

This was generated from a form at: /WWW/test/form1

If the change to remove mailto and msub were active, the message would be easy to process into a database of interest/level/individual. That could then be used as a feeder to a program to determine when to send e-mail to an individual on the topic area.

Mail Message 2

To: ivler
From: nobody@site.com
Subject: Area of interest

football ivler Area of interest I have a fair interest in this topic ivler@i-xpress.com

This was generated from a form at: /WWW/test/form2.

HTML5 Development Center

Recent Articles