Home Archive RSS Login

I learned something new today

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.

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";
    }
  }


Things to remember:

  1. 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.
  2. The CHMOD of the script must be 755 (executable). Again, the mails kept bouncing back when the permissions on the script where not 755.
I have only written steps applicable for websites hosted on cPanel, with email forwarding to pipe enabled and PHP programs. Hope this helps some of you.

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.


Author: Prit -  Date: 05 May 2009 12:36
Tags: programming,pritlog,web -  Visits: 94543 -  No Comments




Comments

No comments posted yet!


Add Comment

Comment Form

 (Required)

 (Optional, will not be published)

 (Optional, format: http(s)://website.com)



 (w8og18ju)