# Ajouter un formulaire de contact à un site GitHub Pages

> 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.

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

GitHub Pages ne sert que des fichiers statiques : un formulaire qui envoie vers votre propre site reçoit `405 Not Allowed` et le message est perdu. Faites pointer l'`action` du formulaire vers un endpoint Ikiform, ajoutez `username.github.io` et votre éventuel domaine personnalisé aux **Allowed domains**, et redirigez vers une page de remerciement qui inclut le chemin de votre site de projet. Rien ne change dans votre dépôt ni dans les réglages de Pages, et aucun secret ne finit dans le dépôt public.

## Ce qui change sur GitHub Pages

GitHub Pages publie ce que construit votre dépôt ou votre workflow Actions, et rien d'autre. Jekyll s'exécute au build si vous l'utilisez, puis le résultat n'est que des fichiers. Il n'y a pas de gestionnaire de requêtes : `mail()` de PHP, un script Node ou un formulaire CGI en Python ne s'exécuteront pas, quoi que vous commitiez.

Vous pouvez constater l'échec depuis un terminal. Un POST vers n'importe quelle page d'un site Pages reçoit ceci :

`Terminal`:

```bash
curl -i -X POST -d "message=hello" https://ada.github.io/notebook/contact.html
```

`Réponse`:

```http
HTTP/2 405
server: Varnish
content-length: 131

<html>
<head><title>405 Not Allowed</title></head>
```

Quatre autres points distinguent Pages des autres hébergeurs statiques, et chacun touche au formulaire de contact :

| Particularité de Pages | Conséquence pour le formulaire |
| --- | --- |
| Les sites de projet vivent sous un chemin, `username.github.io/repo/` | Une URL de remerciement `/thanks.html` pointe vers le site utilisateur, pas vers votre projet. Chaque URL a besoin de la partie `/repo/` |
| Aucun réglage pour les en-têtes de réponse personnalisés | Une Content-Security-Policy ne peut venir que d'une balise `<meta>` dans la page |
| Le dépôt est souvent public | Tout ce qu'il contient est public. L'id du formulaire peut y être ; une clé d'API secrète ou un mot de passe de messagerie, jamais |
| GitHub indique que les sites Pages ne doivent pas servir à des transactions sensibles comme l'envoi de mots de passe ou de numéros de carte bancaire | Limitez le formulaire de contact à un formulaire de contact. N'y collectez ni coordonnées bancaires ni mots de passe de compte |

Schéma : Ce qu'exécute GitHub Pages, et où doit aller l'envoi d'un formulaire de contact

1. Vous poussez sur la branche que Pages publie.
2. Jekyll ou votre workflow Actions construit le site une fois.
3. Pages sert le résultat sous forme de fichiers statiques sur github.io ou votre domaine personnalisé.
4. Un visiteur envoie le formulaire de contact. Si son action pointe vers votre propre site, Pages répond 405 Not Allowed.
5. Avec l'action réglée sur votre endpoint Ikiform, Ikiform stocke le message et vous l'envoie par e-mail.
6. Ikiform redirige le navigateur vers la page de remerciement, que Pages sert comme n'importe quel fichier.

Le code s'exécute chez GitHub une fois par push. Rien de chez vous ne s'exécute quand un visiteur clique sur Envoyer : c'est pourquoi l'envoi doit quitter github.io.

## Le formulaire

Pour un site écrit à la main, ajoutez `contact.html` à côté d'`index.html`. Celui-ci est pour un site de projet à `ada.github.io/notebook`, la redirection inclut donc `/notebook/` :

`contact.html`:

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta
      http-equiv="Content-Security-Policy"
      content="default-src 'self'; form-action 'self' https://ikiform.com; connect-src 'self' https://ikiform.com"
    />
    <title>Contact</title>
  </head>
  <body>
    <h1>Get in touch</h1>
    <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">Email</label>
      <input id="email" name="email" type="email" autocomplete="email" required />

      <label for="about">What is it about?</label>
      <select id="about" name="about">
        <option value="question">A question about the project</option>
        <option value="hire">Work together</option>
        <option value="other">Something else</option>
      </select>

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

      <input type="hidden" name="page" value="docs-home" />
      <input type="hidden" name="_redirect" value="https://ada.github.io/notebook/thanks.html" />
      <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
      <button type="submit">Send</button>
    </form>
  </body>
</html>
```

- La Content-Security-Policy en `<meta>` est facultative. Gardez-la si vous en avez une, et vérifiez que `form-action` et `connect-src` incluent `https://ikiform.com`. Pages ne peut pas envoyer l'en-tête à votre place.
- Le select `about` vous dit pourquoi quelqu'un a écrit avant même d'ouvrir le message. Adaptez les options à ce pour quoi les gens vous écrivent réellement.
- L'input masqué `page` enregistre la page où se trouvait le formulaire, ce qui est utile quand le même formulaire figure sur plusieurs pages de documentation.
- Gardez `email` comme nom de champ. Les e-mails de notification l'utilisent comme adresse de réponse.

Si le même HTML est déployé sous plusieurs chemins, ou si vous n'êtes pas sûr du chemin final, construisez la redirection dans le navigateur à partir de l'adresse de la page. Placez ceci après le formulaire :

`contact.html`:

```html
<script>
  document.querySelectorAll('input[name="_redirect"]').forEach((input) => {
    input.value = new URL("thanks.html", document.baseURI).href;
  });
</script>
```

Vous utilisez Jekyll ? Ne codez pas du tout l'URL en dur. Le [guide Jekyll](https://ikiform.com/fr/docs/guides/jekyll.md) propose un include qui la construit avec `absolute_url`, lequel ajoute votre `baseurl` pour les sites de projet. Vous construisez avec Astro, Vite ou Hugo via un workflow Actions ? Réglez le chemin de base du framework sur `/repo/` pour que les ressources du formulaire se chargent, et utilisez le guide [Hugo](https://ikiform.com/fr/docs/guides/hugo.md) ou celui du framework pour le formulaire lui-même.

## Domaines autorisés sur github.io

Ajoutez `ada.github.io`, avec votre propre nom d'utilisateur. Cela couvre votre site utilisateur et tous vos sites de projet, car ils partagent le même hôte. Ajoutez aussi votre domaine personnalisé si vous en utilisez un ; `example.com` couvre aussi `www.example.com`.

N'ajoutez jamais `github.io` seul. Tous les sites Pages correspondraient, y compris des copies de votre formulaire sur les sites d'autres personnes. Avec des domaines autorisés définis, un `_redirect` vers `https://ada.github.io/notebook/thanks.html` est suivi ; sans eux, Ikiform l'ignore et affiche sa page de remerciement hébergée.

> Activez **Enforce HTTPS** dans les réglages Pages du dépôt. Ikiform ne suit que les valeurs `_redirect` qui commencent par `https:`, et un domaine personnalisé encore sans certificat sert des pages `http:`.

## Remplacer un lien mailto :

Beaucoup de sites Pages démarrent avec un lien `mailto:` dans le pied de page. Le remplacer par le formulaire empêche les nouveaux scrapers de lire votre adresse dans la page, et les visiteurs sans appli de messagerie configurée peuvent enfin vous joindre. Deux choses à savoir avant de le supprimer :

- L'adresse reste dans l'historique de votre dépôt, et dans tout fork ou archive de l'ancienne page. Le formulaire aide à partir de maintenant ; il ne rend pas privée une adresse publique depuis des années.
- Les réponses partent de votre propre boîte. Les e-mails de notification définissent l'expéditeur comme adresse de réponse : cliquer sur **Reply** fonctionne donc comme le lien `mailto:`, mais dans l'autre sens.

Ikiform n'envoie jamais d'e-mail au visiteur : indiquez donc sur la page de remerciement quand il peut attendre une réponse. Si vous recevez plus de messages que vous ne pouvez en traiter par e-mail, un webhook peut déposer chacun dans [Slack](https://ikiform.com/blog/form-submissions-to-slack.md) ou [Discord](https://ikiform.com/blog/form-submissions-to-discord.md).

## Vérifiez que tout fonctionne

Faites ceci sur l'adresse `github.io` en ligne. Pages n'a pas de déploiements de préproduction : testez donc d'abord en local avec un serveur local.

1. Ajoutez `localhost` et `username.github.io` dans **Allowed domains**, plus votre domaine personnalisé si vous en avez un.
2. Commitez `contact.html` et `thanks.html`, attendez la fin du déploiement Pages dans l'onglet **Actions** du dépôt, puis ouvrez la page en ligne.
3. Envoyez le formulaire. Vous devez arriver sur votre propre `thanks.html`, avec le chemin du projet dans la barre d'adresse.
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 Not Allowed` après avoir cliqué sur Envoyer | Le formulaire déployé envoie toujours vers votre propre site. Affichez le code source de la page sur github.io et vérifiez l'`action` ; un ancien build en cache peut rester en ligne quelques minutes. |
| La page de remerciement d'Ikiform au lieu de la vôtre | La valeur de `_redirect` n'a pas le chemin du dépôt, est en `http:`, ou le formulaire n'a pas de domaines autorisés. Ajoutez `username.github.io` et utilisez l'URL `https:` complète. |
| `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. |
| Les envois fonctionnent en local mais la console affiche une erreur CSP sur github.io | Une Content-Security-Policy en `<meta>` dans votre layout n'inclut pas `https://ikiform.com` dans `form-action` ou `connect-src`. |

## Questions

### GitHub Pages peut-il traiter les soumissions de formulaire ?

Non. GitHub Pages sert des fichiers statiques et n'exécute aucun code quand un visiteur envoie un formulaire : un POST vers une URL Pages reçoit donc 405 Not Allowed. Faites plutôt pointer l'action du formulaire vers un backend de formulaires.

### Est-il sûr de commiter l'endpoint du formulaire dans un dépôt public ?

Oui. L'id du formulaire finit de toute façon dans votre HTML public. Protégez le formulaire avec les domaines autorisés et les vérifications anti-spam, et ne commitez jamais de clé d'API secrète, car un site statique n'a aucun endroit sûr où la garder.

### Pourquoi ma redirection de remerciement mène-t-elle à la mauvaise page sur un site de projet ?

Un chemin comme /thanks.html pointe vers la racine de username.github.io, pas vers votre projet. Utilisez l'URL complète avec le chemin du dépôt, ou construisez-la à partir de document.baseURI dans le navigateur.

### Le formulaire fonctionne-t-il toujours après l'ajout d'un domaine personnalisé à GitHub Pages ?

Oui. Le formulaire envoie à Ikiform quel que soit le domaine qui sert la page. Ajoutez le domaine personnalisé dans Allowed domains à côté de username.github.io, et mettez à jour toute valeur _redirect pour utiliser le domaine personnalisé une fois HTTPS imposé.

### 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.
- [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.
- [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.
- [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.
- [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.
- [Amazon S3](https://ikiform.com/fr/guides/contact-form-static-site/aws-s3.md): 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.
