PHP script to handle incoming mails using pipes
I recently came across this blogging service called "Posterous". The feature that caught my attention was this: You can send mails to a particular email address and it would get automatically posted onto the blog as a post. I had heard about something similar in Wordpress couple of years ago.I started doing my research on how this could be done. In this post, I try to document the steps that were involved and any challenges I faced doing this.
What can this be used for?
- Such a script could handle the auto subscribe or unsubscribe to or from a mailing list
- To write and manage a full mailing list application
- To send commands to your site or scripts using emails
- To post on a blog as I did
- ...... (your imagination is the limit)
Step 1:
Add an email forwarder in your cPanel. Under the email section, you will find "forwarders". Click on this and you will be able to add email forwarders. When you add a forwarder, there will be an option to "pipe to a program". Choose this and add the full path to your php script that will be handling the mails. This program should have permissions of 755 to be executable. I wasted some significant time because I forgot this.


Step 2:
Now, you can start writing your program to handle the mails. It will look like this: (this script is taken from this post.)
#!/usr/bin/php -q
<?php
ob_start();
// read from stdin
$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd)) {
$email .= fread($fd, 1024);
}
fclose($fd);
// handle email
$lines = explode("n", $email);
// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;
for ($i=0; $i < count($lines); $i++) {
if ($splittingheaders) {
// this is a header
$headers .= $lines[$i]."n";
// look out for special headers
if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) {
$subject = $matches[1];
}
if (preg_match("/^From: (.*)/", $lines[$i], $matches)) {
$from = $matches[1];
}
if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
$to = $matches[1];
}
} else {
// not a header, but message
$message .= $lines[$i]."n";
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$splittingheaders = false;
}
}
ob_end_clean();
?>
When you have completed Step 1 and Step 2, the script will run when the mail arrives and reads and parses the mail. <?php
ob_start();
// read from stdin
$fd = fopen("php://stdin", "r");
$email = "";
while (!feof($fd)) {
$email .= fread($fd, 1024);
}
fclose($fd);
// handle email
$lines = explode("n", $email);
// empty vars
$from = "";
$subject = "";
$headers = "";
$message = "";
$splittingheaders = true;
for ($i=0; $i < count($lines); $i++) {
if ($splittingheaders) {
// this is a header
$headers .= $lines[$i]."n";
// look out for special headers
if (preg_match("/^Subject: (.*)/", $lines[$i], $matches)) {
$subject = $matches[1];
}
if (preg_match("/^From: (.*)/", $lines[$i], $matches)) {
$from = $matches[1];
}
if (preg_match("/^To: (.*)/", $lines[$i], $matches)) {
$to = $matches[1];
}
} else {
// not a header, but message
$message .= $lines[$i]."n";
}
if (trim($lines[$i])=="") {
// empty line, header section has ended
$splittingheaders = false;
}
}
ob_end_clean();
?>
You can now use the variables, $to, $headers, $subject and $message and process as you require. Maybe use php mail to send them back an email or store it on a database. For the purposes of Pritlog hosted site, I do some validations and store this in the database.
Step 3: (Only required if you need better message parsing)
One challenge I had was that the above script was not parsing the message well, especially when the message had multi-parts (text, html etc). I found this php class called "Mime email message parser".What I did is to write the full message (not parsed one) from the above step into a file and let the mime message parser class do the correct parsing. During my tests from several different email id's, this class parsed the mail correctly.
Here is the code for this.
$file = 'tempmail.txt';
$current = $email;
file_put_contents($file, $current);
require_once('mimeparser/rfc822_addresses.php');
require_once('mimeparser/mime_parser.php');
$message_file=((IsSet($_SERVER['argv']) && count($_SERVER['argv'])>1) ?
$_SERVER['argv'][1] : $file);
$mime=new mime_parser_class;
$mime->mbox = 1;
$mime->decode_bodies = 1;
$mime->ignore_syntax_errors = 1;
$parameters=array(
'File'=>$message_file,
'SkipBody'=>0,
);
if(!$mime->Decode($parameters, $decoded))
echo 'MIME message decoding error: '.$mime->error.' at position
'.$mime->error_position."rn";
else
{
for($message = 0; $message < count($decoded); $message++)
{
if($mime->Analyze($decoded[$message], $results)) {
$message = $results["Data"];
}
else
echo 'MIME message analyse error: '.$mime->error."rn";
}
}
$current = $email;
file_put_contents($file, $current);
require_once('mimeparser/rfc822_addresses.php');
require_once('mimeparser/mime_parser.php');
$message_file=((IsSet($_SERVER['argv']) && count($_SERVER['argv'])>1) ?
$_SERVER['argv'][1] : $file);
$mime=new mime_parser_class;
$mime->mbox = 1;
$mime->decode_bodies = 1;
$mime->ignore_syntax_errors = 1;
$parameters=array(
'File'=>$message_file,
'SkipBody'=>0,
);
if(!$mime->Decode($parameters, $decoded))
echo 'MIME message decoding error: '.$mime->error.' at position
'.$mime->error_position."rn";
else
{
for($message = 0; $message < count($decoded); $message++)
{
if($mime->Analyze($decoded[$message], $results)) {
$message = $results["Data"];
}
else
echo 'MIME message analyse error: '.$mime->error."rn";
}
}
Things to remember:
- The #!/usr/bin/php -q at the beginning of your script is very important. The "-q" supresses output. My initial attempts were failing and took a long time for me to figure this one out. If it had any sort of outputs or warnings, then the mail would bounce back. When I did this, it stopped bouncing back.
- The CHMOD of the script must be 755 (executable). Again, the mails kept bouncing back when the permissions on the script where not 755.
The outcome of this experiment is that now Pritlog.com users can send mails to post on their blogs. Hurray!!
Please feel free to post any comments, suggestions or questions.
Tags: programming,pritlog,web - Visits: 1094 - Comments: 1
Plugin system for Pritlog
A plugin system enables external users or members of the community to add functionality to the software without even touching a single line from the main software program.Pritlog needed a plugin system and that too a very efficient and lightweight one. I found the plugin system called "Simple Hooks Plugin" from Phpclass website. The link is http://phpclasses.betablue.net/browse/package/4497.html.
I will mention some details of how it is implemented.
Firstly, the main program needs to initialize the plugins. It can be done like this:
//include Simple Hooks Plugin Class
$SHP = new SHP();
//set hook to which plugin developers can assign functions $SHP->developer_set_hook('hook-test');
$SHP = new SHP();
//set hook to which plugin developers can assign functions $SHP->developer_set_hook('hook-test');
Second, the main program needs to define what is called hooks. These are basically points in the main program where the developer wants external plugins to attach and execute. This code can look like this:
<html>
<head>
<title>Testing the plugins</title>
</head>
<body>
<?php
//Initialize the plugin
include "SHP.class.php";
$SHP = new SHP();
$SHP->developer_set_hook('hook-test');
echo "<h1>Simple Hooks Plugin</h1>";
$SHP->execute_hooks('hook-test');
?>
</body>
</html>
<head>
<title>Testing the plugins</title>
</head>
<body>
<?php
//Initialize the plugin
include "SHP.class.php";
$SHP = new SHP();
$SHP->developer_set_hook('hook-test');
echo "<h1>Simple Hooks Plugin</h1>";
$SHP->execute_hooks('hook-test');
?>
</body>
</html>
In the above piece of code, the developer has provided a hook called hook-test where external plugins can attach and execute. Now let us look at a simple plugin.
//set plugin id as file name of plugin
$plugin_id = basename(__FILE__);
//some plugin data
$data['name'] = "Name of the plugin";
$data['author'] = "Authors Name";
$data['desc'] = "Brief description of the plugin";
$data['url'] = "Plugin/Author website";
//register the plugin
register_plugin($plugin_id, $data);
//plugin function
function test_function() {
echo 'echoed from plugin';
}
//add hook, where to execute a function
add_hook($plugin_id, 'hook-test','test_function');
echo "Plugin 1 LOADED!"; //code to execute when loading plugin
$plugin_id = basename(__FILE__);
//some plugin data
$data['name'] = "Name of the plugin";
$data['author'] = "Authors Name";
$data['desc'] = "Brief description of the plugin";
$data['url'] = "Plugin/Author website";
//register the plugin
register_plugin($plugin_id, $data);
//plugin function
function test_function() {
echo 'echoed from plugin';
}
//add hook, where to execute a function
add_hook($plugin_id, 'hook-test','test_function');
echo "Plugin 1 LOADED!"; //code to execute when loading plugin
When the main program runs, this plugin is picked up and the final output from the program would be:
Plugin 1 LOADED!
<h1>Simple Hooks Plugin</h1>
echoed from plugin
See how the code from the plugin got executed in the main program even without touching a single line of code from the main program.
In Pritlog, I modified the plugin system so that the user can enable or disable a plugin at will.
This was a very interesting and exciting experiment for me.
Tags: pritlog,web - Visits: 378 - No Comments
Testimony: God saved me from destruction
It was my birthday and I was driving on the highway 101 from Woodland Hills to Westlake Village. I must have been going at pretty good speed and all of a sudden, when I was nearing Agoura Hills, a red car from two lanes away started changing lanes. Within no time, it was almost half into my lane. It was in an instant and I just steered a little to the right and missed a major accident. By God's grace, there was no car in the lane on my right. I was in shock for sometime and I think the folks in the red car would have been in the same situation as I could see them going extremely slow after this incident.I thank my God for protecting me continuously even though I have not been very faithful to Him many times.
Few weeks ago, one of amy friends was sharing this - "since you actually witnessed an incident where God protected you supernaturally, you think - wow God is protecting you .. What about the millions of other instances when God is protecting and caring for you and you never see it because He has prevented an accident or a harmful condition much before it ever came near you." This really made me think and hope will make you think too.
Psalms 103:
1 Bless the LORD, O my soul;
And all that is within me, bless His holy name!
2 Bless the LORD, O my soul,
And forget not all His benefits:
3 Who forgives all your iniquities,
Who heals all your diseases,
4 Who redeems your life from destruction,
Who crowns you with lovingkindness and tender mercies,
5 Who satisfies your mouth with good things,
So that your youth is renewed like the eagle’s.
Tags: testimony - Visits: 321 - No Comments
Create subdomains in PHP
When I started receiving more and more requests for installing Pritlog on my server for different folks, I wanted to think of a better solution than just installing a separate Pritlog copy to each individual and put them in separate sub directories. This can cause any modification or updations to all these different installations to be a very time consuming task.This is when I started thinking about the possibility of modifying Pritlog in such a way that a single installation could handle multiple blogs and these blogs can be in separate subdomains - similar to how it works in Blogspot and few other sites.
First task was to create sub domains dynamically using PHP. Usually, sub domains can be created from the control panel provided by your hosting provider. But, this is a manual task. I did some searching through the net and came across some articles that talked about using a XML API provided by cPanel (hosting control panel) that could be used. My delicious link below has the bookmarks I made during my research.
http://delicious.com/prithish/subdomain
But, none of the API solutions worked for me. I was trying this on my hosting account with Hostmonster. Finally, the below solution worked for me.
The original discussion link:
http://www.webmasterworld.com/forum88/8746.htm
The steps that actually helped me.
Step 1: First you need to set
your main domain to act as a catch-all subdomain. its like putting
ServerAlias * so that each subdomain which is requested to the main domain reaches the same place. I mean if your main domain root is
/home/admin/abc.com/htdocs/
then your catch-all setup shall send all sub-domain requests to that same directory
/home/admin/abc.com/htdocs/
Initially, I could not figure out how to do it in Hostmonster. Finally, I found the solution somewhere that said, we could add a subdomain called '*' and make it direct to the root of the domain. This way, my domain became a catch all domain.
Step 2: You'd add this code to very top of your index page right after ""
$domain = $_SERVER['HTTP_HOST'];
$domain_parts = explode('.',$domain);
if (count($domain_parts) == 3 && $domain_parts[0]!= "www") {
// make sure a subdomain is called
$user = $domain_parts[0];
$loc = "http://domain.tld/whateverpage.ext?varname=$user";
@header("Location:$loc");
}
$domain_parts = explode('.',$domain);
if (count($domain_parts) == 3 && $domain_parts[0]!= "www") {
// make sure a subdomain is called
$user = $domain_parts[0];
$loc = "http://domain.tld/whateverpage.ext?varname=$user";
@header("Location:$loc");
}
What this step is basically saying is when the domain is a catch all domain, all requests to any subdomains will come to the index files of the root domain. You can add this code to parse the data in the requested url and figure out what subdomain was requested and use "header" function from within your index script to handle the redirection.
I am now using this to provide hosted Pritlog. Here are some links to check this out.
http://mathew.pritlog.com/
http://tania.pritlog.com/
http://blakley.pritlog.com/
If anything on this post is not clear, please feel free to post a comment requesting clarification.
Tags: web - Visits: 2277 - Comments: 4
Testimony: Peace in the flight
Few weeks ago, we had to travel to a Oklahoma city to meet with our pastor from India. He was visiting here for a convention.Our son is a very active kid. He loves to run around and doesnt like to be constrained in a place. My wife had thought and planned very well to make sure that my son would be calm and quiet in the flight. She purchased all kinds of fun things and toys and drawing stuff so that he could be kept in one place.
We surrendered every detail of the trip to Jesus and started the journey. After all the procedures, we finally boarded the flight. After the flight took off, I looked at my son who was sitting near my wife in the adjacent set of seats. He was sleeping away. Just few minutes ago when we boarded the flight, he was very active. I was surprised. It was as if he was drugged. :). He slept throughout the journey. We could not ask for more from our Lord. The times he did not sleep, he would be just focusing on scribbling something on the drawing board. We were so excited and grateful for the way God takes care of us in spite of our shortcomings.
Even our return journey was blessed by God. My son was sleeping most of the time and it was very peaceful. It was like a dream.
Jeremiah 32:27
“Behold, I am the LORD, the God of all flesh. Is there anything too hard for Me?
Tags: testimony - Visits: 320 - No Comments