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 CronjobSpam-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-SkripteHä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 KontaktzweckFazit
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.