You are on page 1of 11

MyInternetTutorials.

com

Free Autoresponder Tutorial

Find more of this tutorial at:

http://www.MyInternetTutorials.com

©2008, Michael Suddes – MyInternetTutorials.com


All Rights Reserved
http://www.MyInternetTutorials.com

Autoresponder tutorial
An autoresponder is on the surface a simple program. Take a list of email addresses and send a message. But you
can do that with an email program with a bcc: field. In its most common incarnation, an autoresponder sends out
messages to a subscriber in a pre-defined sequence and timing. Additionally, to comply with todays anti-spam laws
an autoresponder must include opt-out links in each message. To be safest, you can use a double opt-in system for
subscribers. But, this basic system is a single opt-in approach, and a manual unsubscribe system.
If theres enough interest, I will cover an add-on script that will handle double opt-ins and automatic unsubscribes.
Most, if not all, autoresponder programs use a database system. And, almost all of those use mySQL. If you're not
familiar with mySQL it would be beneficial to find a tutorial on it and at least get an idea of how it works. I have a
mySQL tutorial planned, but it will assume a basic knowledge of the program.
Additionally, a basic knowledge of php is assumed for this tutorial.
If you really need to get this program up and running, follow this link to download the finished product, but I
recommend you follow along with me to learn how it works.
So, lets get started:
Form handler script
The first thing we need to do is get subscribers information into the database. At minimum we need their name and
email address. We need a form and a way to process that form. The easiest way to do this is a page with a form and
a php script that gets called when the form is submitted.
Its a very simple form, two fields and a submit button. At least on the surface. if you want to prevent someone
from hacking your form, it takes a bit more planning.
Heres a basic form:
 

<form action="<?php echo $editFormAction; ?>" name="form1" method="post">


<p>Name:<br />
<input name="name" id="name" type="text" />
</p>
<p>email:<br />
<input name="email" id="email" type="text" /></p>
<p> <input name="Submit" value="Free access" type="submit" /> </p>
<input name="MM_insert" value="form1" type="hidden" /></form>

 
Th action of the form is a variable that is calculated from the name of the page the script is on, and any query
strings. The two fields are self explanatory. Then a submit button. Next, a hidden field that tells the script what we
want to do with the data. Not a required step, but it makes things easier if you have multiple forms.
This form gets placed in the page where you want it. The rest of the script goes at the top of the page.
 

<?php
$hostname_mailer = "localhost";
$database_mailer = "database";
$username_mailer = "user";
$password_mailer = "password";
$mailer = mysql_pconnect($hostname_mailer, $username_mailer, $password_mailer) or die
(mysql_error());

 
First, we open the script with <?php. Then we open our database. Hostname tells php where to connect, database
tells it which database, and user and password for access. The function mysql_pconnect uses the supplied variables

©2007 Michael Suddes - MyInternetTutorials.com


All Rights Reserved 1
http://www.MyInternetTutorials.com

and returns a variable $mailer that we can use to access the database directly throughout the script.The next few
sections list the functions that we declare before we get to the code that calls them.
 

function GetSQLValueString($theValue, $theType, $theDefinedValue = "",


$theNotDefinedValue = "")
{
$theValue = (!get_magic_quotes_gpc()) ? addslashes($theValue) : $theValue;
switch ($theType) {
case "text":
$theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
break;
case "long":
case "int":
$theValue = ($theValue != "") ? intval($theValue) : "NULL";
break;
case "double":
$theValue = ($theValue != "") ? "'" . doubleval($theValue) . "'" : "NULL";
break;
case "date":
$theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL";
break;
case "defined":
$theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue;
break;
}
return $theValue;
}

 
This function checks the user supplied variables to make sure they aren't malicious. And typecasts the submission
to the type expected by the database.
 

$dodgy_strings = array(
"content-type:"
,"mime-version:"
,"multipart/mixed"
,"bcc:"
);

function contains_bad_str($str_to_test) {
$bad_strings = array(
"content-type:"
,"mime-version:"
,"multipart/mixed"
,"Content-Transfer-Encoding:"
,"bcc:"
,"cc:"
,"to:"
);

foreach($bad_strings as $bad_string) {
if(eregi($bad_string, strtolower($str_to_test))) {
echo "$bad_string found. Suspected injection attempt - mail not being sent.";
exit;
}
}

©2007 Michael Suddes - MyInternetTutorials.com


All Rights Reserved 2
http://www.MyInternetTutorials.com

function contains_newlines($str_to_test) {
if(preg_match("/(%0A|%0D|\\n+|\\r+)/i", $str_to_test) != 0) {
echo "newline found in $str_to_test. Suspected injection attempt - mail not being sent.";
exit;
}
}

 
These three functions are more of the safeties against malicious attacks. First we define an array of strings we don't
want in our database. Next, the function will compare a string to this list to see if it contains the forbidden strings.
The next function will check to see if the submitted information includes newlines, these can also indicate a
malicious attack.
 

function is_valid($email){
$qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]';
$dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]';
$atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c'.
'\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+';
$quoted_pair = '\\x5c[\\x00-\\x7f]';
$domain_literal = "\\x5b($dtext|$quoted_pair)*\\x5d";
$quoted_string = "\\x22($qtext|$quoted_pair)*\\x22";
$domain_ref = $atom; $sub_domain = "($domain_ref|$domain_literal)";
$word = "($atom|$quoted_string)"; $domain = "$sub_domain(\\x2e$sub_domain)*";
$local_part = "$word(\\x2e$word)*"; $addr_spec = "$local_part\\x40$domain";
return preg_match("!^$addr_spec$!", $email) ? 1 : 0;

}
 
This function is specifically to check if the email address is plausibly valid, I tried some different routines that
check the actual address by contacting the domains mail server, but that's a lot of server load. If you give some
incentive to put in a correct email address, like freebies in the email, then you stand a much better chance of
getting a valid email.
 

if (!(empty($_POST))){
$email = GetSQLValueString($_POST['email'], "text");
$name = GetSQLValueString($_POST['name'], "text");

if (!is_valid($email)) {
echo 'Invalid email submitted - mail not being sent.';
exit;
}
contains_bad_str($email);
contains_bad_str($name);
contains_newlines($email);
contains_newlines($name);
}
 
Now we are getting into the code. This first section is an if loop that checks to see if the post variable from the
form has data in it. If it does it proceeds to load the data into variables $name and $email. As we do this, we send

©2007 Michael Suddes - MyInternetTutorials.com


All Rights Reserved 3
http://www.MyInternetTutorials.com

the data to the GetSQLValueString function we described above with the data type we want it converted to. Next,
we send the email address to the is_valid function to check the email address. We embed this in an if statement so
that if the email isn't valid, we print an error message and exit the program.
The next four lines send the data to the other validator functions we looked at earlier, the functions have built in
mechanisms that print an error messages and exit the program if an error occurs. If some of this seems
inconsistent, it is. Mainly becausen I found these functions on other tutorial and sample code sites and used them
here. Good programmers write their own code, great programmers steal great code.
 

$editFormAction = $_SERVER['PHP_SELF'];
if (isset($_SERVER['QUERY_STRING'])) {
$editFormAction .= "?" . htmlentities($_SERVER['QUERY_STRING']);
}
 
As I mentioned above when I showed the code for the form, the script constructs the action for the form
dynamically. $_SERVER['PHP_SELF'] is a system variable you can use in any php script to get the name and path
of the script. We then check to see if the query string is set and add that to the variable if it is set. This preserves
data from one page to another in certain cases. In this case it isn't necessary, but good programming habit.
 

if ((isset($_POST["MM_insert"])) && ($_POST["MM_insert"] == "form1")) {


$dstamp = date("Y-m-d H:i:s");
$insertSQL = sprintf("INSERT INTO info (name, email, date) VALUES (%s, %s, '$dstamp')",
GetSQLValueString($_POST['name'], "text"),
GetSQLValueString($_POST['email'], "text"));
mysql_select_db($database_mailer, $mailer);
if(mysql_query($insertSQL, $mailer) ){
}
 
This segment begins by checking the hidden field from the form and whether it is the correct form. Once again this
is Dreamweaver's setup in case of multiple forms and actions in a single script. If both of these conditions are true,
we drop into the script. We get todays date and current time from the date() function, in an easy to read format.
Now we have the three pieces of data for the record: the users name, email address, and the datestamp. We
construct the SQL statement and place it into the variable $insertSQL. Next, we tell mySQL which database we're
using with the mysql_select_db function.
Next, we run the query on the database with the mysql_query function feeding it the $insertSQL variable we built
earlier, and the database variable $mailer. The if statement checks the result of mysql_query. If it returns true then
we do nothing and contnue the script. This next code section covers what we do if it fails.
 

else{
echo "<h2>Sorry, we don't allow duplicate email adresses in the database.<BR>";
echo "Please use your back button to go back and try again.<BR>";
echo "Thanks!</h2>";
die(mysql_error());
}
mailit ();

 
This is the second part of the if statement outlined above, its what happens if the if statement returns the value of
false because of an error. The only likely common error is a duplicate email address since we've already checked
other malicious entries in the preceeding code. ( You would be amazed at how many people put their information

©2007 Michael Suddes - MyInternetTutorials.com


All Rights Reserved 4
http://www.MyInternetTutorials.com

in two or even three time for some reason! )


If someone enters an email address that already exists in the database, mySQL won't insert the record and returns
false as the result. When this happens, the above code prints the error message and exits. The die(mysql_error())
function prints the actual error code from mySQL for debugging purposes.
So yes, we are making an assumption that the error is a duplicate email address. Not the best programming
practice, but we can add more error checking here in the future.
The next function we call is mailit(), this function will take a bit to explain, as it emails the thankyou message and
the free report. Before we get to that, we have a few more lines of code to cover.
 

$insertGoTo = "join.html";
if (isset($_SERVER['QUERY_STRING'])) {
$insertGoTo .= (strpos($insertGoTo, '?')) ? "&" : "?";
$insertGoTo .= $_SERVER['QUERY_STRING'];
}
header(sprintf("Location: %s", $insertGoTo));

 
This section creates a redirect header to send the user to your thank you or download page. It also checks to see if
there's a query string to pass along to the new page and adds it to the redirect. Then it prints the header which send
the subscribers browser to the new page. This basically ends the form handling section of the code. But we have
the mailit() function to explore before we're done.
 

function mailit(){
$name = $_POST["name"];
$email = $_POST["email"];
$to = "$name <$email>";
$from = "FastEasyWorkouts.com <webmaster@fasteasyworkouts.com>";
$subject = "Here is your requested information from FastEasyWorkouts.com";
$fileatt = "thermogenicfoods.pdf";
$fileatttype = "application/pdf";
$fileattname = "thermogenicfoods.pdf";
$headers = "From: $from";
 
We just called this function, and now lets step through the code. We load in the name and email into variables and
then declare several other variables needed to send to the email program. $to, $from, and $subject are self
explanatory. The next three variables are needed for the file we're attaching to the email. $fileatt is the path and
local name of the file. $fileatttype is the mime code for the file type. $fileattname is the name you want the file to
have when you attach it. We also declare the $headers variable, we'll be adding more to it in the next section.
 

$file = fopen( $fileatt, 'rb' );


$data = fread( $file, filesize( $fileatt ) );
fclose( $file );

$semi_rand = md5( time() );


$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";

$headers .= "\nMIME-Version: 1.0\n" .


"Content-Type: multipart/mixed;\n" .
" boundary=\"{$mime_boundary}\"";

©2007 Michael Suddes - MyInternetTutorials.com


All Rights Reserved 5
http://www.MyInternetTutorials.com

 
Here we open the file for reading with fopen which returns a variable that points to the open file. Then we use
fread to load the actual data into $data. To keep things cleaned up and neat we then use fclose to close the file and
free up the memory.
Next we create a large random number that acts as a bookend for the attached file data. We declare the rest of the
bookend as $mime_boundary. This will be used in several places. Now we add this to $headers with the required
mime protocols of mime version, type of email which is multipart/mixed, and what the boundary code is.
 

$message = "This is a multi-part message in MIME format.\n\n" .


"--{$mime_boundary}\n" .
"Content-Type: text/plain; charset=\"iso-8859-1\"\n" .
"Content-Transfer-Encoding: 7bit\n\n" .

$message .= "Thank you!\n\n" .


"Your requested information is included in this email.\n".
"For any questions, please feel free to email us at\n".
"webmaster@fasteasyworkouts.com\n\n";

$message .= "To access the signup page directly please use the link below:\n\n" .
"http://fasteasyworkouts.com/amember/signup.php\n\n".
"To see the information page again please use this link:\n\n".
"http://www.fasteasyworkouts.com/join.html\n\n\n\n";
 
This is a large chunk of code but very simple, so bear with me. We start by declaring the $message variable. Please
make note of the "\n" newlines and the concatenation periods between quotation marks. we could put all of this in
one big quote, but this is easier to read. The newlines are important, note where there are one, and where there are
two at the top of the message, this is important, as the email programs look for these. Everything before the Thank
you! is telling the email program that this is a mime message and we're starting with a text segment.
After this we write our message. I wanted double spacing for this message so you will see lots of double newlines
in my text. At the end of my message there's four newlines to make some space for the attachment.
 

$data = chunk_split( base64_encode( $data ) );

$message .= "--{$mime_boundary}\n" .
"Content-Type: {$fileatttype};\n" .
" name=\"{$fileattname}\"\n" .
"Content-Disposition: attachment;\n" .
" filename=\"{$fileattname}\"\n" .
"Content-Transfer-Encoding: base64\n\n" .
$data . "\n\n" .
"--{$mime_boundary}--\n";
 
This section adds the next part of the message. First we split the file and encode it to plain text so it can be sent in
the email with chunk_split( base64_encode( $data ) ). Then we add the headers, the data, and the final bookend.
 

if( mail( $to, $subject, $message, $headers ) ) {

}
else {
echo "<p>There was an error sending the mail.</p>";

©2007 Michael Suddes - MyInternetTutorials.com


All Rights Reserved 6
http://www.MyInternetTutorials.com

exit;
}
}
 
As we send the email message using mail(), a built in php functionality, we check and make sure it sends properly
with the if statement. If mail() returns true we don't do anything and we go back to where the function was called.
If an error occurs, we print an error message and exit the program.
 
Autoresponder script
Now that we have a way to get names and addresses into the database, we need to get them out and send messages
to them. In the last section, we inserted the name and email into the database, datestamped the record, and set their
message counter to zero. Now, we need to compare their datestamp to today to see how many days they've been in
the system and send the appropriate message if any. If we send a message, we increment their counter.
Those of you who have used Dreamweaver will recognize some of the code here, I use their utilities to access the
mySQL database.
Ready? Here we go:

<?php
$hostname_mailer = "localhost";
$database_mailer = "database";
$username_mailer = "user";
$password_mailer = "password";
$mailer = mysql_pconnect($hostname_mailer, $username_mailer, $password_mailer) or die
(mysql_error());
 
This code serves the same function as the identical section in the form script above.
 

mysql_select_db($database_mailer, $mailer);
$query_Recordset1 = "SELECT * FROM info";
$Recordset1 = mysql_query($query_Recordset1, $mailer) or die(mysql_error());
$row_Recordset1 = mysql_fetch_assoc($Recordset1);
$totalRows_Recordset1 = mysql_num_rows($Recordset1);
?>
 
In the first line we tell mySQL which database we're using. In the next line we use a variable to hold our mySQL
query. The query tells mySQL to SELECT all the fields from the table named info. We then feed this variable and
the variable for the database to mysql_query. This returns a variable or, if an error occurs, ends the script.
In the absence of an error, the next two rows fetch a variable for the first record in the query, and the total number
of records returned by the query. The ?> tag closes the php script so we can handle some plain html.
 
<html >
<head>
<title>Autoresponder</title>
</head>
<body>
 
Just basic html headers, no meta tags are necessary because its for our use only, not for the public.
 

©2007 Michael Suddes - MyInternetTutorials.com


All Rights Reserved 7
http://www.MyInternetTutorials.com

<?php
$count = 0;
function elapsedDays($dt)
{
$yr=strval(substr($dt,0,4));
$mo=strval(substr($dt,5,2));
$da=strval(substr($dt,8,2));
$hr=strval(substr($dt,11,2));
$mi=strval(substr($dt,14,2));
$se=strval(substr($dt,17,2));
$time = mktime($hr,$mi,$se,$mo,$da,$yr);

$diff = time()-$time;
return floor($diff/60/60/24);
}
 
This section starts by re-opening the php script, then we initialize a counter to track how many record we process.
Next, we have a function that converts the date format we use in the database as a timestamp to UNIX time, and
calculates the difference in days between when the record was entered and now. The function returns the number
of elapsed days to the part of the script that called it.
 

do {
$time1 = $row_Recordset1['date'];
$days = elapsedDays($time1);
$query_message = "SELECT * from messages WHERE sequence = $days";
$Recordset2 = mysql_query($query_message, $mailer) or die(mysql_error());
 
The first line starts a loop that will continue until al the records are processed. Next, we get the elapsed days for the
current record. Once we have the elapsed days we query the database to see if there's a message that corresponds
to the number of elapsed days.
 

if (($row_Recordset2 = mysql_fetch_assoc($Recordset2)) && ($row_Recordset1['sequence'] !


= $days)){

$name = $row_Recordset1['name'];
$email = $row_Recordset1['email'];
$from = "FastEasyWorkouts.com <webmaster@fasteasyworkouts.com>";
$headers = "From: $from";

 
First we check to see if there was a message that matched our records elapsed days, and that the sequence of the
message matches the sequence of the record as a safeguard to sending the same message twice. If all these factors
are in place, we pull al the fields from the message record and proceed to process the record. We pull the records
name and email address and put them in $name and $email variables respectively. We assign our from information
as well.
 

$message = preg_replace("/\{([^\{]{1,100}?)\}/e","$$1", $row_Recordset2['message']);

©2007 Michael Suddes - MyInternetTutorials.com


All Rights Reserved 8
http://www.MyInternetTutorials.com

$subject = $row_Recordset2['subject'];
$recepient = "$name <$email>";

if( mail( $recepient, $subject, $message, $headers) ) { }

else { echo "<p>There was an error sending the mail.</p>"; }

echo "Processing record #$count, sending message #$days to $email<BR>";

 
This section starts with probably the most difficult piece of code in the entire script. Its called a regular expression,
and its one of the most difficult types of code to learn. Suffice it to say that this line of code replaces anything in
curly brackets with the contents of a variable with the same name. Example in the stored message text {name}
would be replaced by the contents of variable $name. This same line places the modified message into the variable
$message.
Next, we place the message subject from the database into a variable, as well as the email address of the
subscriber.
Now all of the proper parts are in place and we can send them to the mail() function, this uses sendmail on your
server to send the message. We put it inside an if statement to make sure it doesn't throw an error. If it does, we
print an error message and continue. The last line in this section prints an informational message telling us what
message was sent to whom. This line could be commented out on larger lists.
 

$query_message = "UPDATE `info` SET `sequence` = '$days' WHERE `name` = '$name'


AND `email` = '$email' LIMIT 1 ";
$Recordset3 = mysql_query($query_message, $mailer) or die(mysql_error());

mysql_free_result($Recordset2);

$count = $count + 1;
}

} while ($row_Recordset1 = mysql_fetch_assoc($Recordset1));

 
We're almost done! In this section we take care of housekeeping and close the processing loop. The first line
updates the sequence field in the subscribers record to confirm we sent that particular message to that address.
mysql_free_result releases the address to the queried record to free up memory. Then we update the counter to
track the total number of messages we're sending.
The first curly bracket closes the if statement from above where we checked to see if there was a message to send.
And, the second curly bracket closes the do loop that processes each email record. You can see the while statement
that will continue this loop until we run out of email records. After this we'll finish up and close the script.
 

mysql_free_result($Recordset1);

©2007 Michael Suddes - MyInternetTutorials.com


All Rights Reserved 9
http://www.MyInternetTutorials.com

echo "<BR><HR><BR>Processing done. Processed $count messages.";


?>
</body>
</html>

 
This section releases the mySQL query with all of the email records, reports the total number of records processed
from our counter, and closes the body and html tags. Thats it, one simple autoresponder.
Now, I'm going to show you the code that will create the mySQL tables needed for this script to work.
 

CREATE TABLE `info` (


`name` varchar(50) NOT NULL default '',
`email` varchar(50) NOT NULL default '',
`sequence` int(11) NOT NULL default '0',
`key` int(11) NOT NULL auto_increment,
`date` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`key`),
UNIQUE KEY `email` (`email`)
) TYPE=MyISAM;

CREATE TABLE `messages` (


`message_ID` int(11) NOT NULL auto_increment,
`subject` text NOT NULL,
`message` text NOT NULL,
`sequence` int(11) NOT NULL default '0',
UNIQUE KEY `sequence` (`sequence`),
KEY `message_ID` (`message_ID`)
) TYPE=MyISAM;

 
These two statements create the mySQL tables you will need to store the data. If you don't know if your server has
mySQL, or how to create a database, I suggest you contact your hosting company and check with them. As I
mentioned above, I am planning a mySQL tutorial, and I will cover things like this.
Installation

©2007 Michael Suddes - MyInternetTutorials.com


All Rights Reserved 10

You might also like