Bulk Email Script in PHP and MySQL Database

In this post, I will show you how we can send an email to multiple receivers using simple PHP script. This script also shows how we can send bulk if we have server limitation on number of emails can be sent in period of time.  Many web hosting provider do not support bulk emails so I have set this script to come out of this limitation.

This Bulk Email script can send HTML email. You can also use this script to send promotional and marketing emails.

In this tutorial we will create three files. First file is HTML content of email, second file is the actual code which sends emails to multiple address one at a time and third file is allowing receivers to unsubscribe from email list.


<p>Hello there</p>
<p>This is sample email file</p>



$con = mysql_connect("localhost","dbuser","dbpass"); // replace dbuser, dbpass with your db user and password
mysql_select_db("dbname", $con); // replace dbname with your database name
To use this script database table must have three fields named sno, email and sub_status
$query = "select sno, email from dbtable where sub_status = 'SUBSCRIBED'";
$result = mysql_query($query, $con);
$emails = array();
$sno = array();
	$sno[] = $row['sno']; // this will be used to unsubscribe the user
	$emails[]=$row['email']; // email id of user
/* you can also get email id data from CSV using below code */
//$file =  file_get_contents("travel_database.csv"); 
//$emails = explode(",",$file);

/* count.txt is used to store current email sent number/count */
$count =  file_get_contents("count.txt");
	$to  = $emails[$i];

	// subject
	$subject = 'Set Your Title Here';

	// message
	$message = file_get_contents("sample.html"); // this will get the HTML sample template sample.html
	$message .= '<p><a href="http://yourdomain.com/path-to-folder/unsubscribe.php?id='.$sno[$i].'&username='.$emails[$i].'">Please click here to unsubscribe.</a></p>
	// To send HTML mail, the Content-type header must be set
	$headers  = 'MIME-Version: 1.0' . "\r\n";
	$headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";

	// Additional headers
	//$headers .= "To: $to" . "\r\n";
	$headers .= 'From: Name <info@yourdomain.com>' . "\r\n";
	//$headers .= 'Cc: sendcc@yourdomain.com' . "\r\n";
	//$headers .= 'Bcc: sendbcc@yourdomain.com' . "\r\n";

	// Mail it
	if(mail($to, $subject, $message, $headers)) {
		$file = fopen("mailsentlist.txt","a+"); // add email id to mailsentlist.txt to track the email sent
		fwrite($file, $to.",\r\n");
		$file = fopen("notmailsentlist.txt","a+"); // add email to notmailsentlist.txt here which have sending email error
		fwrite($file, $to.",\r\n");

	if(($i-$count)>=200) // this will send 200 mails from database per execution
		$filec = fopen("count.txt",'w'); // store current count to count.txt
		fwrite($filec, $i);
}//for end
$filec = fopen("count.txt",'w'); // store fine count to count.txt this will be used as a start point of next execution
fwrite($filec, $i);

Replace “http://yourdomain.com/path-to-folder/” with your path to unsubscribe.php

You can set the cron job on sendmail.php on particular time frame. For example if you hosting provider support only 100 mail per hour than you can set cron job par hour and update the value here

if(($i-$count)>=100) // update this in code of sendmail.php


$con = mysql_connect("localhost","dbuser","dbpass");
mysql_select_db("dbname", $con);

$sno = (integer)$_GET['id'];
$email = mysql_real_escape_string($_GET['username']);

$query = "update tablename set sub_status = 'UNSUBSCRIBED' where sno = $sno and email = '$email'";
echo "You have Successfully unsubscribed. Thank you for using the service.";


Comment here if you have any queries. 

Email Crawler Script PHP MySQL

This script is useful for crawling the emails from the website in recursive manner. this is really very easy class to call and starting crawling emails.

Note: I found it somewhere on internet. I put it here for my future reference. It also useful to people who wants this type of script.


Written by: Aziz S. Hussain 
Email: azizsaleh@gmail.com 
Website: www.azizsaleh.com 
Produced under GPL License 
Email address scraper based on a URL.
class scraper
	// URL that stores first URL to start
	var $startURL; 

	// List of allowed page extensions
	var $allowedExtensions = array('.css','.xml','.rss','.ico','.js','.gif','.jpg','.jpeg','.png','.bmp','.wmv','.avi','.mp3','.flash','.swf','.css'); 

	// Which URL to scrape
	var $useURL; 

	// Start path, for links that are relative
	var $startPath; 

	// Set start path
	function setStartPath($path = NULL){
		if($path != NULL)
			$this->startPath = $path;
		} else {
			$temp = explode('/',$this->startURL);
			$this->startPath = $temp[0].'//'.$temp[2];

	// Add the start URL
	function startURL($theURL){
		// Set start URL
		$this->startURL = $theURL;

	// Function to get URL contents
	function getContents($url)
		$ch = curl_init(); // initialize curl handle
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_VERBOSE, 0);
		curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
		curl_setopt($ch, CURLOPT_AUTOREFERER, false);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,7);
		curl_setopt($ch, CURLOPT_REFERER, 'http://'.$this->useURL);
		curl_setopt($ch, CURLOPT_URL,$url); // set url to post to
		curl_setopt($ch, CURLOPT_FAILONERROR, 1);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);// allow redirects
		curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // return into a variable
		curl_setopt($ch, CURLOPT_TIMEOUT, 50); // times out after 50s
		curl_setopt($ch, CURLOPT_POST, 0); // set POST method
		$buffer = curl_exec($ch); // run the whole process
		return $buffer;

	// Actually do the URLS
	function startScraping()
		// Get page content
		$pageContent = $this->getContents($this->startURL);
		echo 'Scraping URL: '.$this->startURL.PHP_EOL; 

		// Get list of all emails on page
		// Add the email to the email list array
		foreach($results[1] as $curEmail)
			$insert = mysql_query("INSERT INTO `emaillist` (`emailadd`) VALUES ('$curEmail')");

		echo 'Emails found: '.number_format($insertCount).PHP_EOL; 

		// Mark the page done
		$insert = mysql_query("INSERT INTO `finishedurls` (`urlname`) VALUES ('".$this->startURL."')"); 

		// Get list of new page URLS is emails were found on previous page
		$currentList = $this->cleanListURLs($results[1]); 

		// Add the list to the array
		foreach($currentList as $curURL)
			$insert = mysql_query("INSERT INTO `workingurls` (`urlname`) VALUES ('$curURL')");

		echo 'URLs found: '.number_format($insertURLCount).PHP_EOL;
		$getURL = mysql_fetch_assoc(mysql_query("SELECT `urlname` FROM `workingurls` ORDER BY RAND() LIMIT 1"));
		$remove = mysql_query("DELETE FROM `workingurls` WHERE `urlname`='$getURL[urlname]' LIMIT 1"); 

		// Get the new page ready
		$this->startURL = $getURL['urlname'];

		// If no more pages, return
		if($this->startURL == NULL){ return;}
		// Clean vars
		// If more pages, loop again

	// Function to clean input URLS
	function cleanListURLs($linkList)
		foreach($linkList as $sub => $url)
			// Check if only 1 character - there must exist at least / character
			if(strlen($url) <= 1){unset($linkList[$sub]);}
			// Check for any javascript
			// Check for invalid extensions
			if($count > 0){ unset($linkList[$sub]);}
			// If URL starts with #, ignore
			if(substr($url,0,1) == '#'){unset($linkList[$sub]);} 

			// If everything is OK and path is relative, add starting path
			if(substr($url,0,1) == '/' || substr($url,0,1) == '?' || substr($url,0,1) == '='){
			$linkList[$sub] = $this->startPath.$url;
		return $linkList;


 `emailadd` varchar(255) NOT NULL,
 PRIMARY KEY (`emailadd`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='List of all gotten emails';

 `urlname` varchar(255) NOT NULL,
 PRIMARY KEY (`urlname`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='List of finished urls';

 `urlname` varchar(255) NOT NULL,
 PRIMARY KEY (`urlname`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='List of current working urls';


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	$DB_USER = 'root';
	$DB_HOST = 'localhost';
	$DB_NAME = 'test';
	$dbc = mysql_connect ($DB_HOST, $DB_USER, $DB_PASSWORD) or $error = mysql_error();
	mysql_select_db($DB_NAME) or $error = mysql_error();
	mysql_query("SET NAMES `utf8`") or $error = mysql_error();
	if($error){ die($error);}


	$new = new scraper;
	// Start Path can be empty, which will be extracted from the start URL



Transfer MySQL Database Server to Server Using cPanel

Hello Friends,

Few days ago I have project to transfer MySQL Database from one server to another. I don’t want to use my internet bandwidth for this large database by downloading to my local computer and then uploading this to another server. Rather I was thinking of transferring this by one server to another.

Below is the syntax to do that.

[In Mysql Bin Folder]>mysqldump -h[source-hostname-or-IP] -u[username] -p[password] [Database-name] | mysql -h[destination-hostname-or-IP] -u[username]&nbsp;-p[password] [target-Database-name]

Before Using this you have to setup few thing in you local machine.

  • Install MySQL
  • Open command prompt.
  • Locate “bin” directory in MySQL Installation in Command Prompt
  • Create Database in Destination or Target Server
  • Make Remote Connection allowed on both Destination and Source Server.
  • fire command with your own parameter.

Please feel free to ask any question.

Thank you.


How to Improve MySQL Large Database Performance

Hello friends,

This is my first post for the blog. Recently I have worked on two large database projects on   backend MySQL Database. During the period of the project I came across with many problems and somehow I managed them all.

Many of you also came across with the same MySQL Database problem with Performance. Query is not running well etc. During this period  I read many blogs and forums to solve these problems. I have figured out some tips or can say some points which we should taken care of.

Database Engine (MYISAM vs. Innodb)

Both MySQL Database engines have its own pros and cons that we have to decide which type of db engine will work great for us. Below are some concerns with this two engines:


  • MYISAM use less memory
  • It allows full text search
  • It locks the table while writing
  • It is useful for application in which reading is high and fewer write


  • It uses more memory
  • It does not support full text search
  • InnoDB provides faster performance
  • It lock the table at row level while writing to the table
  • It works great for the application which make extensive use of read and write both


Good Database Design

Good database design is a backbone for the application performance. Bad design makes application performance less. Table must be normalized. Data Structure is the main factor which must be developed carefully. Every Developer must give time for each table and fields for making good design. You should give proper data type to each field. When you done with database creation, you would like to see what is MySQL suggest you for your database table. Here is the Command which can help you to get this information:

ANALYZE TABLE <table-name>;

You can find full description here: http://dev.mysql.com/doc/refman/5.5/en/analyze-table.html


What many of us is knowing that indexes help us to increase the speed of query. Many times indexes create confusion in mind. Creating of proper indexes for the table is necessary but do make table overhead of indexes as indexes take space on the disk. So it increases the workload on the disk. Working on my project I many time need to add and delete column from large table which takes so much time. For increasing performance we can make index ON of OFF. so before whenever I start my database operation I make the index key off and do the operation when operations completed I again makes indexes ON. So rather than making new indexes on my each operation, it will make new index when I male Index on so its only one time. for turning on and index I use below syntax:

Disable Indexes:  ALTER TABLE table_name DISABLE KEY
Enable Indexes: ALTER TABLE table_name ENABLE KEY


Tuning MySQL

Hardware makes as important role as other things in database tuning. Our hardware needs just as much attention and tuning as our database and script does. It is also need to check MySQL Configuration file what type of changes we have make to the configuration. There is one tool available which is perl script. You can download and Install on server It tells that which type of configuration change you can make improve the performance.


Note: This are the simple things which I feel good to use and take care for better performance.