AWS S3

Add a contact form to a static website on Amazon S3 or CloudFront without Lambda, API Gateway or SES.

Amazon S3 serves files and nothing else: an S3 website endpoint answers only GET and HEAD requests, so a form posted to your bucket fails. The usual AWS answer is API Gateway plus a Lambda function plus SES, with IAM roles and a verified sender to set up. With SilentForms none of that is needed. The form posts from the visitor's browser to the submit endpoint, SilentForms emails you the submission, and your bucket keeps serving static files.

1. Get an access key#

Enter your email on the access key page and click the confirmation link. The key only routes submissions to your inbox, so it is safe in a public object.

2. Create the form page#

Create contact.html in your site folder:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Contact</title>
</head>
<body>
  <h1>Contact</h1>
  <form action="https://silentforms.com/api/submit" method="POST">
    <input type="hidden" name="accessKey" value="YOUR_ACCESS_KEY_HERE">
    <input type="hidden" name="redirect" value="https://www.example.com/thanks.html">

    <label for="name">Name</label>
    <input id="name" type="text" name="name" autocomplete="name" required>

    <label for="email">Email</label>
    <input id="email" type="email" name="email" autocomplete="email" required>

    <label for="message">Message</label>
    <textarea id="message" name="message" rows="6" required></textarea>

    <!-- Honeypot: hidden from people, filled in by bots -->
    <input type="checkbox" name="botcheck" style="display: none;" tabindex="-1" autocomplete="off">

    <button type="submit">Send</button>
  </form>
</body>
</html>

3. Create the thank-you page#

The thank-you page is just another object in the bucket. Create thanks.html:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="robots" content="noindex">
  <title>Thanks</title>
</head>
<body>
  <h1>Thanks!</h1>
  <p>Your message is on its way. We will reply by email.</p>
  <p><a href="/">Back to the homepage</a></p>
</body>
</html>

The redirect in the form points at it with the full file name, thanks.html. That works on every setup below; a folder-style URL such as /thanks/ only works where an index document is resolved for subfolders (see the gotchas). Without the redirect field, visitors land on the default SilentForms success page. See Redirect after submit.

4. Upload#

Sync the folder to the bucket with the AWS CLI:

aws s3 sync ./site s3://www.example.com --delete

The CLI sets Content-Type: text/html from the .html extension. If you upload another way, make sure the objects have that content type, or browsers download the page instead of showing it.

Choose how the bucket is served#

S3 website endpoint#

With static website hosting enabled on the bucket and its objects publicly readable, the site is available at the bucket's website endpoint, for example http://www.example.com.s3-website-us-east-1.amazonaws.com. This is fine for testing, but website endpoints do not support HTTPS. The form still posts securely, because the browser sends it straight to SilentForms over HTTPS, but the page itself and the thank-you page are served over plain HTTP.

For HTTPS and a custom domain, put a CloudFront distribution in front of the bucket, with a certificate from AWS Certificate Manager for your domain. Then use the HTTPS URL in redirect: https://www.example.com/thanks.html. After uploading changes, invalidate the cache so CloudFront serves the new files:

aws cloudfront create-invalidation --distribution-id YOUR_DISTRIBUTION_ID --paths "/*"

The distribution only needs to allow GET and HEAD. The form's POST never touches CloudFront.

What you do not need#

  • No Lambda, API Gateway or SES. Nothing on AWS runs when a form is submitted.
  • No CORS configuration on the bucket. CORS rules on a bucket control which sites may read from that bucket. Here the browser sends the form to SilentForms, which is the server that answers the cross-origin request, and it allows any origin. Your bucket is not part of that request.
  • No IAM credentials in the page. The access key is not an AWS credential and only routes submissions.

Test it#

Open contact.html on the website endpoint or your CloudFront domain, send yourself a message and check that you land on thanks.html and the email arrives (check spam the first time). In the browser's network tab, the submit request should go to the SilentForms endpoint and return a 303 redirect to your thank-you page.

Gotchas#

  • The redirect shows "403 Forbidden" or "AccessDenied" XML. The thank-you object is missing, misspelt or not publicly readable. With CloudFront and a private bucket, a missing object also shows up as 403 rather than 404.
  • /thanks/ works on the website endpoint but not through CloudFront. When CloudFront reads from the bucket's REST endpoint, the default root object applies only to the root URL, not to subfolders. Link to thanks.html directly.
  • Visitors see the old form after you change it. CloudFront is still serving the cached copy. Run an invalidation.
  • "Invalid or inactive access key." The key in the uploaded file is wrong, or the form is paused in the dashboard.

For every error message, see Troubleshooting.

Next steps#