I'm currently working on an article that discusses various third party services that can help flesh out a static web site. While researching that article, I got to thinking about contact forms and how (or if) I could use Parse to power them. Parse is built for ad hoc data storage of - well - anything. I wouldn't typically think of contact forms as being something I'd want to save, but the more I thought about it, the more I thought that in some organizations this could be a powerful feature. You can track communication over time as well as use the email addresses as a list to contact in the future. There are probably multiple ways of doing this, but here is what I came up with.
I began with - of course - the contact form. I built something short and sweet that I thought would be fairly typical. It asks for a name, email address, an "area" (i.e., why are you contacting us), and has a box for the comment.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
</head>
<body>
<h2>Contact Form</h2>
<form id="commentForm">
<p>
<label for="name">Your Name</label>
<input type="text" name="name" id="name" required>
</p>
<p>
<label for="email">Your Email</label>
<input type="email" name="email" id="email" required>
</p>
<p>
<label for="area">Your question involves:</label>
<select name="area" id="area">
<option value="stuff">Stuff</option>
<option value="otherstuff">Other Stuff</option>
<option value="starwars">Star Wars</option>
<option value="startrek">Star Trek</option>
</select>
</p>
<p>
<label for="comments">Your Comments<br/></label>
<textarea name="comments" id="comments" required></textarea>
</p>
<p>
<input type="submit" value="Send Comments">
</p>
</form>
<script src="http://www.parsecdn.com/js/parse-1.2.12.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="app.js"></script>
</body>
</html>
I assume none of this needs to be explained, but I will point out I'm using HTML5 form validation here. At the bottom I'm loading jQuery, Parse's library, and my own JavaScript file app.js. I began by building a simple shell of a form handler.
/* global $,document,console */
$(document).ready(function() {
$("#commentForm").on("submit", function(e) {
e.preventDefault();
console.log("Handling the submit");
//add error handling here
//gather the form data
var data = {};
data.name = $("#name").val();
data.email = $("#email").val();
data.area = $("#area option:selected").val();
data.comments = $("#comments").val();
});
});
Again - I assume this is pretty boilerplate. Note that I intentionally skipped doing form validation. As that's been done about eleven billion times or so I wanted to keep this proof of concept as simple as possible.
Ok, so let's talk Parse. I'm going to assume you've read my earlier posts on Parse. I went ahead and set up a new application on Parse and copied down my appropriate keys. My HTML file already had Parse's JavaScript library included so I didn't need to do anything there. I knew I could easily take the comment data and store it in Parse. Here is the updated version with Parse enabled.
/* global $,document,console,Parse */
$(document).ready(function() {
var parseAPPID = "1xW2AmMzvU7pukTxmXycGC6zVIsC9llnLesiGvXZ";
var parseJSID = "k8dOFpCbQcdyaGCDk9jytrlaGezfnGMIKsuy8veX";
Parse.initialize(parseAPPID, parseJSID);
var CommentObject = Parse.Object.extend("CommentObject");
$("#commentForm").on("submit", function(e) {
e.preventDefault();
console.log("Handling the submit");
//add error handling here
//gather the form data
var data = {};
data.name = $("#name").val();
data.email = $("#email").val();
data.area = $("#area option:selected").val();
data.comments = $("#comments").val();
var comment = new CommentObject();
comment.save(data, {
success:function() {
console.log("Success");
//Alerts are lame - but quick and easy
alert("Thanks for filling the form!");
},
error:function(e) {
console.dir(e);
}
});
});
});
Again, I tried to keep it simple so on a successful return I use a lame alert to let you know it went through. I don't even publicly display a message if an error is thrown. Again, bad. But I was trying to make the demo as simple as possible. I ran this and confirmed that I could fill out the form and the results would be stored at Parse.
While this would work, I'd have to constantly check the Parse dashboard to see when someone filled out my contact form. How can I add email support?
One of the more interesting features of Parse is Cloud Code. Cloud Code is JavaScript that runs on the server. One of the best examples of it is performing aggregate operations. Imagine you had a million or so "Rating" objects. If you wanted to get an average for all the objects you could download them all to the client and loop. Or you can run code on Parse's server and do it there instead. Guess which one is better?
Along with having access to your data on the server itself, Parse has a set of Cloud Modules that wrap various third-party services. One of them is Mailgun. Mailgun is a mail API service that provides up to 10000 emails on their free tier. That kicks ass. I think my blog here is reasonably successful for a tech site and I get maybe 100 or so emails per month from my contact form.
I followed the directions for installing a new Cloud Code directory and it created a new file, main.js, with a sample Cloud Code function. The docs have an example of running code on saving data, so I used that as my basis as well as the docs on using the Mailgun module. Here is my final function:
/* global Parse,console,require */
var Mailgun = require('mailgun');
Mailgun.initialize('raymondcamden.mailgun.org', 'mykeysmilkshakeisbetterthanyours');
Parse.Cloud.beforeSave("CommentObject", function(request, response) {
var text = "Comment Email\n" +
"From: "+request.object.get("name") + "\n"+
"Email: "+request.object.get("email") + "\n"+
"Area: "+request.object.get("area") + "\n\n"+
"Comments:\n" + request.object.get("comments");
Mailgun.sendEmail({
to: "raymondcamden@gmail.com",
from: request.object.get("email"),
subject: "Comment Form - " + request.object.get("area"),
text: text
}, {
success: function(httpResponse) {
response.success();
},
error: function(httpResponse) {
console.error(httpResponse);
response.error("Uh oh, something went wrong");
}
});
});
You can see where I take the data from the Comment object and use that when I speak to Mailgun. I also use the email address on the form as the from value. This makes it easy to reply. I've also taken the "area" field and used that in the subject. That could be useful for filtering emails based on what they concern. And does it work? Yep!
Want to give it a try yourself? Hit the demo and spam me to high heaven.