Contact Us Form with Astro and Resend

Back to Blog

In this article, we will cover how to set up an Astro powered Contact Us form that uses Resend to deliver an email to you when the form is submitted.

Setup Astro

Creating a new Astro application is simple. If you don't have Node.js on your machine, you'll need to download and install it.

Once you have Node on your machine, just run the following command in your terminal.

npm create astro@latest

Once the Astro app is setup, make a new page by creating a new file: src/pages/contact-us.astro We'll keep it empty for now.

Create Resend Account

Now let's get setup a Resend account and generate an API key.

Once you have the API key, add it to your Astro's .env file

RESEND_API_KEY=REPLACE_WITH_YOUR_KEY

Create An Astro Action

Now that we have the Astro application created, and a Resend API key to use, let's define an Astro Action. The purpose of this action is to receive the form input, and to send an email to your inbox.

// src/actions/index.ts import { ActionError, defineAction } from "astro:actions"; import { Resend } from "resend"; import { z } from "astro:schema"; export const server = { sendEmail: defineAction({ // Set this action to receive data as form submissions accept: "form", // Declare what fields to expect, and how to validate them // Behind the scenes, astro:schema uses ZOD formats input: z.object({ email: z.string().email().min(1, "Email is required"), contact_name: z.string().min(1, "Name is required"), message: z.string().min(1, "Message is required"), }), handler: async ( { email, contact_name, message } ) => { const resend = new Resend(import.meta.env.RESEND_API_KEY); const emailPayload = { from: "onboarding@resend.dev", to: "YOUR_EMAIL@HERE.com", subject: `Contact Us Submission from ${contact_name}`, replyTo: email, html: `<h1>New Contact Submission</h1><div><p>Email: ${email}</p></div><div><p>Name: ${contact_name}</p></div><div><p>Message: ${message}</p></div>`, }; const { data, error } = await resend.emails.send(emailPayload); if (error) { throw new ActionError({ code: "BAD_REQUEST", message: error.message, }); } return data; }, }), };

Build the Contact Page

With the Astro Action in place, let's fill in the empty src/pages/contact-us.astro page we created earlier.

--- // if you have a layout, import it import Layout from "../layouts/Layout.astro"; // import the actions import { actions } from "astro:actions"; // set the page as being client rendered instead of SSR export const prerender = false; // Get the result, including any possible errors const actionResult = Astro.getActionResult(actions.sendEmail); --- <Layout> <div> <h1>Contact Us</h1> { actionResult && !actionResult.error && ( <div> Success! </div> ) } { actionResult && actionResult.error && ( <div> Error! <br /> {actionResult.error.message || "Unknown error"} </div> ) } <!-- default message, when no form is submitted --> { !actionResult && ( <p> Fill out the form below to connect with us. </p> ) } <form action={actions.contact.sendEmail} method="POST"> <div> <label for="contact_name"> Name: </label> <input type="text" id="name" name="contact_name" required /> </div> <div> <label for="email"> Email: </label> <input type="email" id="email" name="email" required /> </div> <div> <label for="message"> Message: </label> <textarea id="message" name="message" required></textarea> </div> <button type="submit" id="contact-us-submit"> Send Message </button> </form> </div> </Layout>

All Done!

And there you have it. A fully functional contact-us form. Load up your website and visit the /contact-us route to see your page in action!

I hope you found this post useful and informative. No go and build something awesome!