- Get link
- X
- Other Apps
- Get link
- X
- Other Apps
Astro makes it easy to create fast, lightweight websites, but a standard contact form does not automatically deliver messages to your inbox. The form can collect a visitor’s name, email address, and message in the browser, but it still needs a secure server-side process or third-party service to send that information by email.
In this guide, you will learn how to connect an Astro contact form with email using a secure Astro API endpoint and Resend. You will also learn how to protect your API key, validate submissions, prevent common spam, troubleshoot errors, and choose an alternative solution when your Astro website uses fully static hosting.
This method is suitable for:
- Business websites
- Developer portfolios
- Agency websites
- Landing pages
- Service-based websites
- Lead-generation websites
What You Need Before Connecting the Form
Before starting, make sure you have the following:
- A working Astro project
- Node.js and npm installed
- An email API provider account
- A verified domain or access to your DNS settings
- A destination email address
- A hosting platform that supports server-side functions
This tutorial uses Resend because it provides a simple Node.js package and a developer-friendly email API. However, the same general process can be adapted for Brevo, SendGrid, Mailgun, Postmark, or another reliable provider.
Astro pages are normally generated as static files. Because the email must be sent when a visitor submits the form, your contact endpoint must run dynamically on the server.
Important: Never place your email API key in browser-accessible HTML, JavaScript, or Astro component code. Anyone visiting the website may be able to discover and misuse it.
When converting an existing front-end project into WordPress, you may also find this guide on how to convert a React website into a lightweight WordPress theme helpful.
Create the Astro Contact Form
Create a file named contact.astro inside your src/pages directory.
The form will send the visitor’s information to an Astro API endpoint located at /api/contact.
---
// src/pages/contact.astro
---
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<title>Contact Us</title>
</head>
<body>
<main>
<h1>Contact Us</h1>
<form action="/api/contact" method="POST">
<div>
<label for="name">Name</label>
<input
id="name"
name="name"
type="text"
minlength="2"
maxlength="100"
required
/>
</div>
<div>
<label for="email">Email Address</label>
<input
id="email"
name="email"
type="email"
maxlength="200"
required
/>
</div>
<div>
<label for="message">Message</label>
<textarea
id="message"
name="message"
minlength="10"
maxlength="5000"
required
></textarea>
</div>
<div class="website-field" aria-hidden="true">
<label for="website">Website</label>
<input
id="website"
name="website"
type="text"
tabindex="-1"
autocomplete="off"
/>
</div>
<button type="submit">Send Message</button>
</form>
</main>
</body>
</html>
<style>
.website-field {
position: absolute;
left: -9999px;
}
</style>Every field must have a name attribute. Without it, the field’s value will not be included in the submitted form data.
The following attributes improve usability:
requiredprevents empty submissions.type="email"checks the basic email format.minlengthprevents extremely short entries.maxlengthlimits excessively large submissions.<label>elements improve accessibility.
The hidden website field is a basic honeypot. Normal visitors will not complete it, but automated bots may fill it in.
Browser validation improves the user experience, but it is not sufficient for security. The submitted data must also be validated on the server.
Build the Server-Side Email Endpoint
Install the Resend package from your Astro project directory:
npm install resendCreate the following file:
src/pages/api/contact.tsAdd this code:
import type { APIRoute } from "astro";
import { Resend } from "resend";
export const prerender = false;
const apiKey = import.meta.env.RESEND_API_KEY;
const contactToEmail = import.meta.env.CONTACT_TO_EMAIL;
const contactFromEmail = import.meta.env.CONTACT_FROM_EMAIL;
const resend = new Resend(apiKey);
function escapeHtml(value: string): string {
return value
.replaceAll("&", "&")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll('"', """)
.replaceAll("'", "'");
}
function isValidEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
export const POST: APIRoute = async ({ request }) => {
try {
if (!apiKey || !contactToEmail || !contactFromEmail) {
console.error("Contact form environment variables are missing.");
return new Response("Server configuration error.", {
status: 500,
});
}
const formData = await request.formData();
const name = String(formData.get("name") ?? "").trim();
const email = String(formData.get("email") ?? "").trim();
const message = String(formData.get("message") ?? "").trim();
const website = String(formData.get("website") ?? "").trim();
if (website) {
return new Response(null, { status: 204 });
}
if (
name.length < 2 ||
name.length > 100 ||
!isValidEmail(email) ||
email.length > 200 ||
message.length < 10 ||
message.length > 5000
) {
return new Response("Please check the submitted information.", {
status: 400,
});
}
const safeName = escapeHtml(name);
const safeEmail = escapeHtml(email);
const safeMessage = escapeHtml(message).replaceAll("\n", "<br />");
const { error } = await resend.emails.send({
from: contactFromEmail,
to: contactToEmail,
replyTo: email,
subject: `New website message from ${name}`,
html: `
<h2>New Contact Form Submission</h2>
<p><strong>Name:</strong> ${safeName}</p>
<p><strong>Email:</strong> ${safeEmail}</p>
<p><strong>Message:</strong></p>
<p>${safeMessage}</p>
`,
text: `
New Contact Form Submission
Name: ${name}
Email: ${email}
Message:
${message}
`,
});
if (error) {
console.error("Email provider error:", error);
return new Response(
"Your message could not be sent. Please try again.",
{ status: 502 },
);
}
return Response.redirect(
new URL("/thank-you/", request.url),
303,
);
} catch (error) {
console.error("Contact endpoint error:", error);
return new Response(
"An unexpected error occurred. Please try again.",
{ status: 500 },
);
}
};
export const ALL: APIRoute = async () => {
return new Response("Method not allowed.", {
status: 405,
headers: {
Allow: "POST",
},
});
};The following line is essential:
export const prerender = false;It tells Astro that the endpoint must run on demand rather than being generated as a static file.
The endpoint also:
- Reads the submitted form data.
- Rejects likely spam submissions.
- Validates field lengths and email formatting.
- Escapes user-provided content.
- Sends HTML and plain-text email versions.
- Handles provider and server errors.
- Redirects successful users to a thank-you page.
Escaping the submitted values is important because visitors should not be able to inject unwanted HTML into your notification email.
Add Environment Variables and a Server Adapter
Create a .env file in the project root:
RESEND_API_KEY=re_your_private_api_key
CONTACT_TO_EMAIL=you@example.com
CONTACT_FROM_EMAIL=Website Contact <contact@yourdomain.com>Replace the example values with your actual API key and email addresses.
Add the environment file to .gitignore:
.env
.env.*
!.env.exampleThis helps prevent private credentials from being uploaded to a public GitHub repository.
You must also add the same environment variables to your hosting platform. Local .env values are not automatically transferred when the website is deployed.
Verify Your Sending Domain
For reliable email delivery, verify your domain through your email provider and add the required DNS records.
Use an email address from the verified domain as the sender:
contact@yourdomain.comDo not use the visitor’s email as the sender. Instead, place it in the replyTo property. This allows you to reply directly while maintaining proper email authentication.
Install a Server Adapter
Install the adapter that matches your hosting platform.
For Netlify:
npx astro add netlifyFor Vercel:
npx astro add vercelFor Cloudflare:
npx astro add cloudflareFor a Node.js server:
npx astro add nodeInstall only one adapter based on your deployment environment.
Create a simple success page at:
src/pages/thank-you.astro---
---
<html lang="en">
<head>
<title>Thank You</title>
</head>
<body>
<main>
<h1>Thank You</h1>
<p>Your message has been sent successfully.</p>
<a href="/">Return to the homepage</a>
</main>
</body>
</html>Protect the Astro Contact Form From Spam
Any public form can eventually attract automated spam. The honeypot field provides basic protection, but a production website should use multiple safeguards.
Recommended protections include:
- Server-side validation: Validate every submitted field on the server.
- Rate limiting: Restrict repeated requests from the same IP address.
- Maximum field lengths: Prevent unusually large submissions.
- CAPTCHA or Turnstile: Add bot verification when spam becomes frequent.
- Origin checking: Reject requests from unauthorized websites.
- Generic error messages: Avoid exposing internal server details.
- Server-side logging: Log failed requests without unnecessarily storing personal data.
- Submission timing checks: Reject forms completed unrealistically quickly.
Security Tip: Never send an API key to the browser or include it in client-side JavaScript.
You should also consider adding a privacy notice near the form, especially when collecting names, email addresses, telephone numbers, or other personal information.
Test the Form and Fix Common Errors
Start the local Astro development server:
npm run devOpen your contact page and submit a test message.
Confirm that:
- The browser sends a POST request.
- The endpoint returns a success response or redirect.
- The message reaches the correct inbox.
- The reply button uses the visitor’s email.
- Invalid submissions return an error.
- The API key is not visible in browser tools.
- The form works after production deployment.
Use the browser Network panel and your hosting platform’s function logs when investigating errors.
| Problem | Likely Cause | Recommended Solution |
|---|---|---|
| API endpoint returns 404 | Incorrect route or static-only deployment | Check the file path and server adapter |
| Endpoint returns 500 | Missing environment variables | Add the variables to the hosting dashboard |
| Provider returns 403 | Sender domain is not verified | Verify the domain and sender address |
| Form reloads without sending | Incorrect action or request method | Use /api/contact and method="POST" |
| Email reaches spam | Authentication records are missing | Configure the required DNS records |
| Duplicate emails arrive | Multiple submissions are being sent | Disable the button after submission |
| Local form works but live form fails | Production configuration is different | Check live variables and function logs |
Always test the deployed website before considering the integration complete. Local testing cannot fully verify production environment variables, DNS authentication, serverless behavior, or real email delivery.
Alternative Ways to Connect an Astro Form With Email
A custom API endpoint provides control and flexibility, but it is not the only available solution.
Astro Actions
Astro Actions provide structured server-side functions, input validation, and standardized error handling. They can be useful for modern Astro projects that contain several interactive forms.
Hosted Form Services
Services such as Formspree, Basin, Getform, and Netlify Forms can process submissions without a custom email endpoint.
They are useful for:
- Small static websites
- Beginner projects
- Simple portfolio forms
- Websites with low submission volume
However, free plans may include submission limits, branding, reduced control, or fewer spam-protection features.
External Serverless Functions
You can keep the main Astro website static and send submissions to a separate serverless function hosted on platforms such as Vercel, Netlify, Cloudflare, or AWS.
This approach provides flexibility but creates an additional service that must be secured and maintained.
| Method | Best For | Main Limitation |
|---|---|---|
| Astro API endpoint | Custom business forms and complete control | Requires server-compatible hosting |
| Astro Actions | Modern Astro projects with multiple forms | Requires backend runtime configuration |
| Hosted form service | Beginners and simple static sites | Usage limits and less customization |
| External function | Static hosting with a separate backend | Additional configuration and maintenance |
For most small business websites, an Astro API endpoint or Astro Action offers the best balance of security, customization, and reliability.
Frequently Asked Questions
Can an Astro contact form send email without a backend?
A browser form cannot securely use a private email API key by itself. You need an Astro endpoint, Astro Action, serverless function, or hosted form-processing service.
Can I connect an Astro contact form to Gmail?
Yes. Your email provider can deliver form notifications to a Gmail address. Do not place Gmail credentials or API keys inside browser-accessible code.
Why does my Astro contact form work locally but not online?
Your production environment variables may be missing, the incorrect server adapter may be installed, or the hosting platform may not support the selected server runtime.
Can I use PHP to process an Astro contact form?
Yes, but only when your hosting server supports PHP. Many Astro websites use Node.js endpoints or serverless functions instead.
Is Resend required for an Astro contact form?
No. You can use Brevo, SendGrid, Mailgun, Postmark, Formspree, Netlify Forms, or another trusted provider.
How can I reduce contact form spam?
Use server-side validation, rate limiting, a honeypot field, submission timing checks, field-length restrictions, and CAPTCHA or Cloudflare Turnstile when needed.
Should I use the visitor’s email as the sender address?
No. Use an address from your verified domain as the sender and place the visitor’s email in the reply-to field.
Conclusion
Learning how to connect an Astro contact form with email involves more than adding a few form fields. The form needs a secure server-side handler, protected environment variables, an authenticated email provider, proper validation, spam protection, and a compatible hosting environment.
The API endpoint method covered in this guide provides a strong foundation. It validates visitor information, blocks basic bot submissions, safely creates the email, handles provider errors, and redirects successful users to a confirmation page.
Before launching your form, test it on the live website, verify your sending domain, review your server logs, and confirm that no private API credentials are publicly accessible.
A carefully configured contact form provides visitors with a reliable way to reach your business while protecting your website and email account from unnecessary security and delivery problems.
Astro
Astro Contact Form
Contact Form Tutorial
Email Integration
JavaScript
Resend API
Static Website
Web Development
- Get link
- X
- Other Apps








Comments
Post a Comment
Please keep your comment relevant to the article. Do not include passwords, API keys, personal information, or promotional links.