3 januari 2007
Een nieuwsbrief is een ideaal middel om het percentage terugkerende bezoekers op je site te vergroten. Tevens is het een zeer goedkoop (bijna gratis) marketingmiddel. In dit artikel zullen we een nieuwsbriefmodule bouwen aan de hand van PHP en MySQL. De module zal deze eigenschappen hebben:
Voor de nieuwsbriefmodule zullen drie tabellen nodig zijn:
In deze tabel worden de adressen opgeslagen van de mensen die abonnee zijn van de nieuwsbriefdienst. Hierin worden uiteraard de NAW-gegevens opgeslagen, maar daarnaast wordt er ook in opgeslagen of de aanmelding al geconfirmeerd is of niet. Tenslotte voegen we een veld met de naam ‘code’ toe. Deze zullen we later gebruiken als een soort van wachtwoord bij de confirmatie. Hier komen we later op terug. De tabel die we gaan gebruiken ziet er als volgt uit:
Tabel 'adressen': +----+---------------+------+------+-------+ | id | geconfirmeerd | code | naam | email | +----+---------------+------+------+-------+
Opmerking:
In de praktijk zul je uiteraard extra velden toevoegen zoals geslacht en voornaam. Om het allemaal wat overzichtelijk te houden, gebruiken we nu een minimale tabel.
Deze tabel bevat de mailings. In deze tabel plaatsen we een 0/1-variabele met de naam ‘verzonden’ om aan te geven of de nieuwsbrief al verzonden is of niet. Verder hebben we een interne titel en een onderwerpregel en slaan we zowel de HTML versie van de mail als de platte tekst versie op. De tabel wordt dan iets als:
Tabel 'mailings': +----+-----------+-------+-----------+----------+-----------+ | id | verzonden | titel | onderwerp | mailHTML | mailTekst | +----+-----------+-------+-----------+----------+-----------+
Op het moment dat een nieuwsbrief verzonden wordt, worden alle afzonderlijke mailtjes in de database gezet, zodat een cron job er elke paar minuten een aantal uit kan halen om te versturen. We slaan hierin ook de naam en het emailadres van de geadresseerde op. Deze tabel bevat dus deze velden:
Tabel 'mails': +----+------+-------+----------+----------+-----------+ | id | naam | email |onderwerp | mailHTML | mailTekst | +----+------+-------+----------+----------+-----------+
Nu we de database gemaakt hebben, moet er uiteraard een formulier gemaakt worden waarmee je je kan aan- en afmelden voor deze service. We maken ook gebruik van een confirmatiemailtje.
Voor je iemand een mailing mag versturen, moet deze persoon eerst toestemming hebben gegeven dat de mailing naar zijn mailadres wordt verstuurd. Dit wordt opt-in genoemd. Dit toestemming geven is niet overdraagbaar, oftewel: de eigenaar van het mailadres moet zichzelf aanmelden. Om dit te garanderen, wordt er vaak gebruik gemaakt van een confirmatiemailtje. Weliswaar kan iedereen het formulier voor aanmelding invullen, maar alleen als de gebruiker op een link in een confirmatiemailtje klikt is de aanmelding voltooid.
Opmerking:
Opt-out mailings versturen betekent dat je mensen ongevraagd een mailing stuurt, zonder dat hier toestemming voor is gegeven. Je geeft wel de mogelijkheid om bijvoorbeeld door het aanklikken van een link de registratie af te melden, maar de gebruiker heeft nergens om gevraagd. Dit is illegaal.
We gebruiken hetzelfde formulier om gebruikers te laten aanmelden of juist afmelden. Het formulier zal dus een radiobutton bevatten waarmee je kan aangeven of het gaat om aanmelden danwel afmelden. Verder bevat het formulier een veld voor je naam en een veld voor je emailadres. De code is dus iets als:
Naam
Opmerking:
Voor nu besteed ik even geen aandacht aan de verplichte velden en ga ik er van uit dat mensen keurig juiste data invoeren. Dit is eventueel via Javascript of PHP te controleren.
Als iemand zich wil aanmelden, dient er gecontroleerd te worden of het emailadres al niet in de database zit. Bij het afmelden moet het adres er juist wel in staan, anders valt er niks af te melden. De aanmeldpagina wordt dus iets als dit (waarbij ik er vanuit ga dat er al een databaseverbinding is):
function getCode($length){
$letters = array( 'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'0','1','2','3','4','5','6','7','8','9'
);
srand((double) microtime() * 1000000);
for ($c = 0; $c < $length; $c++)
$password .= $letters[rand(0,count($letters))];
return $password;
}
if ($_POST['submitForm']){
if ($_POST['actie'] == "afmelden"){
$result = mysql_query(" SELECT *
FROM adressen
WHERE email = '" . $_POST['email'] . "'") or die (mysql_error());
if (mysql_num_rows($result) == 0){
echo "
Dit emailadres (” . $_POST['email'] . “) bestaat niet in de database.
“;
}else{
$code = getCode(20);
mysql_query(” UPDATE adressen
SET code = ‘” . $code . “‘
WHERE email = ‘” . $_POST['email'] . “‘”) or die (mysql_error());
mysql_query(” SELECT *
FROM adressen
WHERE email = ‘” . $_POST['email'] . “‘”) or die (mysql_error());
/* Stuur de confirmatie voor AFMELDEN */
echo “
Dank u wel voor uw afmelding. Een confirmatiemail is naar u gestuurd.
“;
}
}else{
$result = mysql_query(” SELECT *
FROM adressen
WHERE email = ‘” . $_POST['email'] . “‘”) or die (mysql_error());
if (mysql_num_rows($result) == 1){
echo “
Dit emailadres (” . $_POST['email'] . “) bestaat al in de database.
“;
}else{
$code = getCode(20);
mysql_query(” INSERT INTO adressen
(geconfirmeerd, code, naam, email)
VALUES (’0′, ‘” . $code . “‘,
‘” . addslashes($_POST['naam']) . “‘, ‘” . $_POST['email'] . “‘)”) or die (mysql_error());
/* Stuur de confirmatiemail voor AANMELDEN */
echo “
Dank u wel voor uw aanmelding. Er is een confirmatiemail naar u gestuurd.
“;
}
}
}else{
?>
Naam
}
?>
Opmerking:
De $code wordt gebruikt om te voorkomen dat iemand de confirmatie-URL kan raden en op die manier alsnog niet bestaande emaildressen (of adressen van anderen) kan aan- of afmelden. $code is een string van 20 karakters bestaande uit getallen en letters.
Opmerking:
Zoals je ziet dienen er mailtjes verstuurd te worden. Hiervoor gebruik ik de class PHPMailer waarmee je erg makkelijk mailtjes kan versturen. Dit artikel gaat niet over PHPMailer dus voor vragen daarover moet je de documentatie van deze class maar wat lezen.
Het idee van de confirmatiemailtjes is dat er een mail wordt verstuurd met daarin een link voor confirmatie van het af- danwel aanmelden. Dit doen we op deze manier:
// Include de class (jouw pad kan natuurlijk afwijkend zijn)
include_once("include/classes/class.phpmailer.inc");
$mail = new PHPMailer();
// Afzender
$mail->FROM = trim(“info@jouwsite.nl”);
$mail->FROMName = trim(“Jouw naam”);
$mail->AddReplyTo = trim(“Jouw naam”);
// Geadresseerde
$mail->AddAddress($_POST['email'], $_POST['naam']);
// Onderwerp
$mail->Subject = “Confirmeren van aanmelding”;
// Tekstversie
$return = “Beste ” . $_POST['naam'] . “,nn”;
$return .= “Je hebt je zojuist aangemeld voor de nieuwsbrief van www.jouwsite.nl. Door op onderstaande link te klikken confirmeer je je aanmelding:nn”;
$return .= “http://www.jouwsite.nl/nieuwsbrief.php?actie=aanmelden&email=” . $_POST['email'] . “&code=” . $code . “nn”;
$return .= “Met vriendelijke groeten,nn”;
$return .= “jouwsite.nl”;
$mail->AltBody = $return;
// HTML-versie
$return = “
Beste ” . $_POST['naam'] . “,
Je hebt je zojuist aangemeld voor de nieuwsbrief van www.jouwsite.nl. Door op onderstaande link te klikken confirmeer je je aanmelding:
Met vriendelijke groeten,
jouwsite.nl
“;
$mail->Body = $return;
// Versturen
$mail->Send();
?>
Opmerking:
M.b.t. de lengte van dit artikel ga ik er vanuit dat het de lezer zelf wel lukt om de tabel mailings te vullen.
Op het moment dat er een mailing verstuurd wordt, worden de afzonderlijke mails in de tabel mails gezet. Deze zijn al volledig geprepareerd, waarmee ik bedoel dat de mails al gepersonificeerd zijn. In de mailings die ik verstuurd, gebruik ik altijd variabelen als %naam% en %email%. Deze moeten uiteraard vervangen door de naam en het emailadres van de ontvanger. Ik gebruik dus de volgende code om de tabel mails te vullen. Hierbij is $id het ID van de mailing die verstuurd zal worden:
// Haal de gegevens van de mailing op
$result = mysql_query(" SELECT *
FROM mailings
WHERE id = '" . $id . "'") or die (mysql_error());
$onderwerpOrigineel = mysql_result($result, 0, "onderwerp");
$bodyHTMLOrigineel = mysql_result($result, 0, "mailHTML");
$bodyTextOrigineel = mysql_result($result, 0, "mailTekst");
$result = mysql_query(" SELECT *
FROM adressen
WHERE geconfirmeerd = '1'") or die (mysql_error());
while ($obj = mysql_fetch_object($result)){
// Vervang de variabelen
$tijdelijkeVars = array( "%naam%",
"%email%");
$mailVars = array( stripslashes($obj->naam),
$obj->email);
$onderwerp = str_replace($tijdelijkeVars, $mailVars, $onderwerpOrigineel);
$bodySendHTML = str_replace($tijdelijkeVars, $mailVars, $bodyHTMLOrigineel);
$bodySendText = str_replace($tijdelijkeVars, $mailVars, $bodyTextOrigineel);
// Insert in tabel ‘mails’
mysql_query(” INSERT INTO mails
(naam, email, onderwerp, mailHTML, mailTekst)
VALUE (‘” . $obj->naam . “‘, ‘” . $obj->email . “‘,
‘” . addslashes($onderwerp) . “‘, ‘” . addslashes($bodySendText) . “‘,
‘” . addslashes($bodySendHTML) . “‘)”) or die (mysql_error());
}
// Sla op dat deze mail al verzonden is
mysql_query(” UPDATE mailings
SET verzonden = ’1′
WHERE id = ‘” . $id . “‘”) or die (mysql_error());
?>
Inmiddels staan alle mails die verzonden kunnen worden in de tabel mails. We gaan nu een code schrijven die elke keer zeg eens 25 mails uit deze tabel trekt en verstuurd. Deze code wordt d.m.v. een cron job zeg eens elke 2 minuten aangeroepen, zodat we 750 mails per uur kunnen versturen. De hele boel in één keer versturen is een veel te zware serverbelasting als de nieuwsbrief naar enkele honderden mensen of meer verstuurd moet worden. De code voor het versturen van de 25 mailtjes is:
// Databasegegevens en -connectie
define("DB_HOST", "localhost");
define("DB_USERNAME", "gebruikersnaam");
define("DB_PASSWORD", "wachtwoord");
define("DB_DBNAME", "database");
mysql_connect(DB_HOST, DB_USERNAME, DB_PASSWORD);
mysql_select_db(DB_DBNAME);
// Include PHPMailer (dit pad zal bij jou anders zijn!)
include_once('/var/www/vhosts/jouwsite.nl/httpdocs/include/classes/class.phpmailer.inc');
// Aantal mails die per aanroep verstuurd worden
$aantalEmailsPerKeer = 25;
// Selecteer de laatste $aantalEmailsPerKeer mailtjes
$result = mysql_query(" SELECT *
FROM mails
ORDER BY id DESC
LIMIT " . $aantalEmailsPerKeer);
// Verstuur de boel
while ($obj = mysql_fetch_object($result)){
// Haal de gegevens van dit ding op
$naam = stripslashes($obj->naam);
$email = stripslashes($obj->email);
$onderwerp = stripslashes($obj->onderwerp);
$bodySendHTML = stripslashes($obj->mailHTML);
$bodySendText = stripslashes($obj->mailTekst);
$mail = new PHPMailer();
$mail->ClearAddresses();
$mail->FROM = “info@jouwsite.nl”;
$mail->FROMName = “Jouw site”;
$mail->AddReplyTo = “info@jouwsite.nl”;
$mail->AddAddress($email, $naam);
$mail->Subject = $onderwerp;
/* Als er plaatjes zijn in het mailtje, moeten die embedded worden. Dit uitleggen gaat te ver
voor dit artikel, dus we geven de code zonder er al te veel commentaar bij te zetten.
*/
$data = $bodySendHTML;
// Haal alle img-tags op
preg_match_all(“|](.*)>|U”, $data, $imgmatches);
// Haal alle src-elementen op
$imgNames = array();
while (list($key, $value) = each($imgmatches)) {
while (list($key2, $value2) = each($value)) {
preg_match(“#src=([^s]{0,})s#”, $value2, $naam);
$naam[1] = str_replace(“‘”, “”, $naam[1]);
$naam[1] = str_replace(‘”‘, “”, $naam[1]);
$imgNames[] = $naam[1];
}
}
// Filter dubbele elementen
$imgNames = array_unique($imgNames);
// Doorloop alle images en vervang ze door embedded dingen
$i = 1;
while (list($key, $value) = each($imgNames)){
// Str-replace
$bodySendHTML = str_replace($value, “cid:my-” . $i, $bodySendHTML);
// Embedded ding
if (substr($value, -3) == “gif”){
$encoding = “image/gif”;
}else{
$encoding = “image/jpeg”;
}
$mail->AddEmbeddedImage(“../” . $value, “my-” . $i, “Pic$i”); // Dit pad (../) is natuurlijk afhankelijk van waar je foto’s staan…
$i++;
}
// Bepaal de body (HTML) en body (platte tekst)
$body = ”
if ($mail->Send() == true){
mysql_query(“DELETE FROM mails WHERE id = ‘” . $obj->id . “‘”);
}
}
// Sluit de database
mysql_close();
?>
Opmerking:
Hoe je de cron job instelt verschilt per server. Ook dit gaat wat voorbij aan het doel van de tutorial, dus ik ga er vanuit dat je weet hoe je de cronjob in moet stellen.
Dit is hoe we een nieuwsbriefmodule maken. Voor grotere toepassingen (> 1.000 adressen) zou ik je aanraden speciale software te gebruiken, omdat je dan bijvoorbeeld ook kan monitoren wat de response op de mailings is.