Sending Contact Form Emails with Netlify Serverless Functions

📩 Sending Contact Form Emails Using Netlify Serverless Functions
At Bluesunrise, we believe that modern web apps should be fast, secure, and server-free whenever possible. When building our new Astro website, we wanted to include a Contact Us form that sends an email — without setting up a custom server.
Thanks to Netlify Serverless Functions, Google reCAPTCHA, and AWS SES, we were able to do this in a simple, scalable way — with zero backend code running 24/7.
🧱 The Goal
We wanted our contact form to:
- ✅ Collect user info (name, email, message, etc.)
- ✅ Validate reCAPTCHA to block spam
- ✅ Send the message to our email address
- ✅ Work without deploying our own server
- ✅ Be secure and easy to maintain
✨ The Frontend: Astro Contact Form
We built our form using Astro components like Input
, Textarea
, Radio
, and Select
. When a user clicks Submit, we collect the form data and send it to a Netlify serverless function via fetch()
:
const response = await fetch("/.netlify/functions/send-email", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
We also included Google reCAPTCHA to prevent spam and bots. The token is sent along with the request and verified on the server side.
🔐 The Serverless Function: send-email.js
This Netlify Function is triggered on form submission. Here’s what it does:
- Parses the form
const { name, email, phone, message, captchaToken } = JSON.parse(event.body);
- Validates reCAPTCHA with Google
const captchaResponse = await fetch(
"https://www.google.com/recaptcha/api/siteverify",
{
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: `secret=${captchaSecret}&response=${captchaToken}`,
},
);
If verification fails, we return a 403 error.
- Sends the email using AWS SES
AWS.config.update({
accessKeyId: process.env.NETLIFY_AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.NETLIFY_AWS_SECRET_ACCESS_KEY,
});
Then we used the AWS SDK to send the message:
await ses.sendEmail(params).promise();
The HTML message contains all the form fields and is formatted nicely for email readers.
✅ Why We Love This Approach
Using Netlify Functions for form submission offers many benefits:
✔ No backend server to maintain. No need for Express, Node, or deployment pipelines. The function runs on demand.
✔ Pay only for usage. Netlify includes generous limits for functions in the free tier. We only pay if traffic grows significantly.
✔ Easy integration with Astro. Astro doesn’t have a backend runtime — but Netlify Functions give you just enough server logic when needed.
✔ Secure and scalable. We store our keys in Netlify environment variables and validate users with reCAPTCHA.
🧪 Things to Watch For
✅ Make sure your AWS SES account is verified and in production mode.
✅ Use Netlify’s environment variables for secret keys (never commit them).
✅ If needed, log errors from the serverless function for easier debugging.
🧠 Final Thoughts
This setup proves that you don’t need a traditional server to build secure, full-featured websites. With Astro, Netlify, and a bit of AWS, you can build fast, beautiful websites with powerful backend features — without leaving the JAMstack.