Simple python cgi contact form. Utf8-savvy, mustache-skinnable. Optional captcha (Winograd, Pycaptcha) and gpgme encryption
HTML Python Other
Fetching latest commit…
Cannot retrieve the latest commit at this time.

WhatMail by @TheRealDod

This is a simple cgi contact form that and can handle utf-8, which is a crucial feature for me since not all my friends write to me in English :)

It also has a text captcha. It's enabled by default but you can configure whatmail to disable it.

The GUI (big word for a form and a thankyou page) can be skinned with mustache templates. The default skin is twitter bootstrap based, but anything goes, and skin pull-requests are welcome.

If your form is served via SSL, you can also configure it to encrypt the mail it sends with gpgme (plain old ascii-armor. not mime). Be careful when you set this up: the illusion of security can easily make you lose your head. Peer review is welcome.

There's no email address validation and no assumption that such an address is entered at all (friends can leave a name, strangers may decide to leave a phone number instead). Also note that the identity of the sender can't be verified (even when encryption is enabled, nothing is signed), but the again - your phone doesn't come with prank-call protection either :). For what it's worth, the sender's ip number is included in the mail you receive.


  • Run git submodule update --init to fetch dependencies.
  • Put all files (including .htaccess) in a web-accessible folder.
  • Check your .htaccess settings by accessing from web: If you see python source, do not continue to the next step (creating This file will contain passwords and keys, and you have to make sure it can't be accessible from web. If .htaccess doesn't do the trick, show it to your sysadmin and ask to config your folder at the apache according to what's written there.
  • copy to and edit it. See comments inside the file.
  • That's it. You can now access the folder via web (e.g. /whatmail/) and get a contact form. Send yourself a message to congratulate yourself.

Skinning the GUI

  • Copy the skins/default/ folder to [say] skins/mine/.
  • Edit the mustache templates there.
  • You can also have static files (css, js, graphics) in the skin's folder. In templates, you can refer to that folder as {{skin}} (e.g. <img src="{{skin}}/graphics/logo.png">).
  • Change SKIN_FOLDER at from skins/default to skins/mine.


Enabling gpg

Note: If you decide to enable gpg, make sure the cgi page is served via SSL (otherwise, it's kinda daft). If there's an alternative http url that gets to the same cgi script, it is important to supply an SSL_REDIRECT_TO at (see below).

First thing, you need to make sure you have gpgme and pygpgme installed.
Simply try import gpgme from python and see if it works.
If it doesn't - installing them is beyond the scope of this README file, but it's doable :)

  • Create a script-specific gpg homedir (say, ./.gnupg). If it's inside a web-accessible folder, make sure homedir's name starts with a "." (and verify that you can't get to files there via web).
  • Export the recepient's pubkey (i.e. yours). E.g. do (on your desktop) gpg -a --export > me.asc and upload the temporary me.asc to the server.
  • Import the pubkey to the gpg homedir with gpg --homedir ./.gnupg --import < me.asc
  • Repeat with other pubkeys (if you want to encrypt to multiple recepients).
  • Edit GPG_* parameters at (GPG_HOMEDIR should be a full path starting with /).
  • It is recommended to write your script's SSL url as SSL_REDIRECT_TO. You are using SSL. Right? :)
  • Note: You should make sure your gpg homedir and the files in it are only readable by you (chmod 700 for the folder and 600 for the files). This can also work on a shared host, if the hosting provider has configured cgi scripts to run under your own uid (e.g. at Webfaction).

    If you're on a shared host where cgi scripts of all users run under the same uid (e.g. Apache's www-data), don't try to chmod the homedir so that www-data has rights at the gpg homedir. Better use an unecrypted form, so that your users know where they stand :)


Thanks to the authors of all the stuff glued here together:

Special thanks to Mack for peer review.