Let the contact form deliver to several inboxes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Alejandro Veras
2026-10-13 09:46:20 -04:00
parent b3d93d7cbc
commit a259c92cb0
3 changed files with 8 additions and 5 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
# Resend — sends contact form submissions by email # Resend — sends contact form submissions by email
RESEND_API_KEY= RESEND_API_KEY=
CONTACT_FROM="AI Growth Website <hello@aigrowthtechnologies.com>" CONTACT_FROM="AI Growth Website <hello@aigrowthtechnologies.com>"
# Optional: inbox for enquiries (defaults to rey@aigrowth360.io) # Optional: inbox(es) for enquiries, comma-separated (defaults to rey@aigrowth360.io)
# CONTACT_TO= # CONTACT_TO=
# Optional: Cloudflare Turnstile bot check # Optional: Cloudflare Turnstile bot check
+1 -1
View File
@@ -17,7 +17,7 @@ Copy `.env.example` to `.env.production` (or `.env.local` for development) and f
|---|---|---| |---|---|---|
| `RESEND_API_KEY` | yes | Resend key with sending access to `aigrowthtechnologies.com`. Without it the contact form shows an error. | | `RESEND_API_KEY` | yes | Resend key with sending access to `aigrowthtechnologies.com`. Without it the contact form shows an error. |
| `CONTACT_FROM` | yes | Sender, on the domain verified in Resend: `AI Growth Website <hello@aigrowthtechnologies.com>` | | `CONTACT_FROM` | yes | Sender, on the domain verified in Resend: `AI Growth Website <hello@aigrowthtechnologies.com>` |
| `CONTACT_TO` | no | Inbox that receives enquiries. Defaults to `rey@aigrowth360.io`. | | `CONTACT_TO` | no | Inbox that receives enquiries; separate several with commas. Defaults to `rey@aigrowth360.io`. |
| `TURNSTILE_SECRET_KEY` / `NEXT_PUBLIC_TURNSTILE_SITE_KEY` | no | Cloudflare Turnstile. When both are set, the form shows the challenge. `NEXT_PUBLIC_*` values are baked in at build time, so rebuild after changing it. | | `TURNSTILE_SECRET_KEY` / `NEXT_PUBLIC_TURNSTILE_SITE_KEY` | no | Cloudflare Turnstile. When both are set, the form shows the challenge. `NEXT_PUBLIC_*` values are baked in at build time, so rebuild after changing it. |
## Deploying to a VPS ## Deploying to a VPS
+6 -3
View File
@@ -4,8 +4,11 @@ import { headers } from "next/headers";
export type ContactState = { status: "idle" | "sent" | "error"; message?: string }; export type ContactState = { status: "idle" | "sent" | "error"; message?: string };
// Where enquiries land. Override with CONTACT_TO in the environment if it ever changes. // Where enquiries land. Override with CONTACT_TO (comma-separated for several inboxes) if it ever changes.
const TO = process.env.CONTACT_TO || "rey@aigrowth360.io"; const TO = (process.env.CONTACT_TO || "rey@aigrowth360.io")
.split(",")
.map((a) => a.trim())
.filter(Boolean);
// Resend's shared sender only delivers to the address that owns the Resend account. To send to TO // Resend's shared sender only delivers to the address that owns the Resend account. To send to TO
// from any other account, set CONTACT_FROM to an address on a domain verified in Resend // from any other account, set CONTACT_FROM to an address on a domain verified in Resend
// (e.g. "AI Growth Website <hello@aigrowthtechnologies.com>"). // (e.g. "AI Growth Website <hello@aigrowthtechnologies.com>").
@@ -97,7 +100,7 @@ export async function sendContact(_prev: ContactState, formData: FormData): Prom
try { try {
await sendEmail(apiKey, { await sendEmail(apiKey, {
to: [TO], to: TO,
reply_to: email, reply_to: email,
subject: `New enquiry — ${company || name}`, subject: `New enquiry — ${company || name}`,
text: `${rows.map(([k, v]) => `${k}: ${v}`).join("\n")}\n\n${message}`, text: `${rows.map(([k, v]) => `${k}: ${v}`).join("\n")}\n\n${message}`,