Building a Contact Form with Markdown and reCAPTCHA

Webscript includes built-in support for sending email, which you can see in our basic email example. That example implements a basic contact form with just one field (the body of the message). In this post, we'll build that example up into a more fully-featured contact form that captures a reply-to email address, a custom subject, and a Markdown-formatted message.

The contact form we'll build here is available on our examples page.

The HTML

The easiest way to understand the contact form is to look at the HTML form. This is a simplified version (without any labels):

<form action="https://examples.webscript.io/contact" method="post">
  <input type="text" name="replyto" />
  <input type="text" name="subject" />
  <textarea name="body" rows="10"></textarea>
  <script src="https://www.google.com/recaptcha/api/challenge?k=<RECAPTCHA PUBLIC KEY>"></script>
  <button type="submit">Send</button>
</form>

This form posts replyto, subject, and body fields to the server. By virtue of reCAPTCHA's "challenge API", we're also including a CAPTCHA. This will add two more fields to our form post: recaptcha_challenge_field and recaptcha_response_field. These fields are what we need to use in our script to validate that the CAPTCHA was completed successfully.

Validating the CAPTCHA

When our script receives an HTTP POST, it first needs to validate that the reCAPTCHA was completed correctly. To do that, we need to use reCAPTCHA's server-side API. Using this API is straightforward, and we did it manually in the reCAPTCHA example on our examples page. Since then, we wrote a small module for this, called recaptcha, which is available in our library.

To validate the CAPTCHA, our script just needs to call that library, passing in our reCAPTCHA private key and the current request object:

local RECAPTCHAKEY = '<RECAPTCHA PRIVATE KEY>'
local recaptcha = require 'recaptcha'
if recaptcha.validate(RECAPTCHAKEY, request) then
        -- process the form here
else
        return 'Failed CAPTCHA.'
end

Processing Markdown

To support Markdown formatting in the body, we'll use markdown.lua, also available in our library. To convert the Markdown content to HTML, we need just a couple of lines of code:

local markdown = require 'markdown'
html = markdown(request.form.body)

Sending Email

Finally, we can put everything into an email. The full script is as follows, with a hard-coded email address of hello@webscript.io:

local USERNAME = '<SMTP USERNAME>'
local PASSWORD = '<SMTP PASSWORD>'
local SERVER = '<SMTP SERVER>'
local RECAPTCHAKEY = '<RECAPTCHA PRIVATE KEY>'
local recaptcha = require 'recaptcha'
local markdown = require 'markdown'
if recaptcha.validate(RECAPTCHAKEY, request) then
        html = markdown(request.form.body)
        email.send {
                server = SERVER, username = USERNAME, password = PASSWORD,
                from = '[email protected]', to = '[email protected]',
                subject = '[contact form] '..request.form.subject,
                text = request.form.body,
                replyto = request.form.replyto,
                html = markdown(request.form.body)
        }
        return 'Mail sent.'
else
        return 'Failed CAPTCHA.'
end

Note that we're taking advantage of the fact that email.send can send multipart emails with both text and HTML components. In this case, we're sending the raw Markdown as text as well as the generated HTML.

This script is also available on our example page, where it also returns the generated HTML so you can see how the email looks.

Simple But Powerful

I like this example, because even though it's involves quite a few pieces, the final script is quite short and easy to understand. This is a good example of how Webscript can be quite powerful while maintaining its simplicity.