Automatische Administration von Mailinglisten

Am Beispiel dieser Übung zeige ich, wie ich in der ASYL Plattform die Anmeldung der Helfer und Helferinnen mit der Administration der Postfächer verknüpft habe. Die Opt-In/-Out Optionen sind damit Bestandteil der Anmeldungsformulare, die auf Google Form basieren. Der Mechanismus läuft bereits seit 3 Monate zuverlässig und nimmt sehr viele händische und fehleranfällige Arbeit ab.

Ziel der Übung

In meiner „ASYL Plattform“ können sich die Helfer und Helferinnen bei einem Helferkreis auf einer Webseite anmelden. Ich habe dafür Google Form als technische Basis genommen. Mit Hilfe von Google Apps konnte ich die Kommunikationsnachrichten und die weitere Bearbeitung der Helferdaten genau nach meinen Anforderungen mit eigenen Skripten realisieren. Sobald sich die Helfergruppen im Helferkreis gebildet haben, mussten Postfächer erstellt werden, damit die Helfergruppen entsprechend adressiert werden können. Dieser Schritt wurde manuell durchgeführt, auch nach  jeder Änderung der Helfergruppen. Das Ziel der Übung war, genau diesen Schritt zu automatisieren und die Admins der Seiten zu entlasten.

Was gibt es auf dem Markt ?

Natürlich gibt es auf dem Markt verfügbare Lösungen für Mailinglisten. Mailman ist eine davon, um nur eine zu erwähnen. Mein Setup war jedoch spezifisch und ich wollte hier mein System ergänzen und nicht ganz umkrempeln. Die Benutzer des Systems sollen im Idealfall keine Änderung wahrnehmen. So machte ich mich auf die Suche nach einer Plattform, welche die nachfolgenden Anforderungen erfüllen sollte:

  • Eine Mail-Plattform mit einer einfach zu bedienenden API. Die API ist erforderlich um die bestehenden Formulare zu integrieren.
  • Eine Mail-Plattform mit der Möglichkeit, eigene Domänen zu integrieren: die Benutzer sollen vertraute Domänen sehen.
  • Eine Mail-Plattform, die zwischen öffentlichen und geschlossenen Listen unterscheiden kann.
  • Eine Mail-Plattform mit einer guten Reputation, und wo die E-Mail-Adressen der Benutzer ausreichend  geschützt sind.
  • Und letztendlich eine Mail-Plattform, die ein großes Kontingent an E-Mail-Nachrichten kostenfrei anbietet.

Google bietet auch eine API zu G-Mail-Listen; nach einer kurzen Testphase musste ich jedoch aufgeben, da die Integration mit den Google Forms nicht wirklich trivial und einfach war.

Nach einer kurzen Testphase von:

  • Mailjet
  • Sendgrid
  • Mailgun

habe ich mich für Mailgun entschieden:

Setup: Die Backend Sicht

Folgendes Bild zeigt alle Komponenten, die ich benötigt habe, um die E-Mail Verteiler automatisch zu administrieren:

Blog

  • Google: Die Google Formulare waren bereits vorhanden. Sobald eine Anmeldung durchgeführt wurde, hat Google einen eigenen Skript durchgeführt, um den Benutzer per Mail zu benachrichtigen. Diesen Script musste ich nun erweitern, damit in einer SQL Datenbank die Mailing Listen aktualisiert werden. Google kann keine API direkt nutzen, um z.B. Mailgun direkt zu steuern.
  • Die MY SQL Datenbank lief bei mir auf dem NAS Server. Dort habe ich alle Listen verwaltet.
  • Ein PHP Skript lief auch auf meinem NAS Server und wird per Cronjob täglich um 02:00 nachts ausgeführt. Dieser Skript stellte fest, welche Aktualisierungen erforderlich sind und hat daraufhin mit Mailgun API alle Mail-Listen aktualisiert. Die Admin’s der jeweiligen Helferkreise wurden daraufhin benachrichtigt.
  • Mailgun wurde nie händisch konfiguriert, sondern stets mit dem PHP Skript. Im Mailgun konnte man die Logs anschauen und Gegenmaßnahmen starten, wenn ein Empfänger Probleme hatte.
  • In Mailgun habe ich eigene Domänen nach dem Muster <helfergruppe>.asyl-plattform.de registriert. Dies erforderte sehr tiefe Eingriffe in der DNS-Zonendatei. Das konnte ich mit Strato nicht, daher habe ich meine Domäne bei GoDaddy registriert.
  • In Strato waren die Helferkreise mit ihren Domänen registriert. Dort haben wir alle Fassade-Postfächer angelegt, mit einer eifachen Weiterleitung zu Mailgun-Mailingslisten.
  • Am Ende hatten wir diese Kette:
    Strato: <gruppenname>@asyl-<helferkreis>.de >
    Mailgun: <gruppenname>@<helferkreis>.asyl-plattform.de

Benutzer Sicht

Aus Benutzer Sicht hat sich nichts verändert. Mit nachfolgendem Formular können die Benutzer Ihre Aufnahme in den Postfächern steuern. Die Benutzer erhalten eine E-Mail mit einem Link zum Formular, wo sie jederzeit nachträglich ihre Anmeldung ändern oder beenden können:

Highlights:

  • Die Interaktion Benutzer-Plattform blieb unverändert.
  • Alle früheren Anmeldungen konnten ohne Zusatzaufwand berücksichtigt werden.
  • 10.000 Mails / Monat reichen in der Regel pro Helferkreis > KEINE Kosten.
  • Über Mailgun können Zustellungsprobleme identifiziert werden. Damit können ungültige E-Mail Adressen (Hard-Bounces) oder sonstige temporäre Probleme (Soft-Bounces) schnell identifiziert werden.
  • Alles läuft reibungslos und Stabil seit 3 Monaten.
  • Doppelte Anmeldungen werden vom PHP Skript erkannt und den Admin’s angezeigt.

Lowlights:

  • Bei der kostenfreien Version von Mailgun teilt man sich die IP Adressen mit anderen Benutzer. Die Reputation der IP Addresse führt teilweise zur Ablehnungen der Mails > Abhilfe kann eine eigene IP Addresse schaffen.

 

CODE-Examples:

PHP: Access My SQL DB

// Create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);
// ...
// get Info from SQL Table
$sql = "SELECT Name, Beschreibung FROM " . "`" . $helferKreiseRow["Listen"] . "`";
$mailListenTable = mysqli_query($conn, $sql);

 

PHP: Create Mailgun client to access the API. Private key is stored in the user profile of Mailgun

$mgKey = 'key-xxx';
$reisagreiKey = 'key-yyy';
$waakirchenKey = 'key-zzz';

// ...

# Instantiate the Mailgun client.
if ( $helferKreiseRow["Name"] == 'ReiSaGrei') { $mgClient = new Mailgun($reisagreiKey); }
else if ( $helferKreiseRow["Name"] == 'Waakirchen / Schaftlach') { $mgClient = new Mailgun($waakirchenKey); }
else if ( $helferKreiseRow["Name"] == 'Stephanskirchen') { $mgClient = new Mailgun($stephanskirchenKey); }
else if ( $helferKreiseRow["Name"] == 'Valley') { $mgClient = new Mailgun($valleyKey); }
else if ( $helferKreiseRow["Name"] == 'Bichl und Benediktbeuern') { $mgClient = new Mailgun($bichlKey); }
else { $mgClient = new Mailgun($mgKey); }
sleep (2);

 

PHP:  How to create and delete mailing lists in Mailgun:

function addMember ($mgClient, $mgListAddr, $memberAddr, $memberName) {

$memberList = $mgClient-&gt;get("lists/$mgListAddr/members", array(
'subscribed' =&gt; 'yes',
'limit' =&gt; 100,
'skip' =&gt; 0
));

foreach ($memberList-&gt;http_response_body-&gt;items as $obj) {
if ($obj-&gt;address == $memberAddr) {
echo '(duplicate:' . $memberAddr . ")";
return '<span style="color: red;">-Mehrfach:' . $memberAddr . '-</span>';
}
}

try {
$res = $mgClient-&gt;post("lists/$mgListAddr/members", array(
'address' =&gt; $memberAddr,
'name' =&gt; $memberName,
'subscribed' =&gt; 'yes'
));
} catch (Exception $e) {
echo '(error:' . $memberAddr . ")";
return '<span style="color: red;">-Fehler:' . $memberAddr . '-</span>';
}
return '<span style="color: green;">√</span>';
}

PHP:  How to add a member to a Mailgun mailing list:

 function addMember ($mgClient, $mgListAddr, $memberAddr, $memberName) { $memberList = $mgClient-&gt;get("lists/$mgListAddr/members", array( 'subscribed' =&gt; 'yes', 'limit' =&gt; 100, 'skip' =&gt; 0 ));
// check duplicate users foreach ($memberList-&gt;http_response_body-&gt;items as $obj) { if ($obj-&gt;address == $memberAddr) { echo '(duplicate:' . $memberAddr . ")"; return '<span style="color: red;">-Mehrfach:' . $memberAddr . '-</span>'; } }
try { $res = $mgClient-&gt;post("lists/$mgListAddr/members", array( 'address' =&gt; $memberAddr, 'name' =&gt; $memberName, 'subscribed' =&gt; 'yes' )); } catch (Exception $e) { echo '(error:' . $memberAddr . ")"; return '<span style="color: red;">-Fehler:' . $memberAddr . '-</span>'; } return '<span style="color: green;">√</span>'; } 

Google APPs: Access My SQL and add Mailing List Info


function adminMailingLists (helferkreis, ownMail, helferkreisPrefix) {

// Connection parameters:

var connection = Jdbc.getConnection("jdbc:mysql://domain-name:3306/database-name", "asylplattform", "pwd");

// ...

// check if helfekreis is already configured in mysql db
SQLstatement = connection.createStatement();
query="SELECT `Name`, `Listen` FROM `Helferkreise` WHERE Name = " + "'" + helferkreis + "'";
result = SQLstatement.executeQuery(query);

// create table entry
if (!result.isBeforeFirst() ) {
Logger.log("Helferkreis muss noch angelegt werden");
stmt = connection.prepareStatement('INSERT INTO Helferkreise '
+ '(Name, Aktualisiert, Listen) values (?, ?, ?)');
stmt.setString(1, helferkreis);
stmt.setString(2, '0');
stmt.setString(3, mailinglist);
stmt.execute();

// get E-Mail of subcribed users and start batch change in SQ Table !
filteredMails = findRow(groupArray[i], helferkreis);
for(var j = 0; j &lt; (filteredMails.length); j++){
stmt.setString(1, filteredMails[j][8]);
stmt.setString(2, filteredMails[j][3] + ' ' + filteredMails[j][4]);
stmt.addBatch();
Logger.log("+ Member:" + filteredMails[j][8]);
}
batch = stmt.executeBatch();
}

// indicate that the table is changed, so that the php script in the background can adapt Mailing Lists in Mailgun.
stmt = connection.prepareStatement("UPDATE `Helferkreise` SET `Aktualisiert` = '0' WHERE `Helferkreise`.`Name` ='" + helferkreis + "'");
stmt.execute();
result.close()
SQLstatement.close()
connection.close()
}
<pre>