I’ve recently created my website using GatsbyJS and it’s brilliant. I come from a full stack background, with a lot of back-end experience in PHP so the JAM stack is a different way of thinking for me. However, I’m all about embracing new technology!
My website is fairly simple and doesn’t really need a back-end so it seemed silly to use a CMS with a database; as a developer, I can easily add new information without the need for a fancy admin area. I do however have a contact form, so I needed to decide how I was going to send emails without a backend server.
Netlify does offer built in form handling but I was struggling to get this to work. It actually turns out that Gatsby wasn’t generating the static markup for this form so Netlify didn’t know about it (something to watch out for if your components are being hidden based on state). Also, I wanted the messages to go direct to my inbox, rather than checking on the Netlify site, so I decided lambda functions were the way to go.
Lambda functions basically allow you to create API endpoints without setting up a server. So I just needed to create an endpoint to send emails and call this endpoint when the form is submitted. I decided to use Sendgrid to send out my emails as I really like how you can keep track of activity and they have a really simple node library.
Setting up Netlify functions with Gatsby is really simple and there is already an amazing post on this, so I won’t go into details. Once you’ve ran through the steps in that post, you then just store all of your functions as js files in your lambda directory. Each file must export a handler method with 3 parameters, event, context and callback.
- event — is an object that contains details about the request, such as body and headers
- context — contains information about the context in which the function was called, e.g. identity user information
- callback — is a function that should be called to return either an error (as the first parameter) or a response object. (Although this actually isn’t needed for async calls)
So, to create my lambda function was really simple. I first of all installed and saved the sendgrid dependency using npm and then created a new function called sendmail.js within the lambda folder. One of the reasons why you shouldn’t send things from the client side is because tokens can be stolen easily. Therefore, we need to store the sendgrid API token within Netlify. I also decided to store the email address to send the email message to here, so that it can be updated easily. To access environment variables, go to your Netlify site dashboard, click on settings and click on build & deploy and then environment.
Ok, now we have the environment variables, let’s look at the code
For this function, you can see that we actually only use the event parameter and environment variables (from process.env). The form body is sent as JSON, so we simply parse this and get the values that we need from it. I decided to make it dynamic too and to send all of the fields within the body of my email, this means that if I decided to add another field to the form in future, the function won’t need updating.
The sendgrid documentation doesn’t mention error handling, however I didn’t want to just assume that the message had been sent. I’d rather tell a user that it failed so that I don’t miss out on an important message. I used async await and this caused me a bit of pain as I was getting errors such as
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'statusCode' of undefined when using the callback. It took a bit of hunting around to realise that if you are using an async function, you don’t use the callback, but simply return the response object!
So now we have the function, how do we call it? First of all I created a state object to store all of my form fields. I’m using React hooks, so I’ve written mine this way, however if you are using React classes, simply add to your this.state object.
I then attach a function onto the onChange event for each input element that will update this state.
Finally I created the submit handler below and attached it to onSubmit on my form element. This is just a skeleton, you can do whatever you need to do if the form sends or fails. On my site, I pop up a modal.
And that’s it! simple! Now this is very basic lambda function usage without authentication, etc. If you have functionality that requires authentication, I’d highly recommend reading this post.