Contact Form Setup Guide
This document explains the custom contact form implementation using Resend for email delivery.
Overview
The contact form on /contact-me has been replaced with a custom React form that uses Resend to send emails. This provides a better user experience and more control over the form submission process.
Features
- ✅ Custom React form with validation
- ✅ Responsive design matching the site's monochrome theme
- ✅ Two-email system:
- Notification email to cameron@cameronrohn.com
- Confirmation email to the submitter
- ✅ Loading states and error handling
- ✅ Success message with auto-dismiss
- ✅ Dark mode support
Form Fields
Required Fields:
- Name
- Subject
- Message
Optional Fields:
- Company Name
- Phone Number
Architecture
Frontend Component
- Location:
/src/components/ContactForm/ - Files:
index.jsx- React component with form logicstyles.module.css- CSS module for styling
Backend API
- Location:
/functions/api/contact.js - Type: Cloudflare Pages Function
- Method: POST only
- CORS: Enabled for cross-origin requests
Email Service
- Provider: Resend
- Package:
resend@6.2.2 - Authentication: API key stored as Cloudflare secret
Setup Instructions
1. Get Resend API Key
- Sign up at resend.com
- Navigate to API Keys
- Create a new API key
- Copy the API key (starts with
re_)
2. Verify Domain in Resend
Option A: Verify Root Domain (cameronrohn.com)
- Go to Resend Domains
- Click "Add Domain"
- Enter:
cameronrohn.com - Resend will provide DNS records (SPF and DKIM)
Option B: Use Subdomain (Recommended)
For better email deliverability, use a subdomain:
- Go to Resend Domains
- Click "Add Domain"
- Enter:
mail.cameronrohn.comorsend.cameronrohn.com - Resend will provide DNS records
3. Configure DNS Records (Cloudflare)
- Go to Cloudflare Dashboard
- Select domain:
cameronrohn.com - Navigate to DNS → Records
- Add the records provided by Resend:
SPF Record:
- Type:
TXT - Name:
@(or subdomain name if using subdomain) - Content:
v=spf1 include:_spf.resend.com ~all - TTL: Auto
DKIM Record:
- Type:
TXT - Name: (e.g.,
resend._domainkey) - Content: (long cryptographic key from Resend)
- TTL: Auto
- Wait 5-10 minutes for DNS propagation
- Return to Resend and click "Verify"
4. Set Cloudflare Secret
For production deployment, set the API key as a Cloudflare secret:
wrangler secret put RESEND_API_KEY
When prompted, paste your Resend API key.
5. Local Development (Optional)
For local testing with actual email sending:
-
Create
.env.localfile:RESEND_API_KEY=re_your_api_key_here -
Note: Local development uses Docusaurus dev server which doesn't support Cloudflare Functions. To test the API endpoint locally, you'll need to:
- Deploy to Cloudflare Pages preview environment, OR
- Use
wrangler pages devfor local function testing
Email Configuration
Update "From" Address
If using a subdomain, update the from field in /functions/api/contact.js:
// Change from:
from: 'Cameron Rohn - Contact <noreply@cameronrohn.com>',
// To:
from: 'Cameron Rohn - Contact <noreply@mail.cameronrohn.com>',
Customize Email Templates
The HTML email templates are located in /functions/api/contact.js:
- notificationHtml - Email sent to cameron@cameronrohn.com
- confirmationHtml - Email sent to the submitter
You can customize:
- Colors and styling
- Text content
- Logo/branding
- Layout
Deployment
Build and Deploy
# Build the site
yarn build
# Deploy to Cloudflare Pages
wrangler deploy
The build process will:
- Generate content index
- Build Docusaurus static site
- Build Cloudflare Functions
Verify Deployment
- Visit: https://cameronrohn.com/contact-me
- Fill out the form
- Submit and verify:
- Success message appears
- Email received at cameron@cameronrohn.com
- Confirmation email received at submitted address
Troubleshooting
Form submits but no emails sent
Check 1: Domain Verification
- Go to Resend Domains
- Ensure domain shows "Verified" status
- If not verified, check DNS records in Cloudflare
Check 2: API Key
- Verify secret is set:
wrangler secret list - If not listed, run:
wrangler secret put RESEND_API_KEY
Check 3: Cloudflare Logs
wrangler tail
Submit the form and check for errors in the logs.
Check 4: Resend Dashboard
- Go to Resend Emails
- Check for failed delivery attempts
- Review error messages
Form shows error message
Check Network Tab:
- Open browser DevTools → Network tab
- Submit form
- Look for
/api/contactrequest - Check response status and error message
Common Issues:
- 400: Missing required fields → Check form validation
- 401: Invalid API key → Reset Cloudflare secret
- 500: Server error → Check
wrangler taillogs
Emails go to spam
Solutions:
- Verify SPF and DKIM records are correct
- Use subdomain instead of root domain
- Warm up the domain by sending a few test emails
- Check Resend's deliverability guide
CORS errors
If you see CORS errors in the browser console:
- Check that
/functions/api/contact.jshas correct CORS headers - Verify the API endpoint is being called at
/api/contact - Ensure Cloudflare Functions are deployed
Testing Checklist
- Domain verified in Resend dashboard
- DNS records added to Cloudflare
- Cloudflare secret
RESEND_API_KEYset - Site deployed to Cloudflare Pages
- Form loads on https://cameronrohn.com/contact-me
- All fields visible and functional
- Required field validation works
- Form submission shows loading state
- Success message appears after submission
- Notification email received at cameron@cameronrohn.com
- Confirmation email received at submitted address
- Reply-to address is set correctly
- Email formatting looks good in Gmail/Outlook
- Dark mode styling works correctly
- Mobile responsive design works
Security Notes
- ✅ API key stored as Cloudflare secret (not in code)
- ✅ CORS headers configured for security
- ✅ Input validation on both frontend and backend
- ✅ Email validation using regex
- ✅ No API key in
.env.example(uses placeholder) - ✅ Sanitized HTML output to prevent injection
File Structure
website-docusaurus01/
├── src/
│ ├── components/
│ │ └── ContactForm/
│ │ ├── index.jsx # Form component
│ │ └── styles.module.css # Styles
│ └── pages/
│ └── contact-me.mdx # Contact page
├── functions/
│ └── api/
│ └── contact.js # Cloudflare Function
├── .env.example # Environment template
├── package.json # Dependencies (includes resend)
└── docs/
└── CONTACT_FORM_SETUP.md # This file
Resources
- Resend Documentation
- Cloudflare Pages Functions
- Docusaurus MDX Components
- Email Deliverability Guide
Support
For issues or questions:
- Check this guide first
- Review Resend docs
- Check Cloudflare logs:
wrangler tail - Review Resend dashboard for delivery logs