Contact form with reCaptcha and gmail SMTP service

There are many examples on the Internet about how to add web contact form. This is a simple copy and paste example which should work with your web2py app. 

This form is used on web2pyref site and utilised a reCaptcha for subsequent submissions only.

Similar example can be found on which this example is inspired by.

Note, if your gmail account is enabled for two step authentication you will need to create app password. Check your gmail settings page.

Form was tested with and Eurodns mail server settings.


Add below code to your model file. Don't forget to change your gmail and recaptcha settings.

##Contact form example

#Field('unread', 'boolean', readable=False, writable=False, default=True,label=T('Unread')),
#Field('todo', 'boolean', readable=False,writable=False, default=False, label=T('To Do')),
Field('your_name', label=T('Name')),
Field('your_email', requires=IS_EMAIL(), label=T('Email')),
Field('your_phone_number', label=T('Phone number')), # requires=IS_MATCH('[\d\-\+\(\)\.\ ]+'),
Field('client_ip','string',readable=False, writable=False, default=request.client),
Field('subject', label=T('Subject')),
Field('message', 'text', label=T('Message')),
Field('private_comment','text', readable=False, writable=False,label=T('Private Comment')),


Create private and public key on reCaptcha website.

def index():

Contact form
## configure email - GMAIL
mail = auth.settings.mailer
mail.settings.server = ''
mail.settings.sender ='
mail.settings.login = '' # OR mail.settings.login = '' #'
contact_form_cc = ''
contact_form_bcc = ''

form=SQLFORM(db.contact_form, fields = ['your_name','your_email','subject','message'],formstyle='table3cols')

##Check if form was submitted from the same IP address in the last 3 minutes - if yes recaptcha will be enabled
import datetime
now_is =
record = db(db.contact_form.client_ip==your_ip).select(orderby=~db.contact_form.created_on).first()
add_on_time = datetime.timedelta(days=0.000752315) ## How long will recaptcha be enabled for

##Enable for Recaptcha -
from import Recaptcha

##Recaptcha Keys - visit recaptcha website
public_key = 'YOUR-PUBLIC-KEY- HERE'
private_key = 'YOUR-PRIVATE-KEY-HERE'

##Check if comment is posted in the last 3 minutes, if yes, add recaptcha to the form - This part can be commented out.
if record:
if (record.created_on + add_on_time) > (now_is):
form.element('table').insert(-1,(T('Verify'),Recaptcha(request, public_key, private_key,options = "lang:'en,es', theme:'clean'",use_ssl=True)))
##End of recaptcha

## Process, save and send the email
if form.process().accepted:
Name : %s
Email : %s
Phone : %s
Subject : %s
Message : %s
) % (form.vars.your_name, form.vars.your_email, form.vars.your_phone_number, form.vars.subject, form.vars.message)
add_to_database = SQLFORM(db.contact_form)

if mail.send(
cc=contact_form_cc if contact_form_cc else '',
bcc=contact_form_bcc if contact_form_bcc else '',
subject=T('Question from %s on %s website') % (form.vars.your_name,website_name),
reply_to = form.vars.your_email,
message = message):
response.flash = T('Your message has been sent. Thank you')
form.errors.your_email = T('Unable to send the email')

return dict(form=form, now_is=now_is,add_on_time=add_on_time,record=record

View contact_form/index.html

Add to your view file.

{{extend 'layout.html'}}

<div class="col-sm-8">
<h1>Contact Form</h1>




Contact Form

File Download




Sources / Reference

" TinyWebsite"

Tag Cloud

accepted Acces Control access rights actions_disabled admin allowed_attributes allowed_schemes App apps args auth authentication B bar chart BEAUTIFY begin BODY BR carousel CAT CENTER chart check CLEANUP client request client_side CMS CODE COL COLGROUP comment compute contact form crud.create crud.delete crud.tables CRUD custom attributes custom form DAL data define_table deletable depriciated DIV doctype dot dspval EM embed64 enable_record_version end error_message example extension Field types Field FIELDSET file filename form.accepted form.accepts form.process form.validate FORM format Forms Grid H1 H2 H3 H4 H5 H6 hash_vars Hello helper helpers highchart hmac_key host hosting HTML image images inpval ip address ip IS_DATETIME IS_DATETIME_IN_RANGE IS_DECIMAL_IN_RANGE IS_EMPTY_OR IS_EQUAL_TO IS_EXPR IS_FLOAT_IN_RANGE IS_IMAGE IS_INT_IN_RANGE IS_IN_DB IS_IN_SET IS_IPV4 IS_LIST_OF IS_NOT_EMPTY IS_NOT_IN_DB IS_NULL_OR is_slug IS_STRONG IS_TIME IS_UPLOAD_FILENAME IS_UPPER IS_URL lable lambda lang lastdot linkto li_class li_first li_last login_methods maximum maxip maxlen MENU min minimum minip mobile mode module multiple permitted_tags pie chart placeholder plugin prepend_scheme pythonanywhere query rating reCaptcha redirect salt sanitize scheme services settings slug sortable special SQLFORM() SQLFORM.grid SQLFORM SSL submit table constructor TAG test text TinyWebsite ul_class update upper URL rewrite URL validator value vars Views widget XML xmlescape _class _common_fields

Powered by

Hosted on
(affiliated link)