Use a two-stage flow
The steps below walk through this one stage at a time. Complete each step before continuing so nothing gets missed.
- Validate and normalise fields in the client for fast feedback.
- Insert through a policy or server-side function that validates again.
- Return a clear saved state without exposing internal details.
- Queue or send the notification from a trusted server boundary.
- Log delivery status and handle failure without losing the submission.
- Test duplicate submits, invalid input and provider failures.
Alongside that flow, a few rules protect the submission and the recipient.
- Never put an email provider API key in client code.
- Do not trust hidden fields for recipient or permissions.
- Do not show a success message when only the browser request completed.
Pre-launch checklist
This comes down to a handful of concrete details. Work through the list below and flag the ones you have not covered yet.
- Rate limiting or basic spam protection is in place.
- Failed email sends do not delete or lose the saved submission.
- Recipient address is configured server-side, not passed from the client.
- Confirmation state is only shown after the database insert succeeds.
- A test submission has been traced end to end from form to inbox.
Handover notes for the client
Use the list below as a working checklist. Each item is something you can verify or action directly on your own site.
- Where submissions are stored and how to export them.
- Who receives the notification email and how to change that recipient.
- What happens to a submission if the notification email fails.