-->
Bookmark and Share

ASP FormMail

Coding Details

View the source code for this ASP script.

The script is fairly simple with four basic steps.

  1. Check the request to ensure a valid form submission.
  2. Process (most of) the control form fields passed.
  3. If no errors occured in the previous steps, create and send the email.
  4. Produce an output page displaying either errors or the data that was emailed.

Note that the script does not necessarily stop processing when an error occurs. Instead, error messages are stored in a global array and processing continues where possible. Then all the error messages can be displayed on the final step.

The details for each step are discussed below.

Checking for a Valid Form Submission

The script first checks for form data in the request, no data means that there is nothing to process.

   'Check for form data.
   if Request.ServerVariables("Content_Length") = 0 then
     call AddErrorMsg("No form data submitted.")
   end if

Then it does the bot check (if enabled).

   'If bot checking is enabled, check the elapsed time.
   if botCheckFlag then
     startTime = Session(botCheckID)
       if not IsDate(startTime) then
         call AddErrorMsg("Invalid submission.")
       elseif DateDiff("s", startTime, Now()) < botCheckMinTime then
         call AddErrorMsg("Invalid submission.")
       end if
   end if

The next check is to determine if the host in the referering URL is permitted.

  'Check if the referering host is allowed.
  if UBound(allowedHosts) >= 0 then
    host = GetHost(Request.ServerVariables("HTTP_REFERER"))
      if host = "" then
        call AddErrorMsg("No referer.")
      elseif not InList(host, allowedHosts) then
        call AddErrorMsg("Unauthorized host: '" & host & "'.")
      end if
  end if

The HTTP_REFERER environment variable contains the URL of the form that submitted the request. This is passed to the GetHost() function which parses out the host name, i.e. the characters between the the beginning "http://" (or "https://") and the next "/" character.

The script then looks in the allowedHosts list for a match. Any requests from an unauthorized host name generates an error message.

Processing the Control Fields

The only required control field is _recipients. The script ensures that at least one recipient is specified. It then checks that each is a valid email address and is permitted via the allowedRecipients list.

  'Check the email recipients.
  if Request.Form("_recipients") = "" then
    call AddErrorMsg("No email recipient(s) specified.")
  else
    recipients = Split(Request.Form("_recipients"), ",")
    for each addr in recipients
      addr = Trim(addr)
      if not IsValidEmailAddress(addr) then
        call AddErrorMsg("Invalid email address in recipient list: " _
		  & addr & ".")
      elseif UBound(allowedRecipients) >= 0 then
        if not inList(addr, allowedRecipients) then
          call AddErrorMsg( _
            "Unauthorized email address in recipient list: " & addr & ".")
        end if
      end if
    next
    recipients = Join(recipients, ",")
  end if

Next is the _replyToField or _ccToField control field. These work a little differently. The value is taken to be the name of another field present in the form data. The script takes the value of this other field to be used as the Reply-To or CC address.

  'Check for a cc-to or reply-to address.
  ccToAddr = ""
  replyToAddr = ""
  name = Trim(Request.Form("_ccToField"))
  if name <> "" then
    if not allowCcToFlag then
      call AddErrorMsg( _
        "Configuration error: use of _ccToField not permitted.")
    else
      ccToAddr = Request.Form(name)
      if ccToAddr <> "" then
        if not IsValidEmailAddress(ccToAddr) then
          call AddErrorMsg("Invalid email address in " & name _
            & " field: " & ccToAddr & ".")
        end if
      end if
    end if
  else
    name = Trim(Request.Form("_replyToField"))
    if name <> "" then
      replyToAddr = Request.Form(name)
      if replyToAddr <> "" then
        if not IsValidEmailAddress(replyToAddr) then
          call AddErrorMsg("Invalid email address in " & name _
            & " field: " & replyToAddr & ".")
        end if
      end if
    end if
  end if

Note that if _ccToField is used, _replyToField will be ignored.

Again, since the resulting value is suppose to be an email addresses, it is checked to ensure it is in the correct format.

The script then gets the email subject line from the _subject control field.

  'Get the subject text.
  subject = Request.Form("_subject")

The _requiredFields control field is processed next. Like _recipients, it may have multiple values separated by commas, so these checked individually. And like _replyToField or _ccToField, those values are taken to be the names of other form fields.

  'If required fields are specified, check them.
  if Request.Form("_requiredFields") <> "" then
    required = Split(Request.Form("_requiredFields"), ",")
    for each name in required
      name = Trim(name)
      if Left(name, 1) <> "_" and Request.Form(name) = "" then
        call AddErrorMsg("Missing value for " & name)
      end if
    next
  end if

If any of the specified fields has a null string value, an error message is generated. Note that any field whose name starts with an underscore is ignored, as that is reserved for the control fields.

The _fieldOrder control field is handled next, resulting in an array of field names which will be used to display the form fields in that specified order.

  'If a field order was given, use it. Otherwise use the order the fields
   'were received in.
  str = ""
  if Request.Form("_fieldOrder") <> "" then
    fieldOrder = Split(Request.Form("_fieldOrder"), ",")
    for each name in fieldOrder
      if str <> "" then
        str = str & ","
      end if
      str = str & Trim(name)
    next
    fieldOrder = Split(str, ",")
  else
    fieldOrder = FormFieldList()
  end if

Generating the Email

If no errors have been detected so far, the next step is building the email. The script contructs the body of the email note, using HTML formatting.

  'If there were no errors, build the email note and send it.
  if UBound(errorMsgs) < 0 then

    'Build table of form fields and values.
    body = "<table border=""0"" cellpadding=""2"" cellspacing=""0"">" _
      & vbCrLf
    for each name in fieldOrder
      body = body _
           & "<tr valign=""top"">" _
           & "<td><strong>" & name & ":</strong></td>" _
           & "<td>" & Request.Form(name) & "</td>" _
           & "</tr>" & vbCrLf
    next
    body = body & "</table>" & vbCrLf

Note the use of the fieldOrder array. It is simply an array of field names generated in the previous step using either the _fieldOrder control field or (when that control field is not used) by a function called FormFieldList().

This function corrects a small problem with VBScript. While it's possible to simply loop through all the form fields using a statement like...

  for each name in Request.Form
    ...
  next

VBScript doesn't guarantee that the field names will be given in the same order as they appear in the form request sent by the browser.

To ensure that the fields are listed in the order received, the FormFieldList() function is used to generate the names in an array in the proper order.

The _envars control field is checked here to append a display of any requested environmental variables to the email.

  'Add a table for any requested environment variables.
  if Request.Form("_envars") <> "" then
    body = body _
         & "<p> </p>" & vbCrLf _
         & "<table border=""0"" cellpadding=""2"" cellspacing=""0"">" _
         & vbCrLf
    envars = Split(Request.Form("_envars"), ",")
    for each name in envars
      name = Trim(name)

      'Only show environment variables in the permitted list.
      showEnvar = true
      if UBound(allowedEnvars) >= 0 then
        showEnvar = InList(name, allowedEnvars)
      end if
      if showEnvar then
        body = body _
          & "<tr valign=""top"">" _
          & "<td><strong>" & name & ":</strong></td>" _
          & "<td>" & Request.ServerVariables(name) & "</td>" _
          & "</tr>" & vbCrLf
      end if
    next
    body = body & "</table>" & vbCrLf
 end if

Now the email can be sent. If an error occurs when attempting to send it, the error message is saved for display.

    'Send it.
    str = SendMail()
    if str <> "" then
      AddErrorMsg(str)
    else
      'Clear the bot check timestamp.
      Session.Contents.Remove(botCheckID)

      'Redirect if a URL was given.
      if Request.Form("_redirectUrl") <> "" then
        Response.Redirect(Request.Form("_redirectUrl"))
      end if
    end if

Displaying the Results

The final step is to build a page for display. If any errors were encountered, these are listed. Otherwise, the script checks for the _redirectUrl control field

If a redirect URL was specified, it redirects to that page. If not, the script builds a simple display of the fields included in the email. If a URL was specified in the _continueUrl control field, it adds a link to it at the bottom of the page.