Back when I converted my site from WordPress to Hugo, one of the issues I had to take care of was setting up a processor for my contact form. I decided to go with Formspree as their free tier easily handled the amount of form submissions I got per month. While most folks will use Formspree with a "regular" old form post, you can also use a fancy-pants Ajax submission as well. The Formspree folks document this, but their example is rather short, and when I was asked by someone on the Surge Slack about a full example, I decided to whip something up.
To be clear, and more on this at the end, this was a quick bit of code just to give that user a "real" example they could take and modify. There's many different ways of doing this and what I've built here was done in about five minutes.
My example consists of two files - an HTML file and a JavaScript file. There's no styling involved but I assume folks can handle that on their own. First, the HTML.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Test FormSpree.io</title>
</head>
<body>
<div id="formBlock">
<form id="someForm">
<label for="name">Name:</label> <input type="text" id="name"><br/>
<label for="email">Email:</label> <input type="email" id="email"><br/>
<label for="comments">Comments:</label> <br/>
<textarea id="comments"></textarea><br/>
<input type="submit">
</form>
</div>
<div id="thankyouBlock" style="display:none">
<p>
Thank you for filling out the form. I care a lot about it.
</p>
</div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="test.js"></script>
</body>
The only thing particularly interesting here is a hidden div used for the "thank you" message. Formspree supports sending you to a "thank you" page when you send a regular form POST to it, but when working with the Ajax version we need to handle this ourselves. I could have also just changed the HTML on the fly and injected a message, but this seemed simplest. My form has 3 fields arbitrarily chosen for the demo.
Now for the JavaScript:
$(document).ready(function() {
$('#someForm').on('submit', function(e) {
e.preventDefault();
//get the name field value
var name = $('#name').val();
//get the name field value
var email = $('#email').val();
//get the comments
var comments = $('#comments').val();
//pretend we don't need validation
//send to formspree
$.ajax({
url:'https://formspree.io/[email protected]',
method:'POST',
data:{
name:name,
_replyto:email,
email:email,
comments:comments,
_subject:'My Form Submission',
},
dataType:"json",
success:function() {
console.log('success');
$('#formBlock').hide();
$('#thankyouBlock').show();
}
});
});
});
So I assume this is pretty vanilla jQuery, and of course, you don't have to use jQuery. I get my data, validate it (well, I wrote a comment saying I would), and then simply POST to Formspree. I do manipulate the data a bit. First, I pass the email value twice. Why? By passing it as _replyto
, I can actually reply to the email Formspree sends me with the form contents. (As an FYI, I completely missed the fact that Formspree will treat a field named "email" as the replyto as well. So my code there was unnecessary. This is definitely documented, but I missed it.) I still want to see the address so I include it again. _subject
doesn't come from the form at all, but is used by Formspree to set the subject line of the email sent.
While that's it - let's quickly look at what happens when you use this code. First off, don't forget the Formspree requires you to validate a form before it will email you. If you actually look at the result of the POST in your form tools, you'll see this the first time you run it.

The good news is that Formspree still sends the email, but it only does so once and you must confirm it. When you deploy this code to your production site, be sure to quickly confirm it. Their email does a good job of making it real clear you darn well better do so:

When you do confirm, this is the response JSON you get:

The Formspree docs don't really describe in what situations you would get an error. You could, I suppose, notice when success
isn't there and handle it by telling the user that your forms are currently broken and they should simply email you instead. And of course, it just plain works:

So since this discussion came up on the Surge Slack, I went ahead and Surged it. Because why not? You can run this demo here: http://hospitable-cushion.surge.sh/test.html. I can't promise it will be up forever, but I'll run it for now.
I hope this helps, and definitely check out Formspree - it is a great service. If you want, you can stop reading now, in fact, I encourage it. What follows is 100% off topic for the rest of the post. Seriously - I don't mind if you stop.

In a recent blog post, I got called out about the quality of code I used in an example. Many of the points made were absolutely true, but frankly, it was incredibly insulting and literally had me close to simply not blogging again. (To be clear, I'd still write, just not on my personal blog.) Because I feel it needs to be said, here are some things to keep in mind when reading this blog.
- The code I write here is part of how I learn. That means, many times, you're seeing code from the beginning of my process of learning a particular language or technique. I think that has merit. I wish more beginners would share this part of the process. It helps flesh out issues with documentation and process that you don't get when only the experts are speaking.
- When I'm explaining something, I absolutely do not go for the most tight, or short, code and will often break things that could be written on one line into many. I want my code to be readable, and approachable, and that is not always the same as production code.
- Do I worry about misleading people? No. Frankly, there is a group of developers who cut and paste. You can call them StackOverflow developers if you want. You know them because as soon as they need to do something beyond the code they copied, they have no idea how to do it. I'm not going to belittle them because I've done it myself. Now - I think a good developer needs to recognize when they're doing that and take responsibility to actually learn what they are doing, but I flat out refuse to censor myself because someone may use my code incorrectly. Heck, I've been writing this blog for 15 years. I'm sure I've got some quite horrid little nasty gems in my past. Screw it. I'm proud of my mistakes.
So with that being said - as I said from the very beginning on this blog - I hope folks can learn from this blog (and laugh a bit) and if I've done that, then I'm not going to worry about writing the absolute best production quality minified work around.
Oh - but I will use semicolons. Because not using semicolons is like murdering kittens.
Archived Comments
That being said, they probably should avoid my blog like the plague.
Heh!
Hi, so I checked this, but I still don't get it. (yes I'm still crawling in coding). In the other form you add <input type="hidden" name="_next" value=""> so to forward the page to the "Thanks" page after sending. But here you didn't. So when you said: "You would modify the code to set the values to "" and not forward the page away."
I add the input hidden, with both value "" and value "thankyouBlock" but it still forwarded it to a new page. Can you help me out? Sorry if I'm pushing your good will
Ok so a few things. You do not want a form field called _next. That tells FormSpree where to go.
First - are you asking how to set values to ""? If so - I'd get a bit familiar with jQuery as this is basic usage type stuff. The general way is this:
$("#foo").val("");
where foo is the ID of a form field. You would do that one per field.
Next - I was a bit mistaken on the other blog post where I said my code 'forwarded' you on. I forgot my demo here simply hides content and shows content to thank the user.
Ok so far?
Ok, so far so good.
Cool. That's pretty much it I think. Try it and see.
Hi Raymond, cool post! It's gratifying to see people digging into our advanced features and helping others along! (Also, your jQuery looks good to me!)
One suggestion: You shouldn't need to include _replyto and email-- either one will set the reply-to email headers so you can reply with a click. (We should probably be more clear about that in our docs). Thanks again!
You are absolutely right, and frankly, the docs are pretty darn clear. I've updated the blog post with a note about my mistake. Thank you!
Do you know how to get @Formspree to set the "Reply To Name" header? Setting the "reply to email" header is great, but it'd be nice to have a name also. Do you know how?
Currently, for me, the:
name="name"
input value gets sent in the body of the formspree email, but I'd like to have this data sent in the header as well.
I think it is a good idea - but you would need to raise it to Formspree directly. I could see this being something they charge for though.
great post, exactly what i was looking for, thanks
Fantastic post. I really understand what you're saying and have struggled with the best way to communicate an idea. Make no apologies, you're helping people and the critics aren't.
Thank you - I don't even remember the post before this that garnered the attack. I had another one last week, but in general, I'm average a "slam" about once a year, so that's probably pretty good. :)
Just want to say thanks for the effort taken to capture the learning process you went through. The journey teaches more than the destination.
I don't know what trolls think they are achieving. Technology blogging is not a "only superheroes need apply" activity. Constructive criticism is helpful even if it stings a bit. The sting being proportional to the skill of the critic.
You are most welcome. :)
Fantastic post !
This code was working fine on localhost but after hosting my website i was not receiving emails from formspree.
I was facing this error because my emailaddress and new domain / page link was not verified with formspree.
So... you have it working ok?
Great stuff, Raymond. I needed a way to keep users on my site after a form submission, and you came through!
Glad it was helpful!
It's working on my localhost but not working from github. is there any way to fix it ?
How is it not working?
I don't know what happened,it is working now. Thanks for sharing the code with us. Really great stuff.
Cool.
Raymond, beautiful site, and exactly the article I was looking for. Do you think the fact that your email address ends up hard-coded in client-side script is a drawback of this solution? I would rather not give away the recipient of the form, but otherwise I think it's a great solution.
Um, it could be, but if it was a concern, I'd just use a non-primary email address. So for example, if I was some celebrity, I'd use a 'public facing' email address and not one my family and friends know.
You can do form processing with serverless easily enough and if you check my OpenWhisk and Webtask tag pages here, you will find an example of that.
I need to stop saying "easily enough" - it MAY be easy - check it out and let me know. :)
Yeah, agreed, a "public facing" account that just forwards to the actual recipient sounds like a decent way to go. I learned a long time ago that publishing your email address on a public site is asking for spam. But then again, maybe the bots are confused by the way that the email address is part of a URL in this case. Maybe that is good enough to break the address-scraping regex.