Building a Simple PHP Mailing List

 

In this tutorial I will be showing you how to build a PHP mailing list web app. In this web app, users will be able to sign up. Once they do they will be added to the database and an unsubscribe hash will be generated. Admins will be able to send emails and add [unsubscribe] within the email in order to show a way for the subscribers to remove themselves. Javascript will also be added to the sign up process to make it nicer for the users.
Live Demo
Username: alex
Password: password
Download

Databases

We are going to need two databases for this system. One for the admins and one for the subscribers. Here is the SQL code needed for the tables.

CREATE TABLE IF NOT EXISTS `subscribers` (
  `id` int(30) NOT NULL auto_increment,
  `email` varchar(60) NOT NULL,
  `unsubscribeLink` varchar(35) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1  ;

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(30) NOT NULL auto_increment,
  `username` varchar(50) NOT NULL,
  `password` varchar(40) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1  ;

INSERT INTO `users` (`id`, `username`, `password`) VALUES
(1, 'alex', '5f4dcc3b5aa765d61d8327deb882cf99');

After running that code you will have two tables one for subscribers that has an ID, email address and a unsubscribe fields (with ID as the primary key and set to auto increment). The other table for the users has an ID, username and password field (again with the ID as the primary key and set to auto increment). After that we insert into the ‘users’ table the values “alex” for the username and an MD5 hash of the word password. You can change these to what ever you want just make sure that the password is MD5 hashed or you will not be able to login later.

Connecting to the database

Create a directory “functions” and within that two files “function.php” and “config.php”. We will add information to the config file connecting to the database. This is what you need:

<?php
	$dbhost = 'localhost'; // database host
	$dbuser = 'USERNAME'; // database username
	$dbpass = 'PASSWORD'; // database password
	$db		= 'DATABASE'; // the database
	$conn 	= mysql_connect($dbhost, $dbuser, $dbpass) or die("Could not connect to the database"); // creat a connection or die
	mysql_select_db($db) or die("I couldn't find the database"); // select the database or die
	define("BASE_URL", "http://url-to-file/mail_list/"); // the URL to the file
	define("REPLY_EMAIL", "noreply@yourdomain.com"); // the email address we want our mailing list to be from

If you load that page and don’t see anything you have successfully connected to your database. We now need to fill in the ‘functions.php’ file. Within ‘functions.php’ add

<?php
session_start();	// start session
require_once("config.php"); // require our config.php file

function reply($type, $message){ // function to reply to the javascript
		$replying = array("error"=>"{$type}", "message"=>"$message");
		echo(json_encode($replying)); // json encode the responce
}

function add_email_to_database($email){ // adding the email address to the datbase
	// 1. We need to make sure its not already in
	// 2. We need to make a unsubscribe hash
	// 3. We need to add the user

	$email = mysql_real_escape_string($email); // make sure it OK
	$sql = "SELECT * FROM `subscribers` WHERE email = '{$email}' LIMIT 1"; // select all subsribers that has the email and only return (if there is) one
	$qry = mysql_query($sql); // run the query
	if( mysql_num_rows($qry) != 0){ // if that user was found they are not new so return false
		return false;
	}else{ // user was not found
		$unsubLink = ""; // create empty varible
		$unsubLink .= rand(1111, 99999); // generate random number and add it to the empty varible
		$unsubLink .= rand(1111, 99999);
		$unsubLink .= $email; // attach the email address

		$unsubLink = md5($unsubLink); // md5 it
		$unsubLink .= rand(1111, 99999); // then attack a random number

		// insert the values
		$sql = "
				INSERT INTO `subscribers` (
					`id` ,
					`email` ,
					`unsubscribeLink`
				)
				VALUES (
					NULL , '$email', '$unsubLink'
				);
			";

		mysql_query($sql); // run the query
		return true; // return true as we added the user
	}
}

function loggedIn(){ // check if we are logged in
	if($_SESSION['loggedIn'] != 1){ // if we are not
		return false;
	}else{ // if we are
		return true;
	}
}
[/sourceode]</pre>
That is all we need for both of these files.
<h2>Sigh up page</h2>
This page will allow the users to sign up, it will added them to the database after some validation all happening with some AJAX. Create an index.php page and add:
[sourcecode language="php"]
<?php
 session_start(); // start the session
 $message = $_SESSION['message']; // check if we have a message to display
 $_SESSION['message'] = "";  // clear the message for next time
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 <title>Mailing List Web App</title>

 <!-- Start of CSS -->
 <link rel="stylesheet" type="text/css" href="css/reset.css" />
 <link rel="stylesheet" type="text/css" href="css/main.css" />
 <!-- Start of JS -->
 <script type="text/javascript" src="js/jquery.js"></script>
 <script type="text/javascript" src="js/scripts.js"></script>
</head>

<div id="wrap">
 <h1>Join my list!</h1>
 <!-- If we have a message, display it -->
 <?php if(strlen($message) > 0){ ?><h2 class="stat"><?php echo '<br />'. $message ?></h2><?php } ?>
 <br />
 <form action="./add.php" method="POST" id="subscribe">
 <label class="label" for="email">Email</label>
 <input type="text" value="you@you.com" size="20" id="email" name="email" />
 <input type="submit" id="submit" value="Sign Up!" />
 </form>
 <p class="message"></p>
 <br /><br />
 <a class="small" href="admin">(admin)</a>
</div>
</body>
</html

Now create a CSS directory and add a reset CSS file (you can find them online, though this is optional) and a file main.css. Then add this styling:

@charset "UTF-8";
/* CSS Document */
/* UTULITIES */
.clear{clear: both;}
.push{height: 30px;}
/* END */
/* ORDER PAGE CORRECTLY */
*{margin: 0; padding: 0;}
html{overflow-y: scroll;position: relative;}
body{background-color: #e1e1e1; font-family: "Lucida Grande", Verdana, Arial, sans-serif; width: 100%; height: 100%;}
/* END */
h1{
	font-size: 30px;
	font-weight: bold;
	margin-bottom:  20px;
	color: #D0D3D3;
	padding-bottom: 8px;
	border-bottom: 1px solid #B4B6B6;
}
#wrap{
	background-color: #888888;
	width: 500px;
	margin: 0 auto;
	padding: 20px;
}
form{text-align: center;}
.label{color: #C3C5C5;font-size: 20px;}
#email, #password, #username{margin-top: -2px;font-size: 18px;background: none;border: none;border-bottom: 1px dotted black;color: #DBDEDE;}

.message{color:white;padding-top:20px;text-align:center;}
#login{padding-top: 10px;}
#create{text-align: left;}
.input{
font-family: "Lucida Grande", Verdana, Arial, sans-serif;
background:none repeat scroll 0 0 #E3E5E5;
border:1px solid #9A9C9C;
display: block;
font-size:16px;
padding:5px;
color: #3F4040;
}

.input:hover, .input:focus{background: #EAECEC;border: 1px solid #575858;}
.note{color:white;font-size:13px;}
.log{text-decoration: none; color: white;}
.small{text-decoration: none; color: white;font-size: 15px;}
.small:hover{color: black;}
.stat{text-align: center; color: white;}

Javascript

This javascript file will listen for a submit on the form then post the data to our adder php file using jQuery/AJAX.

$(function() {
function pulse(item){ // an animation to plus an item
	$(item).animate({"opacity": 0.5}, 200)
	.animate({"opacity": 1}, 200)
	.animate({"opacity": 0.5}, 200)
	.animate({"opacity": 1}, 200)
	.animate({"opacity": 0.5}, 200)
	.animate({"opacity": 1}, 200)
	.animate({"opacity": 0.5}, 200)
	.animate({"opacity": 1}, 200)
	.animate({"opacity": 0.5}, 200)
	.animate({"opacity": 1}, 200)
	.animate({"opacity": 0.5}, 200)
	.animate({"opacity": 1}, 500);
}

$('#submit').removeAttr('disabled'); // when we load the page make sure this button is OK
$('.message').css({"display": "none"});	// hide the message class

var emailsVal = $('#email').val(); // get the current value of #email

$("#email").focus(function(){	// when the input is clicked
	if($(this).val() == emailsVal){ // if the value is the defult value
		$(this).val(''); // clear the box
	}
});

$('#subscribe').submit(function(e){	// when clicked
	$('#submit').animate({'opacity': '0.4'}).attr({'disabled': 'disabled'}); // fade out/deactivet submit button
	e.preventDefault(); // prevent defult
	$.ajax({ //ajax
		type: 'post', // post the data
		dataType: 'json', // data type
		url: 'add.php', // url of the file to post to
		data: 'email=' + $('#email').val(), // data to post
		success: function(e){ // on success
			if(e.error == true){ // if we set an error
				pulse('#email'); // pule the email box
				$('.message').html(e.message).slideDown(); // display the message
				$('#submit').animate({'opacity': '1'}, function(){ // fade back in the submit box
					$(this).removeAttr('disabled'); // remove the disabled attr so its clickable
				});
			}else{ // if we set didn't set an error
				$('#subscribe').slideUp(); // slide up the subscribe box
				$('.message').html(e.message).slideDown(); // slide down the message
			}
		}
	});

		$(this).ajaxError(function(){
//			alert("THERE WAS AN AJAX ERROR, SORRY ABOUT THAT"); // optional, to say if there was a AJAX error
		});
		return false; // return false (stop form from posting)
}); // end of AJAX

});

Adding the user

Create a file “add.php” where the javascript will post to. Within we will need to validate and then add the user. Also return a JSON encoded response for the awaiting JS script. This is the needed code:

<?php
require_once("functions/functions.php"); // include the functions and the config file
$email = $_POST['email']; // get the email
if (!preg_match('/^[a-z0-9]+([_\.-][a-z0-9]+)*@([a-z0-9]+([.-][a-z0-9]+)*)+\.[a-z]{2,}$/i', $email)) { // make sure it valid
		$error = "Email not valid";	 // set a message
		reply(1, $error); // set an error
		die(); // die and stop running the script
}

if($email == "you@you.com"){ // if its you@you the user just clicked submit and although its valid it won't be a users email
	$error = "Thats not your email!";
	reply(1, $error);
	die();
}

if( add_email_to_database($email) ){ // if we added the user
	reply(0, "Thanks! You are now in the know."); // set no error
}else{
	reply(1, "That email is already in the know."); // else, the user was found alreay
};

Admin pages

That is all that we need to allow the user to subscribe! Now create a directory “admin” and add these files “index.php”, “login.php”, “logout.php” and “poster.php”. In the index file we will post to a login form. I am going to build the login/out script first as I know what I will be needing.

Login

Open the login.php file and add

<?php
	require_once("../functions/functions.php");
		// get/clean values
	$username = mysql_real_escape_string(trim($_POST['username']));
	$password = mysql_real_escape_string(trim($_POST['password']));
		// something was entered
	if(strlen($username) == 0 || strlen($password) == 0){ // if no username of password was entered
		$_SESSION['message'] = "Please enter a username and a password"; // set a message
		header("Location: ". BASE_URL ."/admin");   // direct to the admin page
		die(); // die/stop script
	}else{
		$password = md5($password); // hash the password
	}

	$sql = "
		SELECT * FROM users WHERE username = '{$username}' AND password = '{$password}' LIMIT 1;
		"; // search for users with that username/password
	$qr = mysql_query($sql); // run query
	if( mysql_num_rows($qr) == 1 ){  // if the user was found
		$user = mysql_fetch_assoc($qr); // get values
		$_SESSION['loggedIn'] = 1; // set logged in session
		$_SESSION['username'] = $user['username']; //  you may want their username

		$_SESSION['time'] =  $_SERVER['REQUEST_TIME']; // incase you want to time out a user
		$_SESSION['message'] = "You have been logged in"; // set message
		header("Location: ". BASE_URL ."/admin");   // redirect the user
		die();
	}else{
		$_SESSION['message'] = "Didn't find a username and password with that information.";
		header("Location: ". BASE_URL ."/admin");
		die();
	}

Logging Out

Now open logout.php and add this small bit of simple code to log the user out:

<?php
require_once('../functions/functions.php');
session_destroy(); // destroy all information
session_start(); // start a new session just for the message
$_SESSION['message'] = "You have been logged out"; // say we have been loggged out
header("Location: " .BASE_URL."/admin");  // relocate to the admin page

That is all we need to logout users.

Messeger

Open the index.php file where we will add code to check if we are logged in, if we are we will show a form to email people, if not, we will show a login form submitting the the login.php file we made above.

<?php
	require_once('../functions/functions.php');
	$loggedIn = loggedIn(); // run login function
// checking for message/sessions content

	if( isset($_SESSION['message']) ){ // if we have a message
		$message = $_SESSION['message']; // set a local varible
		$_SESSION['message'] = ""; // clear the session
	}

	if( isset($_SESSION['subject']) ){ // if we have a recovered subject
		$subject = $_SESSION['subject'];
	}else{
		$subject = "";
	}
	if( isset($_SESSION['messageArea']) ){ // if we have a recovered message
		$messageArea = $_SESSION['messageArea'];
	}else{
		$messageArea = "";
	}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<title>Mailing List Web App || ADMIN</title>

		<!-- Start of CSS -->
 	<link rel="stylesheet" type="text/css" href="../css/reset.css" />
	<link rel="stylesheet" type="text/css" href="../css/main.css" />
</head>

<div id="wrap">
<?php if(!$loggedIn){ //user is not logged in ?>
	<h1>Please, login</h1>
	<?php if($message) echo "<h3 class='message'>".$message."</h3>"; ?>
	<form action="login.php" method="POST" id="login">
		<label class="lable" for="username">Username</label>
		<input type="text" value="alex" size="20" id="username" name="username" />
		<br /><br />
		<label class="lable" for="password">Password</label>
		<input type="password" value="" size="20" id="password" name="password" />
		<br /><br />
		<input type="submit" id="submit" value="Log me in!" />
	</form>
	<p class="message"></p>
<?php }else{ // user is logged in ?>
	<h1>Send A Message</h1>
	<?php if($message) echo "<h3 class='message'>".$message."</h3>"; // display any messages ?>

	<form action="poster.php" method="POST" id="create">
		<label for="subject" class="label">Subject</label><br /><br />
		<input class="input" name="subject" id="subject" type="text" value="<?php echo $subject; // echo the varible ?>" />
		<br />
		<label for="messageArea" class="label">Message</label><br /><br />
		<textarea class="input" name="messageArea" id="messageArea" rows="15" cols="46" wrap="wrap"><?php echo $messageArea; ?></textarea>
		<br />
		<input type="submit" value="Send message" /><br />
		<small class="note">Note: Add [unsubscribe] in the email to add an unsubscribe link.</small>
	</form>
	<br /><br />
	<a class="log" href="<?php echo BASE_URL ?>/admin/logout.php">Logout</a>
<?php } ?>
</div>
</body>
</html>

Sending emails

This will now create a nice way to login, and post emails. We just need the scrip to send all the emails. Open poster.php and we will make it.

<?php
require_once('../functions/functions.php');
if($_SESSION['loggedIn'] != 1){
		// if the user is not logged in, redirect them and add the message to
		// tell them they must be logged in
		// helps with unwanted people running your script by posting to it.
		$_SESSION['message'] = "You must be logged in.";
		header("Location: ". BASE_URL ."/admin");
		die();
}
$message = $_POST['messageArea'];
$subject = $_POST['subject'];
if(strlen($message) == 0 || strlen($subject) == 0){
	// if no information was added in either fields, save what was intered in a session and redirect them
	$_SESSION['subject'] = $subject;
	$_SESSION['messageArea'] =  $message;
	$_SESSION['message'] = "Please fill in both the subject and the message.";
	header("Location: " .BASE_URL."/admin");
	die();

}
// grab all the subscribers
$sql = "
	SELECT * FROM subscribers;
";

$qr = mysql_query($sql);
// if we don't have any
if(mysql_num_rows($qr) == 0){
	$_SESSION['message'] =  "You currently have no subscribers";
	header("Location: " .BASE_URL."/admin");
	die();
}

// go through all the subscribers
while( $user = mysql_fetch_array($qr)){
	// set a message
	$_SESSION['message'] =  "Your emails are being sent...";
	// redirect the user (no point in them waiting for all the messages to send...)
	header("Location: " .BASE_URL."/admin");
	$newMessage = ""; // set a clear varible
	// search for the [unsubscribe] tag and replace it with a URL for the user to unsubscribe
	$newMessage = str_replace(
		"[unsubscribe]",
		BASE_URL."/unsubscribe/".$user['unsubscribeLink']."&email=".$user['email'],
		$message
	);

	// replace all special characters
	$newMessage = htmlspecialchars($newMessage);
	// replace new lines with break tags
	$newMessage = str_replace( "\r\n",
								"<br />",
								$newMessage
							);
	// content type
	$headers  = 'MIME-Version: 1.0' . "\r\n";
	$headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
	$headers .= "From: ".REPLY_EMAIL."\r\n"; // who the reply is to
	mail($user['email'], $subject, $newMessage, $headers); // send the email to the user
}

Unsubscribe

Only one small thing left to do… Build the unsubscribe page which is being sent in the email. For this we need a directory called “unsubscribe” and inside that two files. A .htaccess file to make the URL slightly cleaner and the index.php file.
Open the .htaccess and add

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?hash=$1 [L]

This will make the first variable the hash on the index page. Open the index page and this final bit of code:

<?php
require_once('../functions/functions.php');
$hash = mysql_real_escape_string($_GET['hash']); // get the hash, you don't really need to make sure its clean unless you want to add this to a diffrent database table etc.
$email = mysql_real_escape_string($_GET['email']); // get the email
if(strlen($hash) < 1 || strlen($email) < 1 ){ // make sure they are set
	$_SESSION['message'] = "The code is not valid - please contact support";
	header("Location:  ".BASE_URL );
	die();
}
// make sure email is avlid
if (!preg_match('/^[a-z0-9]+([_\.-][a-z0-9]+)*@([a-z0-9]+([.-][a-z0-9]+)*)+\.[a-z]{2,}$/i', $email)) {
	$_SESSION['message'] = "The code is not valid - please contact support";
	header("Location:  ".BASE_URL );
	die();
}

$sql = "
		SELECT * FROM subscribers WHERE email = '$email' AND unsubscribeLink = '$hash' LIMIT 1;
	"; // search for that user
	$qr = mysql_query($sql); // run
	$rows = mysql_num_rows($qr); // get the number or rows with that information

	if($rows == 1){ // if it was found delete it
		$sql = "DELETE FROM `subscribers` WHERE `email` = '$email' AND `unsubscribeLink` = '$hash' LIMIT 1";
		mysql_query($sql);
		$_SESSION['message'] = "You have been unsubscribed successfully";
		header("Location:  ".BASE_URL );
		die();
	}else{ // if not tell them to contact support for manual removal
		$_SESSION['message'] = "You where not found - please contact support";
		header("Location:  ".BASE_URL );
		die();
	}

That is now all complete and you should have a working mailing list app. Hope that you have found this interesting and learnt a few things.

Share and Enjoy:
  • Print
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Add to favorites
  • Design Float
  • DZone
  • email
  • FriendFeed
  • PDF
  • Propeller
  • Reddit
  • RSS
  • StumbleUpon
  • Twitter

Related posts:

  1. Building a Tweetblast
  2. How to Create a Simple API with PHP and MySQL
  3. Create URL Shortener For Twitter Using PHP
  4. Really Simple Model/View Seperation With PHP
  5. Twitter URL Shortener: Part 2


Written by Alex

My name is Alex Bor and I am currently a full time student. I have been building websites for about 3 years and love to build sites that will take advantage of new techniques (such as AJAX and CSS3) to make them both look nicer and be more user friendly. You can view my website or follow me on Twitter.

 

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 
connect with me!