How to build a spam-free contact form without captchas
June 7th, 2009 By nFriedly
Most anti-spam methods used by websites today are annoying at best. They use impossible-to-read captcha images, or they make users jump through some kind of hoop to get the email address instead of just clicking on it. This can mean lost sales and opportunities for you, because each hurdle turns away more users.
This article looks at how to use some simple HTML, CSS, & Javascript to protect your private information without making your guests jump through hoops.
Download a working copy of the contact form discussed here.
The Goal
I want users to be able to contact me simple and easy, no captchas, no math problems, just a regular contact form, clickable email address, and everything copy-paste-able.
The Problem
Spammers love captcha-free forms and clickable email addresses. (And lately, copy-paste-able phone numbers.) I do not want to receive a ton of spam!
The Solution
With a little bit of CSS and JavaScript wizardry, we can make a simple, easy-to-use contact page that will not get you hardly any spam!
A downloadable example is provided at the end of the article.
Part 1: The Contact Form
We are going to make a standard contact form with one extra feature: an input named “url” and a note beside it that says “Don’t type anything here!”
The HTML:
<form method="post" action="/submit.php"> <p>Your name: <br /><input name="name" /></p> <p>Your email: <br /><input name="email" /></p> <p class="antispam">Leave this empty: <br /><input name="url" /></p> <textarea name="message"></textarea> <input type="submit" value="Send" /> </form>
Then we use CSS to hide the input and the note.
The CSS:
.antispam { display:none;}
Then we make a rule in the server that says ‘if the user typed anything in the “url” box, then throw it out.’
The PHP:
<?php
// if the url field is empty
if(isset($_POST['url']) && $_POST['url'] == ''){
// then send the form to your email
mail( 'you@yoursite.com', 'Contact Form', print_r($_POST,true) );
}
// otherwise, let the spammer think that they got their message through
?>
<h1>Thanks</h1>
<p>We'll get back to you as soon as possible</p>
A regular person won’t even see the box normally, and will therefore leave it blank without even thinking about it. If the CSS fails to load, they get a note explaining what to do.
However, when a spam bot looks at this, it sees a good spot to stick whatever spammy url they’re trying to advertise.
Now the php script on the server can tell who is a spammer and who isn’t. The regular people get sent to your email, the spammers get ignored!
Part 2: Click-able Email Address
Spammers steal your email address by scanning through the source code of the site and grabbing anything that looks like an email address. So we’re going to make sure that there is no email address in the source code and instead generate it by JavaScript.
The Javascript:
var first = "yourname"; var last = "yoursite.com";
The HTML:
<p>My e-mail address:
<script type="text/javascript">
document.write('<a href="mailto:'+first + '@' + last+'">'+first + '@' + last+'<\/a>');
</script>
<noscript>
Please enable javascript or use my <a href="/contact.php">contact form</a>
</noscript>
</p>
A regular user will see a regular email address and things just work. A user who happens to have javascript disabled will see an explanation and an alternative solution. And a spammer won’t see a thing!
This method can easily be extended to phone numbers and other personal information.
Complete Examples
A complete working copy of everything mentioned in this article is available here: http://nfriedly.com/stuff/spam-free-contact.zip
For a live demo of all of this and more, see my contact page.
Update: I found that there is an anti-spam plugin for WordPress that uses similar methods to the ones I describe here: http://wordpress.org/extend/plugins/nospamnx/
Does your website need help?
I am an Experienced Web Developer with a sharp eye for security. I can make your site easier to use while at the same time cutting down on level of spam you receive through it. Contact me for more information and a free quote.

I used to get spam all over both my forums. I finally solved that problem the other day. I knew how to but was always too lazy to do anything about it. But problem solved as of now. No more waking up in the morning with incest this and barnyard that posted all over.
LOL, now I’m going to show up in google for “incest” while you’re getting juice for your site. Thanks Noah.
But seriously, what did you do to solve the spam problem? I doubt it was this..
lol Install analytics and let me know if you get shown for incest ever once. If so I would die laughing.
But I just did one of those questions that people have to answer. The one I am using now is
“What is the year minus one”
so it would be 2008.
I have not had a spambot since.
haha, I have google analytics installed + analog on the backend, I’ll let you know if I get any hits.
The year minus one is better than a captcha, but it’s still extra work for the users. That’s what I’m trying to avoid with this method.
I’ve only had a single comment spam from my contact form, and after looking through the logs, i realized that a real person came and typed in some marketing message and hit submit. You can’t really protect against that…
Now that Ive said that I can see you going and posting incest on my site lol.
And yes the typo was meant in the above post as for some reason i get traffic for that in google. I am going to optimize for typos
I may use your idea for a few of my contact forms. I get spam still from those now and again. But normally its not even properly done spam. Like somebody has a retarded spam bot that doesnt even post the link and spam right so I just get an email that is all broken.
LOL, yea, I used to see those all the time.
No, I’m not going to post dirty pics on your site, but I might post half a dozen web dev keywords all linked back to my site
Great post, I have added a similar feature on my site for the contact form and was looking at doing something similar for the comments.
Thanks man, glad to know somebody is finding it useful!
These are relatively weak defenses against spam. I use a timer to see if the form was submitted in less than a few seconds (good for defeating bots), a randomly named field with a random value, validation of all input fields (e.g. email address, phone #, etc.), and I also check to see if there are more than a few links in the submission.
I never thought of a timer to detect form submission time. On my comments I validate name, email address along with using a hidden field as the article above describes. Where the name and email will result in a focus on the improperly imputed field unless the hidden field does not valudate because of text being entered in the hidden field. If thy does happen it thanks them for their contribution and deletes their comment. I have considered checking to see how many links are posted in the comments but right now I am not having any problems and I want to keep it as light as possible
Joseph, that’s a fair argument, this article was going for simple and effective against generic spam bots. Anything targeted to even a specific piece of software (such as wordpress, which this blog runs on) needs more defense.
On this blog I use Akismet and it has had a 100% accuracy rate so far.
http://akismet.com/
On an different blog I worked on in the past, I used Akismet and Spam Karma 2. That uses all of the methods you mentioned and more to determine if a comment was from a spammer.
http://unknowngenius.com/blog/wordpress/spam-karma/
Thank you for a really simple explanation and codespec.
In its simplicity its brilliant and effective. I’m going to implement this approach with the few web forms I use.
Ivan Bayross
Thanks Ivan, post a link here when you do! BTW, I love the look of your site.
The anti-spam extra field is good.
The Javascript to “hide” your email is only going to be partially successful.
SpiderMonkey will cheerfully run the JS for the slightly smart spammers who run that to gather more/better emails.
So you’ve only stopped the stupidest spammers, not the slightly smart one.s
Oh, certainly, this is just a basic line of defense. The smart ones will still get you, but let’s face it: most spammers aren’t that smart or they’d be in a different line of work.
Not sure if you have taken a look at JQuery. At this point in time I’m sure you have. When i first saw i ran as fast as i code. The big chunks of code were over whelming. Besides all that, Jqery has a write in code snippet that can be used to plug chunks of code anywhere on the page based on criteria. This link ( http://docs.jquery.com/Manipulation ) has the code calls to manipulate code on a page. Very helpful if added on to your tut to provide reusable code and added security to perhaps dynamically create the whole form.
Oh yea, I love jQuery, if you take a look at the live demo linked in the article, http://nfriedly.com/contact , you’ll see that it uses jquery to go a little above and beyond what I mention here.
The method that you described does sound very interesting. However, recently I started using Mollom ( http://mollom.com ). There is no captcha. The form is processed by their bot and if it appears to be spam, it is rejected. I was getting at least one spam message in my inbox everyday even with a captcha. I started using Mollom about a month ago and so far only 1 spam message has gotten through.
I do want to look at the method that you described above though. I definitely see some benefits with it.
Hey, I tried this code and it works fine. But when I get the email. It comes with Array{} codes and even it shows the submit. Is there a way I can make it much better? Also it comes from my mail server which is an ugly address lol.
Hi Naz, you can do that by changing the line
to this:
$youremail = 'you@yoursite.com'; $body = "This is the form that was just submitted: Name: $_POST[name] E-Mail: $_POST[email] Message: $_POST[message]"; if( $_POST['email'] && !preg_match( "/[\r\n]/", $_POST['email']) ) { $headers = "From: $_POST[email]"; } else { $headers = "From: $youremail"; } mail($youremail, 'Contact Form', $body, $headers );The preg_match() is there to make sure spammers can’t abuse your server by injecting extra fields (such as CC and BCC) into the header. Take a look at http://www.thesitewizard.com/php/protect-script-from-email-injection.shtml for more info.