# Ein Kontaktformular in eine GitHub-Pages-Site einbauen

> GitHub Pages kann keinen Servercode ausführen, also bekommt ein Formular-POST 405 Not Allowed; sende an ein Formular-Backend und setze Weiterleitungen für Projekt-Sites richtig.

Veröffentlicht am 2026-10-25 · https://ikiform.com/de/guides/contact-form-static-site/github-pages

GitHub Pages liefert nur statische Dateien aus, daher bekommt ein Formular, das an deine eigene Site sendet, `405 Not Allowed`, und die Nachricht geht verloren. Setze die `action` des Formulars auf einen Ikiform-Endpunkt, füge `username.github.io` und eine eventuelle eigene Domain zu **Allowed domains** hinzu und leite auf eine Dankeseite weiter, die den Pfad deiner Projekt-Site enthält. In deinem Repository und deinen Pages-Einstellungen ändert sich nichts, und kein Geheimnis landet im öffentlichen Repo.

## Was bei GitHub Pages anders ist

GitHub Pages veröffentlicht, was dein Repository oder dein Actions-Workflow baut, und sonst nichts. Jekyll läuft zur Build-Zeit, falls du es nutzt, danach ist das Ergebnis eine Sammlung von Dateien. Es gibt keinen Request-Handler, daher laufen PHPs `mail()`, ein Node-Skript oder ein Python-CGI-Formular nicht, egal was du committest.

Du kannst den Fehler im Terminal sehen. Ein POST an eine beliebige Seite einer Pages-Site bekommt das hier:

`Terminal`:

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

`Antwort`:

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

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

Vier weitere Dinge unterscheiden Pages von anderen statischen Hosts, und jedes betrifft das Kontaktformular:

| Pages-Eigenschaft | Was das für das Formular bedeutet |
| --- | --- |
| Projekt-Sites liegen unter einem Pfad, `username.github.io/repo/` | Eine Danke-URL `/thanks.html` zeigt auf die User-Site, nicht auf dein Projekt. Jede URL braucht den Teil `/repo/` |
| Keine Einstellung für eigene Response-Header | Eine Content-Security-Policy kann nur aus einem `<meta>`-Tag in der Seite kommen |
| Das Repository ist oft öffentlich | Alles darin ist öffentlich. Die Formular-ID kann dort stehen; ein geheimer API-Schlüssel oder ein E-Mail-Passwort niemals |
| GitHub sagt, Pages-Sites sollten nicht für sensible Vorgänge wie das Senden von Passwörtern oder Kreditkartennummern genutzt werden | Lass das Kontaktformular ein Kontaktformular sein. Sammle darüber keine Kartendaten oder Kontopasswörter |

Diagramm: Was GitHub Pages ausführt und wohin ein Kontaktformular-Post gehen muss

1. Du pushst auf den Branch, aus dem Pages veröffentlicht.
2. Jekyll oder dein Actions-Workflow baut die Site einmal.
3. Pages liefert das Ergebnis als statische Dateien auf github.io oder deiner eigenen Domain aus.
4. Ein Besucher sendet das Kontaktformular ab. Zeigt seine action auf deine eigene Site, antwortet Pages mit 405 Not Allowed.
5. Ist die action auf deinen Ikiform-Endpunkt gesetzt, speichert Ikiform die Nachricht und schickt dir eine E-Mail.
6. Ikiform leitet den Browser auf die Dankeseite weiter, die Pages wie jede andere Datei ausliefert.

Code läuft bei GitHub einmal pro Push. Wenn ein Besucher auf Senden klickt, läuft nichts von dir, deshalb muss der Post github.io verlassen.

## Das Formular

Für eine handgeschriebene Site leg `contact.html` neben `index.html`. Diese hier ist für eine Projekt-Site unter `ada.github.io/notebook`, daher enthält die Weiterleitung `/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>
```

- Die `<meta>`-Content-Security-Policy ist optional. Behalte sie, wenn du eine hast, und sorg dafür, dass `form-action` und `connect-src` `https://ikiform.com` enthalten. Pages kann den Header nicht für dich senden.
- Das Select `about` sagt dir, warum jemand geschrieben hat, bevor du die Nachricht öffnest. Ändere die Optionen in das, worüber dir Leute tatsächlich schreiben.
- Das versteckte Eingabefeld `page` hält fest, auf welcher Seite das Formular war, was nützlich ist, wenn dasselbe Formular auf mehreren Doku-Seiten steht.
- Behalte `email` als Feldnamen. Benachrichtigungs-E-Mails nutzen es als Reply-To-Adresse.

Wenn dasselbe HTML unter mehreren Pfaden deployt wird oder du nicht sicher bist, wie der endgültige Pfad lautet, bau die Weiterleitung im Browser aus der eigenen Adresse der Seite. Setze das hinter das Formular:

`contact.html`:

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

Du nutzt Jekyll? Schreib die URL gar nicht fest hinein. Die [Jekyll-Anleitung](https://ikiform.com/de/docs/guides/jekyll.md) hat ein Include, das sie mit `absolute_url` baut, was für Projekt-Sites deine `baseurl` ergänzt. Du baust mit Astro, Vite oder Hugo über einen Actions-Workflow? Setze den Basispfad des Frameworks auf `/repo/`, damit die Assets des Formulars laden, und nutze für das Formular selbst die Anleitung zu [Hugo](https://ikiform.com/de/docs/guides/hugo.md) oder zu deinem Framework.

## Erlaubte Domains auf github.io

Füge `ada.github.io` mit deinem eigenen Benutzernamen hinzu. Das deckt deine User-Site und jede Projekt-Site ab, weil Projekt-Sites denselben Host teilen. Füge auch deine eigene Domain hinzu, falls du eine nutzt; `example.com` deckt auch `www.example.com` ab.

Füge niemals `github.io` allein hinzu. Jede Pages-Site würde passen, auch Kopien deines Formulars auf den Sites anderer Leute. Mit gesetzten erlaubten Domains wird einem `_redirect` auf `https://ada.github.io/notebook/thanks.html` gefolgt; ohne sie ignoriert Ikiform ihn und zeigt seine gehostete Dankeseite.

> Aktiviere **Enforce HTTPS** in den Pages-Einstellungen des Repositorys. Ikiform folgt nur `_redirect`-Werten, die mit `https:` beginnen, und eine eigene Domain ohne Zertifikat liefert vorerst `http:`-Seiten aus.

## Einen mailto:-Link ersetzen

Viele Pages-Sites beginnen mit einem `mailto:`-Link im Footer. Ersetzt du ihn durch das Formular, können neue Scraper deine Adresse nicht mehr von der Seite lesen, und Besucher ohne eingerichtete Mail-App erreichen dich endlich. Zwei Dinge solltest du wissen, bevor du ihn löschst:

- Die Adresse bleibt in der Historie deines Repositorys und in jedem Fork oder Archiv der alten Seite. Das Formular hilft ab jetzt; es macht eine Adresse, die jahrelang öffentlich war, nicht wieder privat.
- Antworten kommen aus deinem eigenen Postfach. Benachrichtigungs-E-Mails setzen den Absender als Reply-To-Adresse, daher funktioniert **Reply** so wie vorher der `mailto:`-Link, nur von der anderen Seite.

Ikiform schickt dem Besucher nie eine E-Mail, also schreib auf die Dankeseite, wann er mit einer Antwort rechnen kann. Wenn du mehr Nachrichten bekommst, als du per E-Mail beantworten kannst, kann ein Webhook jede davon stattdessen in [Slack](https://ikiform.com/blog/form-submissions-to-slack.md) oder [Discord](https://ikiform.com/blog/form-submissions-to-discord.md) ablegen.

## Prüfen, ob es funktioniert

Führe das auf der Live-Adresse unter `github.io` aus. Pages hat keine Preview-Deployments, also teste zuerst lokal mit einem lokalen Server.

1. Füge `localhost` und `username.github.io` unter **Allowed domains** hinzu, plus deine eigene Domain, falls du eine hast.
2. Committe `contact.html` und `thanks.html`, warte im Tab **Actions** des Repositorys, bis das Pages-Deployment fertig ist, und öffne die Live-Seite.
3. Sende das Formular ab. Du solltest auf deiner eigenen `thanks.html` landen, mit dem Projektpfad in der Adresszeile.
4. Öffne **Submissions** im Dashboard. Die neue Einsendung ist da, mit jedem Feld, das du gesendet hast.
5. Prüfe das Postfach jedes Benachrichtigungsempfängers. Jeder bekommt eine E-Mail mit den Feldern, und **Reply** geht an den Absender, wenn das Formular ein `email`-Feld hat.
6. Nichts angekommen? Stell den Statusfilter im Dashboard auf **Spam**. Spam bekommt dieselbe Erfolgsantwort wie eine echte Einsendung.

## Stolperfallen

| Problem | Was zu tun ist |
| --- | --- |
| `405 Not Allowed` nach dem Klick auf Senden | Das deployte Formular sendet noch an deine eigene Site. Sieh dir den Quelltext der Seite auf github.io an und prüfe die `action`; ein alter gecachter Build kann noch ein paar Minuten live sein. |
| Die Dankeseite von Ikiform statt deiner | Dem `_redirect`-Wert fehlt der Repository-Pfad, er ist `http:`, oder das Formular hat keine erlaubten Domains. Füge `username.github.io` hinzu und nutze die vollständige `https:`-URL. |
| `403 origin_not_allowed`, oder jeder Post landet im Spam | Die Domain der Seite steht nicht unter **Allowed domains** des Formulars. Füge sie hinzu, plus `localhost` für lokale Tests. Subdomains einer eingetragenen Domain sind erlaubt. |
| Formular-Posts funktionieren lokal, aber die Konsole zeigt auf github.io einen CSP-Fehler | Einer `<meta>`-Content-Security-Policy in deinem Layout fehlt `https://ikiform.com` in `form-action` oder `connect-src`. |

## Fragen

### Kann GitHub Pages Formulareinsendungen verarbeiten?

Nein. GitHub Pages liefert statische Dateien aus und führt keinen Code aus, wenn ein Besucher ein Formular absendet, daher bekommt ein POST an eine Pages-URL 405 Not Allowed. Richte die action des Formulars stattdessen auf ein Formular-Backend aus.

### Ist es sicher, den Formular-Endpunkt in ein öffentliches Repository zu committen?

Ja. Die Formular-ID landet ohnehin in deinem öffentlichen HTML. Schütze das Formular mit erlaubten Domains und den Spamprüfungen und committe niemals einen geheimen API-Schlüssel, weil eine statische Site keinen sicheren Ort dafür hat.

### Warum geht meine Danke-Weiterleitung auf einer Projekt-Site auf die falsche Seite?

Ein Pfad wie /thanks.html zeigt auf die Wurzel von username.github.io, nicht auf dein Projekt. Nutze die vollständige URL mit dem Repository-Pfad oder bau sie im Browser aus document.baseURI.

### Funktioniert das Formular noch, wenn ich GitHub Pages eine eigene Domain hinzufüge?

Ja. Das Formular sendet an Ikiform, egal welche Domain die Seite ausliefert. Füge die eigene Domain unter Allowed domains neben username.github.io hinzu und stell jeden _redirect-Wert auf die eigene Domain um, sobald HTTPS erzwungen wird.

### Ist Ikiform kostenlos?

Nein, es gibt keinen kostenlosen Tarif. Testen ist kostenlos: Du kannst 50 Testeinsendungen pro Monat von localhost senden, bevor du zahlst. Für den Livebetrieb startet Pro bei $6/Monat für 500 Einsendungen, oder du zahlst einmalig 10.000 Einsendungen für $49 oder 50.000 Einsendungen für $149, mit Guthaben, das nie verfällt.

## Weitere Anleitungen

- [Kontaktformular auf einer statischen Site](https://ikiform.com/de/guides/contact-form-static-site.md): Bau ein funktionierendes Kontaktformular in eine statische Site ohne Server ein: wohin der POST geht, Spam, Antworten per E-Mail und Code für jeden Host und jedes Framework.
- [Netlify](https://ikiform.com/de/guides/contact-form-static-site/netlify.md): Betreib ein Kontaktformular auf einer Netlify-Site ohne Netlify Forms: keine Erkennung beim Build, JSON-Posts aus React und ein eigenes Formular für Deploy Previews.
- [Cloudflare Pages](https://ikiform.com/de/guides/contact-form-static-site/cloudflare-pages.md): Bau ein Kontaktformular in Cloudflare Pages ein, ohne eine Function zu schreiben: an ein Formular-Backend senden, Header in _headers setzen und eigene Turnstile-Schlüssel nutzen.
- [Portfolio-Website](https://ikiform.com/de/guides/contact-form-static-site/portfolio-website.md): Ein Portfolio-Kontaktformular mit den Fragen, die du im ersten Gespräch stellen würdest: Projekt, Budget, Zeitplan und ein Link, ohne Server und mit Antworten aus deinem Postfach.
- [Vercel](https://ikiform.com/de/guides/contact-form-static-site/vercel.md): Eine statische Seite auf Vercel beantwortet einen Formular-POST mit 405 Method Not Allowed; hier steht, warum, und wie du das Formular stattdessen an ein Backend sendest.
- [Amazon S3](https://ikiform.com/de/guides/contact-form-static-site/aws-s3.md): S3-Website-Endpunkte akzeptieren nur GET und HEAD über einfaches HTTP, also sende das Kontaktformular an ein Formular-Backend und setze Weiterleitungen mit CloudFront richtig.
