Progressive Enhancement and Form Actions
In React Router v7 and Remix, form submissions are handled on the server via action functions. This guarantees that email submissions succeed even if client-side JavaScript has not loaded or has been blocked by ad blockers.
Implementing the Action Handler (routes/contact.tsx)
Validate incoming FormData with Zod, dispatch the email asynchronously, and return structured JSON responses to the UI.
import type { ActionFunctionArgs } from '@remix-run/node';
import { json } from '@remix-run/node';
import { z } from 'zod';
const ContactSchema = z.object({
email: z.string().email(),
name: z.string().min(2),
message: z.string().min(10),
});
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData();
const parsed = ContactSchema.safeParse(Object.fromEntries(formData));
if (!parsed.success) {
return json({ errors: parsed.error.flatten().fieldErrors }, { status: 400 });
}
const { email, name, message } = parsed.data;
const res = await fetch('https://api.sadasend.com/v1/emails', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SADASEND_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
to: 'support@sadasend.com',
replyTo: email,
subject: `Contact Inquiry from ${name}`,
text: `From: ${name} (${email})\n\nMessage:\n${message}`,
}),
});
if (!res.ok) {
return json({ error: 'Delivery network temporarily unavailable' }, { status: 502 });
}
return json({ success: true });
}Key architectural benefits
- Zero client bundle bloat: Email validation and API credentials remain 100% server-side.
- Built-in CSRF protection: Remix actions handle request origins automatically.
- Instant client revalidation: The UI updates smoothly without full page reloads.
Building AI agents that send email?
Join the SadaSend early access waitlist to get scoped API keys, recipient allowlists, and Model Context Protocol (MCP) servers upon launch.