Kontaktformulare sammeln personenbezogene Daten und müssen DSGVO-konform sein. Dieser Artikel erklärt die rechtlichen Anforderungen und zeigt die technische Umsetzung.

DSGVO-Grundlagen

Was die DSGVO fordert

Grundsätze für Kontaktformulare:
- Datenminimierung (nur nötige Felder)
- Zweckbindung (nur für Kontaktanfrage)
- Transparenz (Datenschutzhinweis)
- Einwilligung (Checkbox vor Absenden)
- Speicherbegrenzung (Löschfristen)
- Sicherheit (Verschlüsselung)

Rechtsgrundlage

| Rechtsgrundlage | Anwendung | |-----------------|-----------| | Art. 6 (1) a | Einwilligung (Newsletter) | | Art. 6 (1) b | Vertragsanbahnung (Anfrage) | | Art. 6 (1) f | Berechtigtes Interesse |

Für einfache Kontaktanfragen reicht meist Art. 6 (1) b (vorvertragliche Maßnahmen).

Pflichtfelder minimieren

Nur notwendige Daten

<!-- GUT: Minimal -->
<form>
    <input type="email" name="email" required>
    <textarea name="nachricht" required></textarea>
    <button type="submit">Absenden</button>
</form>

<!-- SCHLECHT: Zu viele Daten -->
<form>
    <input name="vorname" required>
    <input name="nachname" required>
    <input name="email" required>
    <input name="telefon" required>
    <input name="firma" required>
    <input name="position" required>
    <input name="adresse" required>
    <input name="geburtsdatum" required>
    <textarea name="nachricht" required></textarea>
</form>

Empfohlene Felder

Minimal:
- E-Mail-Adresse (Pflicht)
- Nachricht (Pflicht)

Optional (freiwillig):
- Name (für persönliche Anrede)
- Telefon (für Rückruf)

Datenschutzhinweis

Pflichtangaben

<form>
    <!-- Formularfelder -->

    <div class="datenschutzhinweis">
        <p>
            Ihre Angaben werden zur Bearbeitung Ihrer Anfrage verwendet.
            Weitere Informationen finden Sie in unserer
            <a href="/datenschutz" target="_blank">Datenschutzerklärung</a>.
        </p>
    </div>

    <label>
        <input type="checkbox" name="datenschutz" required>
        Ich habe die <a href="/datenschutz" target="_blank">Datenschutzerklärung</a>
        gelesen und stimme der Verarbeitung meiner Daten zu.
    </label>

    <button type="submit">Absenden</button>
</form>

Datenschutzerklärung ergänzen

## Kontaktformular

Wenn Sie unser Kontaktformular nutzen, werden folgende Daten verarbeitet:

**Erhobene Daten:**
- E-Mail-Adresse
- Ihre Nachricht
- Optional: Name, Telefonnummer

**Zweck der Verarbeitung:**
Bearbeitung Ihrer Anfrage und Kontaktaufnahme

**Rechtsgrundlage:**
Art. 6 Abs. 1 lit. b DSGVO (vorvertragliche Maßnahmen)

**Speicherdauer:**
Ihre Daten werden nach Abschluss der Bearbeitung und Ablauf
gesetzlicher Aufbewahrungsfristen gelöscht, spätestens nach 3 Jahren.

**Empfänger:**
Ihre Daten werden nicht an Dritte weitergegeben.

Einwilligung dokumentieren

Was gespeichert werden sollte

// PHP-Beispiel: Einwilligung dokumentieren
$consent_log = [
    'timestamp' => date('Y-m-d H:i:s'),
    'ip_address' => $_SERVER['REMOTE_ADDR'],
    'user_agent' => $_SERVER['HTTP_USER_AGENT'],
    'consent_text' => 'Ich habe die Datenschutzerklärung gelesen...',
    'consent_version' => '1.0',
    'form_data' => [
        'email' => $email,
        'message' => substr($message, 0, 100) . '...'
    ]
];

// In Datenbank oder Log speichern
file_put_contents(
    '/var/log/consent.log',
    json_encode($consent_log) . "\n",
    FILE_APPEND
);

Datenbank-Schema

CREATE TABLE contact_requests (
    id INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(255) NOT NULL,
    name VARCHAR(255),
    message TEXT NOT NULL,
    consent_given TINYINT(1) NOT NULL DEFAULT 1,
    consent_timestamp DATETIME NOT NULL,
    consent_ip VARCHAR(45),
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    processed_at DATETIME,
    deleted_at DATETIME
);

Technische Umsetzung

HTML-Formular (vollständig)

<form action="/kontakt" method="POST" id="contact-form">
    <!-- Honeypot gegen Spam -->
    <input type="text" name="website" style="display:none" tabindex="-1" autocomplete="off">

    <div class="form-group">
        <label for="email">E-Mail-Adresse *</label>
        <input type="email" id="email" name="email" required
               autocomplete="email">
    </div>

    <div class="form-group">
        <label for="name">Name (optional)</label>
        <input type="text" id="name" name="name"
               autocomplete="name">
    </div>

    <div class="form-group">
        <label for="message">Ihre Nachricht *</label>
        <textarea id="message" name="message" rows="5" required
                  minlength="10" maxlength="5000"></textarea>
    </div>

    <div class="form-group privacy-notice">
        <p>
            Ihre Angaben werden ausschließlich zur Bearbeitung Ihrer
            Anfrage verwendet. Details finden Sie in unserer
            <a href="/datenschutz" target="_blank" rel="noopener">
                Datenschutzerklärung</a>.
        </p>
    </div>

    <div class="form-group">
        <label class="checkbox-label">
            <input type="checkbox" name="privacy_accepted" required>
            <span>Ich habe die
                <a href="/datenschutz" target="_blank" rel="noopener">
                    Datenschutzerklärung</a>
                gelesen und stimme der Verarbeitung meiner Daten zu. *
            </span>
        </label>
    </div>

    <button type="submit">Nachricht senden</button>

    <p class="required-hint">* Pflichtfelder</p>
</form>

PHP-Backend

<?php
// kontakt.php

// Honeypot-Check
if (!empty($_POST['website'])) {
    http_response_code(400);
    exit('Spam detected');
}

// Einwilligung prüfen
if (empty($_POST['privacy_accepted'])) {
    http_response_code(400);
    exit('Datenschutz-Einwilligung erforderlich');
}

// Daten validieren
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
$name = htmlspecialchars($_POST['name'] ?? '', ENT_QUOTES, 'UTF-8');
$message = htmlspecialchars($_POST['message'], ENT_QUOTES, 'UTF-8');

if (!$email || strlen($message) < 10) {
    http_response_code(400);
    exit('Ungültige Eingabe');
}

// In Datenbank speichern
$pdo = new PDO('mysql:host=localhost;dbname=website', 'user', 'pass');
$stmt = $pdo->prepare("
    INSERT INTO contact_requests
    (email, name, message, consent_given, consent_timestamp, consent_ip)
    VALUES (?, ?, ?, 1, NOW(), ?)
");
$stmt->execute([$email, $name, $message, $_SERVER['REMOTE_ADDR']]);

// E-Mail senden
$to = 'kontakt@example.com';
$subject = 'Neue Kontaktanfrage';
$body = "Von: $name <$email>\n\n$message";
$headers = [
    'From' => 'noreply@example.com',
    'Reply-To' => $email,
    'X-Mailer' => 'PHP/' . phpversion()
];

mail($to, $subject, $body, $headers);

// Bestätigung
header('Location: /kontakt/danke');
exit;

WordPress (ohne Plugin)

// functions.php

function custom_contact_form_shortcode() {
    ob_start();
    ?>
    <form action="" method="POST" class="contact-form">
        <?php wp_nonce_field('contact_form', 'contact_nonce'); ?>

        <p>
            <label>E-Mail *</label>
            <input type="email" name="email" required>
        </p>

        <p>
            <label>Nachricht *</label>
            <textarea name="message" required></textarea>
        </p>

        <p>
            <label>
                <input type="checkbox" name="privacy" required>
                Ich stimme der <a href="/datenschutz">Datenschutzerklärung</a> zu.
            </label>
        </p>

        <button type="submit" name="contact_submit">Absenden</button>
    </form>
    <?php
    return ob_get_clean();
}
add_shortcode('kontaktformular', 'custom_contact_form_shortcode');

function process_contact_form() {
    if (!isset($_POST['contact_submit'])) return;

    if (!wp_verify_nonce($_POST['contact_nonce'], 'contact_form')) {
        wp_die('Sicherheitsfehler');
    }

    if (empty($_POST['privacy'])) {
        wp_die('Bitte Datenschutzerklärung akzeptieren');
    }

    $email = sanitize_email($_POST['email']);
    $message = sanitize_textarea_field($_POST['message']);

    wp_mail(
        get_option('admin_email'),
        'Kontaktanfrage',
        "Von: $email\n\n$message"
    );

    wp_redirect(home_url('/danke'));
    exit;
}
add_action('init', 'process_contact_form');

Speicherfristen

Löschkonzept

// Cronjob: Alte Anfragen löschen
// Täglich ausführen

$pdo = new PDO('mysql:host=localhost;dbname=website', 'user', 'pass');

// Nach 3 Jahren löschen (oder nach Bearbeitung + 6 Monate)
$stmt = $pdo->prepare("
    UPDATE contact_requests
    SET deleted_at = NOW(),
        email = 'gelöscht',
        name = NULL,
        message = 'Daten gemäß DSGVO gelöscht'
    WHERE deleted_at IS NULL
    AND (
        created_at < DATE_SUB(NOW(), INTERVAL 3 YEAR)
        OR (processed_at IS NOT NULL
            AND processed_at < DATE_SUB(NOW(), INTERVAL 6 MONTH))
    )
");
$stmt->execute();

echo "Gelöschte Einträge: " . $stmt->rowCount();

Dokumentation

Löschkonzept Kontaktformular:
- Unbearbeitete Anfragen: max. 3 Monate
- Bearbeitete Anfragen: 6 Monate nach Abschluss
- Maximale Speicherdauer: 3 Jahre (Verjährungsfrist)
- Automatische Löschung via Cronjob

Spam-Schutz DSGVO-konform

Honeypot (empfohlen)

<!-- Verstecktes Feld - Bots füllen es aus, Menschen nicht -->
<input type="text" name="fax" style="position:absolute;left:-9999px"
       tabindex="-1" autocomplete="off">
if (!empty($_POST['fax'])) {
    // Spam - nicht verarbeiten
    exit;
}

Zeitbasierte Prüfung

// Token mit Timestamp
session_start();
$_SESSION['form_token'] = time();

// Beim Absenden prüfen
$token_age = time() - $_SESSION['form_token'];
if ($token_age < 3 || $token_age > 3600) {
    // Zu schnell (Bot) oder zu langsam (abgelaufene Session)
    exit('Ungültige Anfrage');
}

reCAPTCHA (mit Vorsicht)

Beachten bei reCAPTCHA:
- Datentransfer in die USA
- In Datenschutzerklärung erwähnen
- Cookie-Consent erforderlich
- Alternative: hCaptcha (EU-Server)

Auskunft und Löschung

Auskunftsrecht (Art. 15)

// Auskunft per E-Mail anfordern
function get_user_data($email) {
    $pdo = new PDO('mysql:host=localhost;dbname=website', 'user', 'pass');

    $stmt = $pdo->prepare("
        SELECT email, name, message, created_at, processed_at
        FROM contact_requests
        WHERE email = ? AND deleted_at IS NULL
    ");
    $stmt->execute([$email]);

    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

Löschrecht (Art. 17)

// Daten auf Anfrage löschen
function delete_user_data($email) {
    $pdo = new PDO('mysql:host=localhost;dbname=website', 'user', 'pass');

    $stmt = $pdo->prepare("
        UPDATE contact_requests
        SET deleted_at = NOW(),
            email = 'gelöscht',
            name = NULL,
            message = 'Auf Anfrage gelöscht (Art. 17 DSGVO)'
        WHERE email = ? AND deleted_at IS NULL
    ");
    $stmt->execute([$email]);

    return $stmt->rowCount();
}

Checkliste

□ Nur notwendige Felder (E-Mail, Nachricht)
□ Datenschutzhinweis am Formular
□ Checkbox für Einwilligung
□ Link zur Datenschutzerklärung
□ HTTPS für Formular-Seite
□ Einwilligung dokumentieren (IP, Timestamp)
□ Löschkonzept implementiert
□ Spam-Schutz ohne Drittanbieter-Cookies
□ Datenschutzerklärung aktualisiert
□ Keine unnötigen Tracking-Skripte

Häufige Fehler

FALSCH:
- Checkbox vorausgewählt
- Pflichtfeld für Telefonnummer
- Kein Hinweis auf Datenschutzerklärung
- Google reCAPTCHA ohne Cookie-Consent
- Unbegrenzte Datenspeicherung
- Daten an Marketing-Tools senden

RICHTIG:
- Checkbox muss aktiv gesetzt werden
- Telefon optional
- Klarer Datenschutzhinweis
- Honeypot statt reCAPTCHA
- Automatische Löschung nach Frist
- Daten nur für Kontaktzweck

Fazit

DSGVO-konforme Kontaktformulare sind keine Hexerei. Minimieren Sie die Datenerhebung, informieren Sie transparent, dokumentieren Sie die Einwilligung und implementieren Sie ein Löschkonzept. Vermeiden Sie Drittanbieter-Tools wie reCAPTCHA, wenn möglich, und setzen Sie auf Honeypots für Spam-Schutz. Bei Unsicherheiten konsultieren Sie einen Datenschutzbeauftragten.