PHP 7 | Einfaches E-Mail Double Opt-in programmieren

Heute zeige ich dir wie du für ein Projekt, z.B. einen Newsletter, eine Double Opt-in Abfrage programmieren kannst, ohne dabei externe Erweiterungen oder Plugins zu benutzen.

Du brauchst dazu:

  • eine MySQL-Datenbank
  • drei PHP-Dateien
    • index.php
    • optin.php
    • success.php

MySQL-Datenbank erstellen

CREATE DATABASE IF NOT EXISTS `newsletter` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

CREATE TABLE `subscribe` (
  `uid` int(10) UNSIGNED NOT NULL COMMENT 'unique id',
  `pid` char(32) NOT NULL COMMENT 'personal id',
  `tstamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'create date',
  `email` varchar(255) NOT NULL COMMENT 'user email',
  `approved` int(1) NOT NULL DEFAULT '0' COMMENT 'email approved'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `subscribe` ADD PRIMARY KEY (`uid`);
ALTER TABLE `subscribe` MODIFY `uid` int(10) NOT NULL AUTO_INCREMENT;

Erklärung:
Es wird eine Datenbank mit dem Namen „newsletter“ erstellt und fünf Spalten.

  • uid -> Eindeutige ID
  • pid -> Persönliche ID
  • tstamp -> Datum wann sich derjenige eingetragen hat
  • email -> Die Benutzer E-Mail-Adresse
  • approved -> 0 = Standard | 1 = Benutzer hat E-Mail bestätigt

Anmeldeformular

$username = 'dein-mysql-benutzername';
$password = 'dein-mysql-benutzerpasswort';

$subscribeForm = '
  <p>Bitte deine E-Mail-Adresse eingeben, mit der Du unseren Newsletter erhalten möchtest.*</p>
  <form action="" method="post">
    <div class="form-group">
      <label>E-Mail</label>
      <input id="email" name="email" type="text" value="">
      <button name="abschicken" type="submit">E-Mail eintragen</button>
    </div>
  </form>
';

if ( isset( $_POST[ 'abschicken' ] ) ) {
  
  if (!empty($_POST["email"]))  {
    $email = $_POST['email'];
    $randomUid = md5(uniqid('', true) . '|' . microtime());

    if ( preg_match("/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]+$/", $email) ) {
      try {
        $pdo = new PDO('mysql:host=localhost;dbname=newsletter', $username, $password);
      } catch (PDOException $e) {
        echo 'Verbindung fehlgeschlagen: ' . $e->getMessage();
      }
      
      $stmt = $pdo->prepare("SELECT * FROM subscribe WHERE email=?");
      $stmt->execute([$email]);
      $checkEmail = $stmt->fetch();

      if ($checkEmail) {
        echo '<div class="anzeige">Die E-Mail-Adresse ' . htmlspecialchars($email) . ' ist schon vorhanden.</div>';
        echo $subscribeForm;
      } else {
        $statement = $pdo->prepare("INSERT INTO subscribe (pid, email) VALUES (?, ?)");
        $statement->execute(array($randomUid, $email));
        $pdo = null;
								
        $to = $email;
        $subject = "Newsletter Anmeldung";

        $message = '
          <html>
            <head>
              <title>Newsletter Anmeldung</title>
            </head>
            <body>
              <p>Bitte bestätige dass Du unseren Newsletter abonniert hast.</p>
              <a href="https://deine-domain.tld/success.php?parameter='.$randomUid.'">Anmeldung bestätigen</a>
            </body>
          </html>
        ';

        $headers = "MIME-Version: 1.0" . "\r\n";
        $headers .= "Content-type:text/html;charset=UTF-8" . "\r\n";
        $headers .= 'From: <deinemail@deine-domain.tld>' . "\r\n";

        mail($to, $subject, $message, $headers);	
        header("Location:optin.php");
        exit();
        }
      } else {
        echo '<div class="anzeige">Bitte korrekte email eingeben.</div>';
        echo $subscribeForm;
      }
    }
  } else {
    echo $subscribeForm;

}

Erklärung:
Das Skript prüft ob eine korrekte E-Mail-Adresse eingegeben wurde. Auch wird in der Datenbank abgefragt ob die eingetragene E-Mail schon vorhanden ist und wenn ja erscheint ein Hinweis.
Ist die E-Mail nicht vorhanden und korrekt eingegeben, wird ein neuer Datenbankeintrag erstellt und eine E-Mail mit Bestätigungslink an die hinterlegte E-Mail-Adresse versendet. Weitergeleitet wird auf die optin.php.

Wichtig: An den markierten Zeilen musst du deine Daten eingeben.

Seite für Hinweis auf Opt-in

Ein Hinweis an den Benutzer, dass der erste Schritt der Anmeldung geklappt hat, zeigen wir ihm auf einer neuen Seite.

<!DOCTYPE html>
<html lang="de">
<head>
    <title>Newsletter Anmeldung - Opt-in</title>
</head>
<body>
  <p>Vielen Dank für Ihr Interesse an unserem Newsletter. In Kürze erhalten Sie den Link zum aktivieren per E-Mail.</p>
</body>
</html>

Anmeldung erfolgreich abschließen

In der success.php prüfen wir ob der Link aus der E-Mail geklickt wurde und die „personal ID“ übereinstimmt.

$username = 'dein-mysql-benutzername';
$password = 'dein-mysql-benutzerpasswort';
										
$userPid = $_GET["parameter"]; 
					
try {
  $pdo = new PDO('mysql:host=localhost;dbname=newsletter', $username, $password);
} catch (PDOException $e) {
  echo 'Verbindung fehlgeschlagen: ' . $e->getMessage();
}

$stmt = $pdo->prepare("SELECT * FROM subscribe WHERE pid=?");
$stmt->execute([$userPid]);
$checkPid = $stmt->fetch();

if ($checkPid) {	
  $statement = $pdo->prepare("UPDATE subscribe SET approved = '1' WHERE pid = :pid");
  $statement->execute(array(':pid'=>$userPid));
} 
$pdo = null;

Erklärung:
Wenn die PID aus dem Link übereinstimmt, wird in der Datenbank bei dem Feld „approved“ der Wert 0 auf 1 gesetzt. Dadurch weißt du, ob der Opt-in auch korrekt durchgeführt wurde und du dem Benutzer deinen Newsletter schicken darfst.

Kommentare

  • Tobias
    12.12.2019 - 15:26 Uhr

    Danke für diesen genialen Code! Funktioniert wirklich super, bis auf: ich erhalte keine Nachricht, wenn sich jemand einträgt. Frage: Was muss ich wo noch einfügen, damit ich (der Newsletter-Anbieter) eine entsprechende E-Mail erhalte, sobald bestätigt wurde? Vielen Dank und lg Tobias

    Antworten
    • Markus
      12.12.2019 - 15:56 Uhr

      Hallo Tobias,

      danke dir!
      Du könntest in der success.php bei der if Abfrage „if ($checkPid)“ eine E-Mail verschicken. Als Beispiel kannst du dir den Code des Anfrageformulars anschauen.

      Antworten
  • fsagregrerqgrefg
    26.01.2020 - 10:43 Uhr

    Auto Increment für uid fehlt hier

    ALTER TABLE `subscribe` MODIFY `uid` int(10) NOT NULL AUTO_INCREMENT;

    Antworten
    • Markus
      01.02.2020 - 15:00 Uhr

      Stimmt! Danke dir!

      Antworten
  • c0der
    04.04.2020 - 13:29 Uhr

    Code funktioniert wunderbar.

    Vielen Dank für’s veröffentlichen!

    Antworten
    • Markus
      06.04.2020 - 09:14 Uhr

      Sehr gerne!

      Antworten
  • Ede
    09.06.2020 - 20:39 Uhr

    Bei meinen Tests war nur die erste bestätigte Opt-In Mail korrekt.
    Bei weiteren Tests war der Wert der .$randomUid. in der Opt-In Mail nicht übereinstimmend mit uid in der Datenbank.

    Beispiel:
    Opt-In Link führt zu
    /success.php?parametera4ac377461fc431110844da6785ff2

    Laut Datenbank ist die pid „caa4ac377461fc431110844da6785ff2“ somit müsste der Link
    /success.php?parameter=caa4ac377461fc431110844da6785ff2
    lauten. (Dieser Link setzt den approved Wert auch von 0 auf 1)

    Der zuständige Code für die Opt-In Mail scheint in Ordnung zu sein:
    Anmeldung bestätigen

    Habt ihr eine Idee wieso $randomUid bei den ersten Zeichen in der Mail von der pid in der Datenbank abweicht und das „=“ verliert?

    Antworten
    • Markus
      10.06.2020 - 08:20 Uhr

      Hallo Ede, ich kann deinen Fehler nicht reproduzieren. Bei mir funktioniert die Übergabe auch bei weiteren Tests. So spontan, teste doch mal einen anderen Browser und/oder Mail-Programm. Lass mich doch bitte wissen wenn es wirklich daran lag.

      Antworten
  • Wolf
    22.09.2020 - 19:53 Uhr

    Tolle Arbeit, danke!

    Antworten
    • Markus
      22.09.2020 - 20:02 Uhr

      Danke! Sehr gerne.

      Antworten
  • Andrew
    21.01.2021 - 00:27 Uhr

    Hallo Markus, danke für das tolle Script. Es läuft bis zur Registrierung soweit wunderbar!
    Leider kommt keine E-Mail Nachricht im Postfach an, könntest Du das bitte nochmal genauer erklären? LG, Andrew

    Antworten
    • Markus
      21.01.2021 - 07:14 Uhr

      Hallo Andrew, das könnte mehrere Ursachen haben. Zieladresse ist korrekt eingerichtet? Mailserver funktioniert? Domain und E-Mail-Adresse stimmen überein? Wenn nicht, Spam Ordner checken.

      Antworten
  • Andrew
    22.01.2021 - 22:22 Uhr

    Hallo Markus, Dankeschön alles gut! Dein Tipp hat mir sehr geholfen und so kam ich auch drauf, dass die Mail bei gmail im Spam Ordner landet. Bei zB. gmx kommt gar keine Mail an – warum auch immer.. LG, Andrew

    Antworten
  • snork
    19.02.2021 - 18:30 Uhr

    gibt es das script auch fertig zum runterladen ich weiß nicht wie ich es zusammenbauen muß

    Antworten
    • Markus
      04.03.2021 - 08:14 Uhr

      Zum Herunterladen gibt es das noch nicht. Woran scheitert es denn?

      Antworten
  • Flo P.
    03.03.2021 - 22:07 Uhr

    Hallo

    Vielen Dank für das Skript. Ich würde allerdings gerne noch den Namen mit erfassen, aber irgendwie scheitere ich daran. An welchen Stellen muss ich das denn noch erweitern?

    Datenbank und auch das Formular ist klar, aber beim Rest vom Code bin ich mir nicht sicher.

    Liebe Grüße

    Antworten
    • Markus
      04.03.2021 - 08:20 Uhr

      Hallo Flo,

      sollte so funktionieren (ungetestet):

      nach Zeile 9 das neue Input Feld (name ist hier wichtig für die Übergabe)
      name="lastname"

      nach Zeile 19
      $lastname = $_POST['lastname'];

      Zeile 36 + 37 ändern
      $statement = $pdo->prepare("INSERT INTO subscribe (pid, email, lastname) VALUES (?, ?, ?)");
      $statement->execute(array($randomUid, $email, $lastname));

      Viel Erfolg

      Antworten
  • Anonymous
    04.03.2021 - 16:56 Uhr

    Super vielen Dank! Klappt auf Anhieb.

    Antworten
  • Andreas (mic210)
    15.03.2021 - 04:58 Uhr

    Hallo Markus,
    Super Tutorial.Weiter so kann man nur Empfehlen.

    Antworten
    • Markus
      15.03.2021 - 17:42 Uhr

      Danke dir für die netten Worte! Freut mich geholfen zu haben.

      Antworten
  • Tim
    22.03.2021 - 16:03 Uhr

    Tolles Script 🙂
    Gibt es auch eine Möglichkeit, dass man sich im Newsletter per Linkt aus der Datenbank automatisch austragen kann?

    Antworten
    • Markus
      06.04.2021 - 21:46 Uhr

      Hallo Tim, klar dazu kannst du das Skript erweitern und die Datenbank nach der E-Mail durchsuchen und entsprechend die 1 wieder auf 0 setzen. Etwa so: SELECT * FROM subscribe WHERE email=?

      Antworten
  • André
    03.01.2024 - 09:12 Uhr

    Hallo,

    Super Script, funktioniert gut,

    Mir ist aufgefallen, wenn ich auf Absenden klicken und das Eingabefeld leer ist, verschwindet das Formular.

    Dann würde ich noch eine checkbox zur Zustimmung der DSGVO einbinden, vielleicht kann mir hier jemand auf die Sprünge helfen? Wäre super nett.

    Antworten

Schreibe einen Kommentar

Erforderliche Felder sind entsprechend markiert.

Wird nicht veröffentlicht.