Archive for the Web Programming Category

PHP Script for parsing inbound email and saving attachments to a web host

Posted in Social Networking, Web Programming with tags , , , , , , on July 18, 2008 by webzealot

Ever wondered how BrightKite, TwitPic, and some of these other Web 2.0 websites have managed to reverse engineer email?  It used to be that websites would send YOU email, but that’s not all that exciting anymore.  Newsletters, notices, and alerts generated by web scripts are pretty common in even the most mundane of websites.

The trend recently has been to flip email on it’s head.  Now people can email (or send SMS text) to a specific address, and the contents of that message can be instantly parsed and posted on a website.  Particularly intriguing to me was the ability of a site like BrightKite or Flikr to save an attached image, more or less instantly, and have it post to the web.

That got me to wondering… How are they doing that?

As a long time ASP coder, I could see lots of trouble ahead.  In the world of Windows hosting, there are some very wide chasms between web services, and email services.  I asked around, looked high and low, and tinkered.  To make a long story short, I don’t think there is any way, or at least any good way, this functionality can be implemented through ASP.  I could be wrong about that, but I sure couldn’t find even a hint of a way to do it.  If I’m wrong, I would love if somebody could please respond and set the record straight.

What I did find is that this is NOT the case in the world of Unix and PHP!  In fact, PHP has many very nice tools to bridge the gap between email and web hosting… Many of these nifty toys can be found at the website.  So, I dove in and started playing!

What I came up with was the following script.  To give proper credit, the main function (called “parsepart”) was originally written by some fellow in the UK named John… That’s all I know about him, and his script is posted on the site along with others.  I did modify his script in a few spots, specifically in decoding the file name of any attachments.  But this script is a foundation for doing what TwitPic, Flikr, FaceBook, and others are doing.  I looked and played long and hard to come up with this… I hope somebody else can benefit from it as well…  Also, this doesn’t handle SMS, just email.  SMS is a task for another day!

//script will fetch an email identified by $msgid, and parse its parts into an
//array $partsarray
//structure of array:
//$partsarray[<name of part>][<attachment/text>]
//if attachment- subarray is [filename][binary data]
//if text- subarray is [type of text(HTML/PLAIN)][text string]

//$partsarray[1][attachment][filename]=filename of attachment in part 3.1
//$partsarray[1][attachment][binary]=binary data of attachment in part 3.1
//$partsarray[2][text][type]=type of text in part 2
//$partsarray[2][text][string]=decoded text string in part 2
//$partsarray[not multipart][text][string]=decoded text string in message that isn’t multipart

function parsepart($p,$i){
global $mbox,$msgid,$partsarray;
//where to write file attachments to:
$filestore = ‘[full/path/to/attachment/store/(chmod777)]’;

//fetch part
//if type is not text
if ($p->type!=0){
//decode if base64
if ($p->encoding==3)$part=base64_decode($part);
//decode if quoted printable
if ($p->encoding==4)$part=quoted_printable_decode($part);
//no need to decode binary or 8bit!

//get filename of attachment if present
// if there are any dparameters present in this part
if (count($p->dparameters)>0){
foreach ($p->dparameters as $dparam){
if ((strtoupper($dparam->attribute)==’NAME’) ||(strtoupper($dparam->attribute)==’FILENAME’)) $filename=$dparam->value;
//if no filename found
if ($filename==”){
// if there are any parameters present in this part
if (count($p->parameters)>0){
foreach ($p->parameters as $param){
if ((strtoupper($param->attribute)==’NAME’) ||(strtoupper($param->attribute)==’FILENAME’)) $filename=$param->value;
//write to disk and set partsarray variable
if ($filename!=”){
$tempfilename = imap_mime_header_decode($filename);

$partsarray[$i][attachment] = array(‘filename’=>$filename,’binary’=>$part);
//end if type!=0

//if part is text
else if($p->type==0){
//decode text
if ($p->encoding==4) $part=quoted_printable_decode($part);
//if base 64
if ($p->encoding==3) $part=base64_decode($part);

//OPTIONAL PROCESSING e.g. nl2br for plain text
//if plain text

if (strtoupper($p->subtype)==’PLAIN’)1;
//if HTML
else if (strtoupper($p->subtype)==’HTML’)1;
$partsarray[$i][text] = array(‘type’=>$p->subtype,’string’=>$part);

//if subparts… recurse into function and parse them too!
if (count($p->parts)>0){
foreach ($p->parts as $pno=>$parr){

//Open the connection to IMAP server
$mbox = imap_open(“{}”, “”, “password”)
or die(“can’t connect: ” . imap_last_error());

$status = @imap_status($mbox, “{}INBOX”, SA_ALL);

//$message_to_read = imap_uid($mbox, $status->uidnext – 1);
$msgid = $status->messages;

if ($msgid == 0) {
die(“No messages in inbox.”);

//fetch structure of message

//see if there are any parts
if (count($s->parts)>0){
foreach ($s->parts as $partno=>$partarr){
//parse parts of email

//for not multipart messages
//get body of message
//decode if quoted-printable
if ($s->encoding==4) $text=quoted_printable_decode($text);
if (strtoupper($s->subtype)==’PLAIN’) $text=$text;
if (strtoupper($s->subtype)==’HTML’) $text=$text;

$partsarray[‘not multipart’][text]=array(‘type’=>$s->subtype,’string’=>$text);

$header = imap_fetchheader($mbox,$msgid);
$obj = imap_rfc822_parse_headers($header);

//And heres the header info… Store it in a database, display it, whatever you like…

echo “Subject: ” . $obj->subject . “<br>”;
echo “From: ” . $obj->reply_toaddress . “<br>”;
echo “Plain Text: ” . $partsarray[‘not multipart’][‘text’][‘string’] . “<br>”;
echo “Text: ” . $partsarray[1][‘text’][‘string’] . “<br>”;
echo “Attachment file name: ” . $partsarray[1][‘attachment’][‘filename’] . “<br>”;

//here you can respond back with a confirmation email to the sender…
$headers = “From:”;
imap_mail ($obj->reply_toaddress,”Thanks for posting!”,”Your message was received!”,$headers);

//here we delete the message once parsed, clean out the mailbox, and close it all up…
imap_delete($mbox, $msgid);

I’ll be the first to admit I’m a bit of a PHP hack, and there may be better ways of doing this… But this script, in fewer than 150 lines, seems to do the trick!

A Nifty ASP Function to Convert a Regular URL into a TinyURL

Posted in Technology, Web Programming with tags , , , on May 14, 2008 by webzealot

I was pretty intrigued when I noticed Twitter will automatically convert a “long” URL into a “TinyURL” (see if you’re not familiar with this) so I assumed must have some sort of open API for automatically converting a URL.

Well, there might be an open API, but I sure couldn’t find it!

However, I figured there had to be a way to query against and get the desired result. So, I wrote my own little script to do exactly that! This uses classic ASP and the XMLHTTP object:

function GetTiny(URL)
if instr(URL, “”) = 0 then
preText = “<input type=hidden name=tinyurl value=”””
postText = “x = document.all.tinyurl.createTextRange();”

strFrom = “; & URL

Set xml = Server.CreateObject(“Microsoft.XMLHTTP”)
xml.Open “GET”, strFrom, False
sHTML = xml.responseText

strFirst = InStr(sHTML, preText ) ‘ Start of data
strLast = InStr(sHTML, postText) -20 ‘ End of Data
TinyURL = Mid(sHTML, strFirst + len(preText), strLast-strFirst-len(preText))

set xml = nothing

GetTiny = TinyURL
GetTiny = URL
end if

end function

To invoke it:

call GetTiny("")

Just that simple! Hope somebody finds this useful! Please let me know if you see any ways this can be improved!

UPDATE: I did discover there is an API for TinyURL… However, I have found it to be problematic. For instance, only “www.” domains seem to work, and adding “http://&#8221; onto the URL will generate an incorrect TinyURL. My script seems to work regardless.