# Ajouter un formulaire de contact à un site statique Amazon S3

> Les website endpoints S3 n'acceptent que GET et HEAD en HTTP simple : envoyez le formulaire à un backend et gérez bien les redirections avec CloudFront.

Publié le 2026-10-25 · https://ikiform.com/fr/guides/contact-form-static-site/aws-s3

Un website endpoint S3 répond à un `POST` de formulaire par `405 MethodNotAllowed` : faites donc pointer l'`action` du formulaire vers votre endpoint Ikiform. Comme l'endpoint est en `http:` simple, un `_redirect` vers lui n'est jamais suivi ; définissez **Redirect after submit** dans les réglages du formulaire, ou placez CloudFront devant pour avoir du `https:`. Avec CloudFront devant le REST endpoint du bucket, redirigez vers un nom de fichier complet comme `thanks.html`, car l'objet racine par défaut ne s'applique qu'à la racine.

## Ce qui change sur S3

Un bucket configuré pour l'hébergement de site statique a son propre website endpoint, comme `http://www.example.com.s3-website-us-east-1.amazonaws.com`. AWS indique qu'il ne prend en charge que les requêtes `GET` et `HEAD` sur les objets. Un envoi de formulaire reçoit une page d'erreur HTML :

`Réponse à un POST`:

```html
<html>
<head><title>405 Method Not Allowed</title></head>
<body>
<h1>405 Method Not Allowed</h1>
<ul>
<li>Code: MethodNotAllowed</li>
<li>Message: The specified method is not allowed against this resource.</li>
<li>Method: POST</li>
<li>ResourceType: OBJECT</li>
```

Trois autres particularités de S3 façonnent le formulaire de contact :

| Particularité de S3 | Conséquence pour le formulaire |
| --- | --- |
| Les website endpoints ne prennent pas en charge HTTPS | Ikiform ne suit un `_redirect` que vers une URL `https:` : une redirection vers l'endpoint nu est donc ignorée |
| Les en-têtes de réponse viennent de CloudFront, pas du bucket | Une Content-Security-Policy se définit dans une politique d'en-têtes de réponse CloudFront |
| L'objet racine par défaut de CloudFront ne s'applique qu'à la racine | Avec une origine REST, `https://example.com/thanks/` ne charge pas `thanks/index.html` ; redirigez vers `thanks.html` |

Pour un site en `https:`, AWS recommande Amplify Hosting, qui repose sur CloudFront, ou CloudFront devant le bucket. Le formulaire fonctionne dans les deux cas. Ce qui change, c'est l'endroit où arrive le visiteur après l'envoi.

Schéma : Où arrive le visiteur après l'envoi, avec et sans CloudFront

1. Sur le website endpoint nu, la page est servie en http et envoie à Ikiform.
2. Ikiform stocke le message, mais ignore un _redirect vers une adresse http et affiche sa page de remerciement hébergée.
3. Définir Redirect after submit dans le tableau de bord contourne ce problème, car ce réglage accepte les URL http.
4. Derrière CloudFront avec votre propre domaine, la page est en https.
5. Ikiform suit le _redirect vers votre thanks.html, tant que le domaine figure dans Allowed domains.

Le message est stocké dans les deux cas. Seule la dernière étape, la destination du navigateur, dépend de https.

## Quelle origine CloudFront

CloudFront peut lire le bucket de deux façons, et ce choix détermine la forme de votre URL de remerciement :

| Origine | Bucket | Pages d'index de dossier | URL de remerciement |
| --- | --- | --- | --- |
| Le website endpoint S3, comme origine personnalisée | Doit être lisible publiquement | Fonctionnent : `/thanks/` charge `thanks/index.html` | `/thanks/` ou `/thanks.html` |
| Le REST endpoint, avec origin access control | Reste privé, lu uniquement par CloudFront | Seulement la racine, via l'objet racine par défaut | `/thanks.html`, un nom de fichier complet |

Un nom de fichier complet fonctionne dans les deux cas, c'est pourquoi les exemples en utilisent un. Si vous préférez ne pas gérer CloudFront vous-même, Amplify Hosting peut déployer depuis le bucket avec `https:` et un CDN géré ; le formulaire n'y demande aucune modification non plus.

## Le formulaire

Les sites S3 sont souvent des sites d'entreprise : ce formulaire demande donc un e-mail professionnel et le nom de l'entreprise. Téléversez-le sous le nom `contact.html` à côté de `thanks.html` :

`contact.html`:

```html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
  <label for="name">Name</label>
  <input id="name" name="name" autocomplete="name" required />

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

  <label for="company">Company</label>
  <input id="company" name="company" autocomplete="organization" />

  <label for="message">How can we help?</label>
  <textarea id="message" name="message" rows="6" minlength="10" required></textarea>

  <input type="hidden" name="_redirect" value="https://www.example.com/thanks.html" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button type="submit">Send</button>
</form>
```

- Le `_redirect` pointe vers le domaine CloudFront, avec un nom de fichier. Il n'est suivi que si `www.example.com` ou `example.com` figure dans **Allowed domains**.
- Sur l'endpoint `http:` nu, retirez l'input `_redirect` et réglez plutôt **Redirect after submit** sur la page de remerciement. Ce réglage accepte les URL `http:`, car seule votre équipe peut le modifier.
- Gardez `email` comme nom de champ. Les e-mails de notification l'utilisent comme adresse de réponse.

Sur un site d'entreprise, plusieurs personnes lisent généralement la boîte de contact. Ajoutez jusqu'à 10 destinataires de notification confirmés au formulaire ; chacun reçoit le message, et celui qui clique sur **Reply** répond directement à l'expéditeur. Si les messages doivent aussi arriver dans un canal partagé ou une file de tickets, ajoutez un webhook signé et acheminez-le via [Zapier](https://ikiform.com/blog/form-submissions-to-zapier.md) ou votre propre code. Le champ `company` arrive en texte brut, prêt à être filtré dans l'un ou l'autre.

Avant de téléverser, testez la page depuis un serveur local avec `localhost` dans **Allowed domains**. Les envois depuis `localhost` comptent comme des tests : vous pouvez donc mettre le formulaire au point avant même que le bucket ne le serve.

Synchronisez le dossier avec le bucket, et invalidez les pages dans CloudFront pour que le nouveau formulaire soit servi tout de suite :

`Terminal`:

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

aws cloudfront create-invalidation --distribution-id E1EXAMPLE --paths "/contact.html" "/thanks.html"
```

## Domaines autorisés sur les hôtes AWS

| Où la page est servie | À ajouter |
| --- | --- |
| Website endpoint nu | L'hôte complet de l'endpoint du bucket, comme `www.example.com.s3-website-us-east-1.amazonaws.com` |
| Domaine CloudFront par défaut | L'hôte exact `d111111abcdef8.cloudfront.net`, pendant vos tests |
| Votre propre domaine | `example.com`, qui couvre aussi `www.example.com` |

N'ajoutez jamais seuls `amazonaws.com`, un suffixe régional `s3-website` ou `cloudfront.net`. Tous les buckets ou distributions du monde correspondraient. AWS inscrit les domaines des website endpoints S3 dans la Public Suffix List pour la même raison : chaque bucket est un site distinct.

## Les en-têtes via CloudFront

Les métadonnées d'objet S3 ne peuvent pas définir de Content-Security-Policy : définissez-la dans une politique d'en-têtes de réponse CloudFront et associez-la au comportement de cache par défaut de la distribution. La valeur de l'en-tête est limitée à 1 783 caractères :

`csp-policy.json`:

```json
{
  "Name": "site-csp",
  "SecurityHeadersConfig": {
    "ContentSecurityPolicy": {
      "Override": true,
      "ContentSecurityPolicy": "default-src 'self'; form-action 'self' https://ikiform.com; connect-src 'self' https://ikiform.com"
    }
  }
}
```

`Terminal`:

```bash
aws cloudfront create-response-headers-policy --response-headers-policy-config file://csp-policy.json
```

> `Override: true` remplace toute CSP envoyée par l'origine. Avec une origine S3 nue, il n'y en a pas, mais cela garde la politique aux commandes si vous changez d'origine plus tard.

## Vérifiez que tout fonctionne

1. Ajoutez les domaines du tableau ci-dessus, plus `localhost` pendant vos tests.
2. Envoyez depuis votre domaine CloudFront. Vous devez arriver sur `thanks.html` sur votre propre domaine.
3. Si vous gardez aussi le website endpoint nu public, envoyez depuis celui-ci et vérifiez que vous arrivez sur la page définie dans **Redirect after submit**.
4. Ouvrez **Submissions** dans le tableau de bord. La nouvelle soumission y est, avec tous les champs envoyés.
5. Vérifiez la boîte de réception de chaque destinataire des notifications. Chacun reçoit un e-mail avec les champs, et **Reply** répond à l'expéditeur quand le formulaire a un champ `email`.
6. Rien n'est arrivé ? Passez le filtre de statut du tableau de bord sur **Spam**. Le spam reçoit la même réponse de succès qu'une vraie soumission.

## Pièges

| Problème | Que faire |
| --- | --- |
| `405 Method Not Allowed` avec `Code: MethodNotAllowed` | Le formulaire a envoyé vers le bucket. CloudFront sert peut-être encore l'ancien `contact.html` ; invalidez-le. |
| `AccessDenied` ou `403` après la redirection | La redirection pointe vers un dossier comme `/thanks/` sur une distribution CloudFront avec une origine REST. Faites-la pointer vers `thanks.html`. |
| Le navigateur arrive sur la page de remerciement d'Ikiform au lieu de la vôtre | `_redirect` est ignoré sauf si son domaine figure dans **Allowed domains** et qu'il s'agit d'une URL `https:`. Ajoutez le domaine, ou définissez plutôt **Redirect after submit** dans les réglages du formulaire. |
| `403 origin_not_allowed`, ou tous les envois finissent en spam | Le domaine de la page n'est pas dans les **Allowed domains** du formulaire. Ajoutez-le, plus `localhost` pour les tests en local. Les sous-domaines d'un domaine listé sont autorisés. |

## Questions

### Un site statique S3 peut-il traiter les soumissions de formulaire ?

Non. Les website endpoints S3 ne prennent en charge que les requêtes GET et HEAD : un POST reçoit donc 405 MethodNotAllowed. Faites pointer le formulaire vers un backend de formulaires, ou construisez une API avec Lambda.

### Ai-je besoin de CloudFront pour que le formulaire de contact fonctionne ?

Non. Le formulaire envoie aussi à Ikiform depuis une page http. CloudFront vous donne le https, ce qui permet à Ikiform de suivre un _redirect vers votre propre page de remerciement.

### Pourquoi pas API Gateway, Lambda et SES ?

Cela fonctionne et garde tout chez AWS, mais vous construisez vous-même la validation, le filtrage du spam, le stockage et les nouvelles tentatives, et SES exige un expéditeur vérifié. Un backend de formulaires demande moins de maintenance pour un formulaire de contact.

### CloudFront mettra-t-il en cache l'ancien formulaire après une modification ?

Possiblement, jusqu'à l'expiration de la copie en cache. Invalidez contact.html après chaque modification, ou téléversez le HTML avec un max-age Cache-Control court pour que les nouveaux formulaires soient en ligne rapidement.

### Ikiform est-il gratuit ?

Non, il n'y a pas d'offre gratuite. Les tests sont gratuits : vous pouvez envoyer 50 soumissions de test par mois depuis localhost avant de payer. Pour passer en production, Pro commence à 6 $/mois pour 500 soumissions, ou vous pouvez payer une seule fois 10 000 soumissions pour 49 $ ou 50 000 soumissions pour 149 $, avec des crédits qui n'expirent jamais.

## Autres guides

- [Formulaire de contact sur un site statique](https://ikiform.com/fr/guides/contact-form-static-site.md): Ajoutez un formulaire de contact fonctionnel à un site statique sans serveur : où va le POST, le spam, les réponses par e-mail, et du code pour chaque hébergeur.
- [Cloudflare Pages](https://ikiform.com/fr/guides/contact-form-static-site/cloudflare-pages.md): Un formulaire de contact sur Cloudflare Pages sans écrire de Function : envoyez à un backend, définissez les en-têtes dans _headers, utilisez vos clés Turnstile.
- [GitHub Pages](https://ikiform.com/fr/guides/contact-form-static-site/github-pages.md): GitHub Pages n'exécute pas de code serveur, un POST de formulaire reçoit donc 405 Not Allowed ; envoyez vers un backend et réglez bien les redirections.
- [Vercel](https://ikiform.com/fr/guides/contact-form-static-site/vercel.md): Une page statique sur Vercel répond à un POST de formulaire par 405 Method Not Allowed ; voici pourquoi, et comment envoyer le formulaire à un backend.
- [Netlify](https://ikiform.com/fr/guides/contact-form-static-site/netlify.md): Un formulaire de contact sur Netlify sans Netlify Forms : pas de détection au build, envois JSON depuis React, et un formulaire à part pour les deploy previews.
- [Site portfolio](https://ikiform.com/fr/guides/contact-form-static-site/portfolio-website.md): Un formulaire de contact de portfolio qui pose les questions d'un premier appel : projet, budget, délai et un lien, sans serveur et avec réponses depuis votre boîte.
