Home arrow PHP arrow Page 5 - Building A PHP-Based Mail Client (part 1)

Opening Up - PHP

Ever wondered how Web-based mail clients work, or what happens toyour email after you hit the "Send" button? This three-part case studydelves into the wild and wacky world of Web-based email applications, usingPHP's built-in POP3 functions to build an email client suitable forrerieving POP3 email via a Web browser. In this introductory segment -connecting to a POP3 server, logging in and out, retrieving message headersfor display, and deleting messages off the server.

TABLE OF CONTENTS:
  1. Building A PHP-Based Mail Client (part 1)
  2. Requiring Immediate Attention
  3. Start Me Up
  4. Fully Function-al
  5. Opening Up
  6. Calling The Exterminator
  7. Back To Square One
By: icarus, (c) Melonfire
Rating: starstarstarstarstar / 55
January 02, 2002

print this article
SEARCH DEV SHED

TOOLS YOU CAN USE

advertisement
With the session instantiated, the next step is to retrieve and display a list of messages from the user's mailbox on the mail server. This is accomplished via "list.php", a PHP script which opens a connection to the POP3 server, obtains a list of message headers and displays them in a neat table.

Before getting into the details of "list.php", I want to take a minute to explain a little something about the user interface. If you look at the sample screenshots in this article, you'll see that every page generated through this application has some common elements: the logo at the top left corner, the copyright note at the top right corner, and a dividing bar containing the page title below both.

Since these elements will remain constant through the application, I've placed the corresponding HTML code in a separate header file, and simply include()d them on each page. Take a look at "header.php":

<table width="100%" border="0" cellspacing="0" cellpadding="5"> <tr> <td><img src="images/logo.jpg" width=67 height=55 alt="" border="0"></td> <td valign="bottom" align="right"><font size="-2" face="Verdana">Everything here is &copy; <a href="http://www.melonfire.com/">Melonfire</a>, 2001.<br>All rights reserved.</font></td> </tr> <tr> <td bgcolor="#C70D11" align="left"><font size="-1" color="white" face="Verdana"><b><? echo $title; ?></b></font></td> <td bgcolor="#C70D11" align="right"><? if(session_is_registered("SESSION")) { ?><font size="-1" color="white" face="Verdana"><b><a style="color: white" href="logout.php">Log Out</a></b></font><? } ?>&nbsp;</td> </tr> </table>
Again, by separating common interface elements into separate files, I've made it easier to customize the look of the application; simply alter these files, and the changes will be reflected on all the pages.

Note that the page title needs to be specified as a variable prior to including this header file in a script - you'll see examples of this over the next few pages. Note also the link to log out, which appears only after the user has logged in (I've used the session_is_registered() function to test for the presence of a valid PHP session).

Okay, back to "list.php". Here's the script:

<?php // list.php - display message list // includes include("functions.php"); // session check session_start(); if (!session_is_registered("SESSION")) { header("Location: error.php?ec=2"); exit; } // open mailbox $inbox = @imap_open ("{". $SESSION_MAIL_HOST . "/pop3:110}", $SESSION_USER_NAME, $SESSION_USER_PASS) or header("Location: error.php?ec=3"); // get number of messages $total = imap_num_msg($inbox); ?> <html> <head> </head> <body bgcolor="White"> <? // page header $title = "Message Listing ($total total)"; include("header.php"); ?> <table width="100%" border="0" cellspacing="3" cellpadding="5"> <!-- command buttons - snipped --> </table> <? if ($total > 0) { ?> <table width="100%" border="0" cellspacing="0" cellpadding="5"> <form action="delete.php" method="post"> <!-- message info columns --> <tr> <td width="5%"><font size="-1">&nbsp;</font></td> <td width="5%"><font size="-1">&nbsp;</font></td> <td width="15%"><font face="Verdana" size="-1"><b>Date</b></font></td> <td width="20%"><font face="Verdana" size="-1"><b>From</b></font></td> <td width="45%"><font face="Verdana" size="-1"><b>Subject</b></font></td> <td width="10%"><font face="Verdana" size="-1"><b>Size</b></font></td> </tr> <?php // iterate through messages for($x=$total; $x>0; $x--) { // get header and structure $headers = imap_header($inbox, $x); $structure = imap_fetchstructure($inbox, $x); ?> <tr bgcolor="<?php echo $bgcolor; ?>"> <td align="right" valign="top"> <input type="Checkbox" name="dmsg[]" value="<? echo $x; ?>"> </td> <td valign="top"> <? // attachment handling code goes here ?> </td> <td valign="top"> <font face="Verdana" size="-1"><? echo substr($headers->Date, 0, 22); ?></font> </td> <td valign="top"> <font face="Verdana" size="-1"><? echo htmlspecialchars($headers->fromaddress); ?></font> </td> <td valign="top"> <font face="Verdana" size="-1"> <a href="view.php?id=<? echo $x; ?>"> <? // correction for empty subject if ($headers->Subject == "") { echo "No subject"; } else { echo $headers->Subject; } ?> </a> </font> </td> <td valign="top"> <font face="Verdana" size="-1"> <? // display message size echo ceil(($structure->bytes/1024)), " KB"; ?> </font> </td> </tr> <? } // clean up imap_close($inbox); ?> </form> </table> <? } else { echo "<font face=Verdana size=-1>You have no mail at this time</font>"; } ?> </body> </html>
This probably looks complicated, but it isn't really. Let's take it from the top:

1. The first few lines of the script are pretty standard - I've included the common function definitions, and tested for the presence of a valid session (and, by implication, the presence of a mail username, password and host).

<? // includes // session check session_start(); if (!session_is_registered("SESSION")) { header("Location: error.php?ec=2"); exit; } ?>
In the event that this test fails, the browser is immediately redirected to the generic error handler, "error.php", with an error code identifying the problem. You'll see this code in almost every script that follows; it's a standard validation routine I plan to perform throughout the application.

2. Assuming that the session check is passed, the next step is to open a connection to the POP3 server. PHP offers the imap_open() function for this purpose; it accepts three parameters: the POP3 server name, the POP3 user name and the corresponding password (you can also use the imap_open() command to open a connection to an IMAP or NNTP server - look at http://www.php.net/manual/en/ref.imap.php for examples).

<? // open mailbox $inbox = @imap_open ("{". $SESSION_MAIL_HOST . "/pop3:110}", $SESSION_USER_NAME, $SESSION_USER_PASS) or header("Location: error.php?ec=3"); ?>
If you're familiar with the POP3 protocol, this is equivalent to sending USER and PASS commands to the server.

If the connection is successful, this function returns a handle representing the mailbox, required for all subsequent operations.

In the event that a connection cannot be opened - say, the password is wrong or the mail server is not active - the browser is again redirected to "error.php" with an error code indicating the problem.

3. If a connection is successfully initiated, the imap_num_msg() function, in concert with the handle returned by imap_open(), is used to obtain the total number of messages in the mailbox; this number is then displayed in the page title.

<? // get number of messages $total = imap_num_msg($inbox); // page header $title = "Message Listing ($total total)"; include("header.php"); ?>
Incidentally, don't be fooled by the prefix on all these function names; as stated previously, though every function starts with "imap_", PHP's IMAP extension can also be used with the POP3 and NNTP protocols.

4. Assuming that there are messages in the mailbox, an HTML table is generated to hold the message headers. In this case, I've decided to display the message date, subject, sender and size, together with a checkbox for message selection and an attachment icon if an attachment exists.

<? if ($total > 0) { ?> <table width="100%" border="0" cellspacing="0" cellpadding="5"> <form action="delete.php" method="post"> <!-- table rows and columns go here --> </form> </table> <? } else { echo "<font face=Verdana size=-1>You have no mail at this time</font>"; } ?>
Within the table, a "for" loop iterates as many times as there are messages, retrieving the headers and structure of each message with the imap_header() and imap_fetchstructure() functions respectively. Throughout this loop, the variable $x references the current message number. Note that I'm iterating through the message list in reverse order so that the more recent messages are displayed first.

<? // iterate through messages for($x=$total; $x>0; $x--) { // get header and structure $headers = imap_header($inbox, $x); $structure = imap_fetchstructure($inbox, $x); // table rows here } ?>
If you're familiar with the POP3 protocol, this is equivalent to sending a series of RETR commands to the server.{mospagebreak title=Treating Messages As Objects} 5. Of the headers I've selected for display, the sender, subject and date are fairly easy to obtain - the imap_header() function returns an object, one for each message, exposing these values as properties. All I need to do is access these properties and echo() them to the page. For example, the object property

$obj->fromaddress
would reference the message's From: header, while the property

$obj->Subject
would reference the message subject.

The imap_header() function returns an object with the following properties, each corresponding to a different attribute of the mail message:

$obj->remail; $obj->date, $obj->Date, $obj->subject, $obj->Subject, $obj->in_reply_to, $obj->message_id, $obj->newsgroups, $obj->references $obj->toaddress $obj->fromaddress $obj->ccaddress $obj->bccaddress $obj->reply_toaddress $obj->senderaddress $obj->udate
For a complete list, take a look at the PHP manual page for this function at http://www.php.net/manual/en/function.imap-header.php

Here's the code to print the message date and sender:

<!-- snip --> <td valign="top"> <font face="Verdana" size="-1"><? echo substr($headers->Date, 0, 22); ?></font> </td> <td valign="top"> <font face="Verdana" size="-1"><? echo htmlspecialchars($headers->fromaddress); ?></font> </td> <!-- snip -->
I also need to link each message to a script, "view.php", which displays the complete message body. I've decided to do this by attaching a hyperlink to the subject of every message in the message list and passing it the message number via the URL GET method.

<td valign="top"> <font face="Verdana" size="-1"> <a href="view.php?id=<? echo $x; ?>"> <? // correction for empty subject if ($headers->Subject == "") { echo "No subject"; } else { echo $headers->Subject; } ?> </a> </font> </td>
If you look at the list above, you'll see that the other two elements of my proposed message listing - the message size and the attachment status - are not available through imap_header(). So what do I do?

6. The answer, as it turns out, lies in another function: imap_fetchstructure(). Using a mailbox handle and message number as arguments, this function reads the message body and returns another object, this one containing information on the message size, message body and MIME parts within it. In order to obtain the message size, I need to simply access this object's "bytes" property.

<td valign="top"> <font face="Verdana" size="-1"> <? // display message size echo ceil(($structure->bytes/1024)), " KB"; ?> </font> </td>
For greater readability, I've converted the number into kilobytes and rounded up to the nearest integer.

At this point, I have absolutely no clue how to find out the attachment status. After a few experiments with the imap_fetchstructure() and imap_body() functions, I was able to obtain the complete body of the message, including the headers for MIME attachments. However, parsing these headers manually turned out to be fairly messy and code-intensive, and my gut tells me there's a better way to do it. So I'm going to leave this aside for now and come back to it after boning up on some MIME theory.

<td valign="top"> <font face="Verdana" size="-1"> <? // attachment handling code goes here ?> </font> </td>
Finally, I need to provide some way for the user to delete messages from the mailbox. The traditional technique is a checkbox next to each message, which is used to select each message for deletion...and I'm a big fan of tradition.

<td align="right" valign="top"> <input type="Checkbox" name="dmsg[]" value="<? echo $x; ?>"> </td>
Note that each checkbox is linked to the message number, and that the selected message numbers will be added to the $dmsg array. When the form is submitted, the "delete.php" script (discussed next) will use this array to identify and mark messages for deletion from the server.

7. With all (or most of) the information now displayed, the last task is to clean up by closing the POP3 connection.

<? // clean up imap_close($inbox); ?>
If you're familiar with the POP3 protocol, this is equivalent to sending a QUIT command to the server.

Here's what it all looks like:



 
 
>>> More PHP Articles          >>> More By icarus, (c) Melonfire
 

blog comments powered by Disqus
escort Bursa Bursa escort Antalya eskort
   

PHP ARTICLES

- Hackers Compromise PHP Sites to Launch Attac...
- Red Hat, Zend Form OpenShift PaaS Alliance
- PHP IDE News
- BCD, Zend Extend PHP Partnership
- PHP FAQ Highlight
- PHP Creator Didn't Set Out to Create a Langu...
- PHP Trends Revealed in Zend Study
- PHP: Best Methods for Running Scheduled Jobs
- PHP Array Functions: array_change_key_case
- PHP array_combine Function
- PHP array_chunk Function
- PHP Closures as View Helpers: Lazy-Loading F...
- Using PHP Closures as View Helpers
- PHP File and Operating System Program Execut...
- PHP: Effects of Wrapping Code in Class Const...

Developer Shed Affiliates

 


Dev Shed Tutorial Topics: