Thalassa CMS logo

Thalassa CMS

Site contact form



Site contact form is a Thalassa CGI feature that lets people to contact the site's team by sending email messages to some predefined email addresses. Besides the obvious input fields for a sender address, a subject and a message body, the user should be provided with the ability to choose a category from a predefined list. More or less good examples of categories are “technical support”, “legal questions”, “vacancies”, “report a typo” and the like.

It is also possible to preselect a category using URIs. This may be useful in case a link to the contact form is to be placed somewhere at the site, like “contact our tech support department for details”, so the particular category is too obvious to leave the choice to the user.

Each category has its title, intended to be visible for the user; a separate email address can be specified for each category, but a default address can be set as well, so one can specify the default address and specific addresses for some (but not necessarily all) categories.

To have a contact form on the site, one first needs to configure categories, composing rules and email sending command; this is done with a [feedback] ini section. Besides that, a page (or multiple pages) must be configured to display the feedback webform and to accept POST requests with the feedback action.

The feedback action and the web form

The action that performs sending feedback messages is named feedback. Unlike all actions we discussed before, this action accepts an optional argument — the name of the preselected feedback category, if there is one. It is intended to be used on a multipath page, e.g.:

  [page contact]
  action = feedback %1%

This type of setup intends that at URI like /thalcg.cgi/contact a form will appear that allows the user to select the feedback category manually, while URIs like /thalcg.cgi/contact/legal will display generally the same form, but with the “category” input disabled and the actual category (legal in this example) already selected.

This is not necessary though. If you're really sure you don't need to preselect feedback categories by specifying them in the URI, you can use a simplified setup, like this:

  [page /contact]
  action = feedback

In this case, the /thalcg.cgi/contact “page” will have no “subdirectories”, as it is usual for non-multipath pages.

Finally, you can make your URI totally unrelated to the preselected feedback category, like this:

  [page /attorneys/contact_the_lawyer.html]
  action = feedback legal

The feedback action expects the following field values:

For a multipath feedback page, you might want to define a path predicate, like this:

  path_predicate =
  +   %[if:%2%:no:
  +      %[ifbelongs:%1%:%[feedback:categories]:yes:no]
  +      :no
  +   ] :
  +   yes

This predicate allows the 1-token URI (e.g., /thalcg.cgi/contact), disallows URIs with more than two tokens (e.g., /thalcg.cgi/contact/alpha/beta) and only allows 2-token URIs in case the second token is an ID of an existing (configured) feedback category. The feedback macro is discussed below.

The [feedback] section

The [feedback] configuration section contains parameters that set up categories (categories, cattitle, selected, email) and email composition and sending (envelope_from, send_command, send_data). This section is not responsible for displaying the web form and handling its POST request;

Configuring categories

To configure feedback categories, one needs first to enumerate the categories, which is done by setting the categories parameter. The parameter's value is a whitespace-separated list of category identifiers; the identifiers are used as specifiers to other parameters, so it is strongly recommended to use only low-case latin letters, digits and possibly the underscore in them. For the abovementioned list of category examples, the respective categories parameter may be as follows:

  categories = tech_support legal vacancies typo_report

Titles for categories are set by the cattitle parameter using category IDs as specifiers, like this:

  cattitle:tech_support = Technical support
  cattitle:legal = Legal questions
  cattitle:vacancies = Jobs and vacancies
  cattitle:typo_report = Report a typo on the site

Email addresses tp which the feedback should be sent are set by the email parameter. Category IDs may be used as specifiers to set email addresses on a per-category basis, like this:

  email:tech_support =
  email:legal =
  email:vacancies =
  email:typo_report =

It is also possible to have specific addresses for some categories and a last-resort address for all the ohers:

  email:tech_support =
  email:typo_report =
  email =

Certainly, you can direct all your feedback to one common address, not using the per-category configuration, like this:

  email =

The last category-related parameter is selected, it allows to choose what category is to be selected by default. To do so, the value for this parameter specific for the desired category must be set to “yes”, like this:

  selected:typo_report = yes

The “envelope from” address

It might be critical for successful mail delivery to set the envelope from email address correctly. This thing often appears confusing for people not familiar with email system, so some explanations may be useful.

The header of a email message is nothing but a part of the message, and it plays mostlty a decorative role, in the sense it doesn't affect the message delivery process. This is true for the From: and To: headers as well. One can even put a complete crap there. What really matters for delivery — that is, for servers (MTAs) that implement the SMTP protocol and actually send and receive electronic mail — are the addresses specified within the SMTP session, outside of the message itself. Each message has exactly one associated sender address and one or more recipient addresses; these addresses don't need to be included in the message itself, because servers communicate them separately. Informally these addresses are known as envelope addresses.

The envelope addresses of the recipients aren't a thing to worry about in the context of the site contact form; the addresses specified for the email parameter (see above) will be used, and as these addresses presumably are controlled by the same team as the site itself, perhaps everything will be okay.

What's important to note is that the sender's address is entered into the form by the user, so its correctness can not be guaranteed nor even verified.

Furthermore, SMTP servers nowadays tend to implement various anti-spam techniques, and some of them, like SPF, can't do anything useful against a professional spammer, but build serious barriers on the way of legitimate emails, such as forwarded ones, and ruin correctly maintained mailing lists (to which users subscribe on their own using email confirmation mechanism). Good or bad, all these techniques can lead to rejection (as “spam”) of a message that comes from a source “unexpected” for the domain name of the sender address. E.g., if the user specifies an address at Gmail, or Yahoo, or whatever the like, mails “from” such address are “expected” to come from Gmail or Yahoo, not from your poor web server.

The good news is that it is the “envelope from” address which is checked in most cases, not the address specified in the From: header of the message. So, the more or less reliable setup will be to place into the From: header whatever the user entered in the form, but set the “envelope from” to an address in a domain that you own or at least control, such as the same domain as for your site. Domain name of the mail system you use to send your messages via may work here, too, in case you are too afraid to run a first-class SMTP server on your own. Well... it may appear a far simpler thing than you expect, but it's still up to you.

The address you use may either be an unattended address, forwarded right to /dev/null, or an address someone reads emails on — such as the webmaster's address. It is, again, up to you. In most cases, only the domain name matters for all these anti-spam checkers.

The “envelope from” address is set by the envelope_from parameter of the [feedback] section, like this:

  envelope_from =

The %[feedback: ] macro

The categories-related part of the feedback configuration, as well as the configured “envelope from” address, are available via the feedback macro. The macro has four functions. Two of them don't need additional arguments: %[feedback:categories] returns the space-separated list of categories, as set by the categories parameter, and %[feedback:envfrom] returns the configured “envelope from” address.

The cattitle function accepts one additional argument — the category ID — and returns the title for the given category. E.g., for the example given above, %[feedback:cattitle:legal] will return the string “Legal questions” as configured by the cattitle:legal parameter.

The ifcatsel function is a conditional checker. It accepts three additional arguments: the category ID, the then value and the else value. In case the given category is set to be preselected by the selected parameter, the then argument is returned, otherwise the function returns its else argument.

The macro is used both in the resting parameters of the [feedback] section and in the page template that composes the actual feedback webform.

Email composition and sending configuration

The rest of the [feedback] section are two parameters, send_command and send_data. Within their values, the feedback macro should be actively used. Besides that, the context-specific %receiver% macro is available. And, the last but not least, you can use the %[req:param: ] macro function to access data from the web form, typed by the user; e.g., %[req:param:mail] should be the user's email, etc.

The send_command parameter is a command line (name and arguments) for the external program to launch to send the message; arguments are split down to words, using the apostrophe “'” and the doublequote “"” as grouping symbols (both an apostrophe within doublequotes and a doublequote within apostrophes are considered as plain chars). As usual, the message itself will be supplied to the command's standard input. For example:

  send_command = /usr/sbin/sendmail -bm -i
  +                -f %[feedback:envfrom] '%[receiver]'

The send_data parameter is a template for the whole message, including the headers and the body. Be sure to leave an empty line between the header and the body, and not to insert empty lines before or in the middle of the header. Thalassa CGI doesn't check anything here on its own, but the message will likely be rejected by the MTA if composed incorrectly. Here's an example of the template:

  send_data = From: %[req:param:mail]
  +To: %[receiver]
  +Subject: %[req:param:subject]
  +MIME-Version: 1.0
  +Content-Type: text/plain; charset=us-ascii
  +Content-Transfer-Encoding: 8Bit
  +X-Sender-Software: Thalassa CGI script
  +X-Sender-Form: %[req:host]%[req:script]%[req:path]
  += "%[req:param:name]", using the site contact form, wrote:

© Andrey V. Stolyarov, 2023, 2024