Path

ez components / documentation / api reference / 2007.1.1 / mail


eZ Components 2007.1.1

Mail: Mail-listing-example

[ Tutorial ] [ Display example ] [ Mail listing example ] [ Rfcs ] [ Class tree ] [ Element index ] [ ChangeLog ] [ Credits ]

Mail Listing Example

How to use

This example demonstrates how to display a listing of mails in a fast and efficient way. Although IMAP is used here, POP3 and MBOX will be easy to implement as well.

The files used by this example are in the mail-listing-example directory inside the docs directory of the Mail component. The output of the mail.php script is html, so in order to see it in a browser you will have to copy the files in your web root directory, and change the include_path variable in the mail.php file to point to the directory where the eZ Components are kept.

You will also have to specify a valid IMAP server with a valid username and password in the app.ini file.

The compiled_templates directory needs to have write permissions for itself and its subdirectories, so be sure to set that.

When clicking on a mail in the mail list, the browser will try to load the message.php file with the ID and mailbox of the clicked message. This file is not implemented yet.

Structure

mail.php

This is the main script. It uses the Mail, Configuration and Template components. You have to modify the 3rd line to point to your location of the eZ Components. Run it from a browser as http://localhost/mail.php or similar depending on your web server.

The current mailbox and the current page in the mail listing are specified using GET, and are initial Inbox and 1.

  1. <?php
  2. // Change this to where you keep the eZ Components
  3. ini_set'include_path''/home/as/dev/ezcomponents/trunk:.' );
  4. require 'Base/src/base.php';
  5. 
  6. // Include the PagingLinks custom block
  7. require 'app/paging_links.php';
  8. 
  9. // Required method to be able to use the eZ Components
 10. function __autoload$className )
 11. {
 12.         ezcBase::autoload$className );
 13. }
 14. 
 15. // Start counting how much the execution time will be
 16. $start microtimetrue );
 17. 
 18. // Read configuration file app.ini with the Configuration component
 19. $iniFile 'app';
 20. $config ezcConfigurationManager::getInstance();
 21. $config->init'ezcConfigurationIniReader'dirname__FILE__ ) );
 22. $options = array( 'templatePath' => dirname__FILE__ ) . $config->getSetting$iniFile'TemplateOptions''TemplatePath' ),
 23.                   'compilePath' => dirname__FILE__ ) . $config->getSetting$iniFile'TemplateOptions''CompilePath' ),
 24.                   'server' => $config->getSetting$iniFile'MailOptions''Server' ),
 25.                   'user' => $config->getSetting$iniFile'MailOptions''User' ),
 26.                   'password' => $config->getSetting$iniFile'MailOptions''Password' ),
 27.                   'mailbox' => isset( $_GET['mailbox'] ) ? $_GET['mailbox'] : $config->getSetting$iniFile'MailOptions''Mailbox' ),
 28.                   'pageSize' => $config->getSetting$iniFile'MailOptions''PageSize' ),
 29.                   'currentPage' => isset( $_GET['page'] ) ? $_GET['page'] : null
 30.                   );
 31. 
 32. // Create a mail IMAP transport object
 33. $transport = new ezcMailImapTransport$options["server"] );
 34. $transport->authenticate$options["user"], $options["password"] );
 35. $transport->selectMailbox$options["mailbox"] );
 36. 
 37. // Get the mailboxes names from the server
 38. $mailboxes $transport->listMailboxes();
 39. sort$mailboxes );
 40. 
 41. // Get the UIDs of the messages in the selected mailbox
 42. // and the sizes of the messages
 43. $mailIDs $transport->listUniqueIdentifiers();
 44. $messages $transport->listMessages();
 45. 
 46. // Calculate how many pages of mails there will be based on pageSize
 47. $numberOfPages = (int) floorcount$messages ) / $options["pageSize"] + );
 48. 
 49. // See if currentPage fits in the range 1..numberOfPages
 50. if ( $options["currentPage"] <= || $options["currentPage"] > $numberOfPages ||
 51.      ( count$messages ) % $options["pageSize"] === && $options["currentPage"] >= $numberOfPages ) )
 52. {
 53.     $options["currentPage"] = 1;
 54. }
 55. 
 56. // Slice the array to the range defined by currentPage
 57. $sizes array_slicearray_values$messages ), ( $options["currentPage"] - ) * $options["pageSize"], $options["pageSize"] );
 58. $mailIDs array_slice$mailIDs, ( $options["currentPage"] - ) * $options["pageSize"], $options["pageSize"] );
 59. $messages array_keys$messages );
 60. 
 61. // Read and parse the headers of the mails in the currentPage from the IMAP server
 62. $mails = array();
 63. $parser = new ezcMailParser();
 64. for ( $i = ( $options["currentPage"] - ) * $options["pageSize"]; $i min$options["currentPage"] * $options["pageSize"], count$messages ) ); $i++ )
 65. {
 66.     $msg $transport->top$messages[$i] );
 67.     $lines preg_split"/\r\n|\n/"$msg );
 68.     $msg null;
 69.     foreach ( $lines as $line )
 70.     {
 71.         // eliminate the line that contains "Content-Type" at it would throw
 72.         // a notice for "multipart/related" (because the multipart object cannot
 73.         // be created due to missing the body)
 74.         if ( stripos$line"Content-Type:" ) === false )
 75.         {
 76.             $msg .= $line PHP_EOL;
 77.         }
 78.         else
 79.         {
 80.             // insert code to analyse the Content-Type of the mail
 81.             // and add an "attachment" icon in case it is "multipart"
 82.         }
 83.     }
 84.     $set = new ezcMailVariableSet$msg );
 85.     $mail $parser->parseMail$set );
 86.     $mails[] = $mail[0];
 87. }
 88. 
 89. // Create some debug information (how many miliseconds the parsing took)
 90. $end microtimetrue );
 91. $debug sprintf"Execution time (without template): %.0f ms", ( $end $start ) * 1000 ) . "\n";
 92. 
 93. // Create a template configuration object based on $options
 94. $templateConfig ezcTemplateConfiguration::getInstance();
 95. $templateConfig->templatePath $options["templatePath"];
 96. $templateConfig->compilePath $options["compilePath"];
 97. $templateConfig->context = new ezcTemplateXhtmlContext();
 98. $templateConfig->addExtension"PagingLinks" );
 99. 
100. // Create a template object based on $templateConfig
101. $template = new ezcTemplate();
102. $template->configuration $templateConfig;
103. 
104. // Assign the template variables with the script variables
105. $template->send->debug $debug;
106. $template->send->mailbox $options["mailbox"];
107. $template->send->mailboxes $mailboxes;
108. $template->send->selected $options["currentPage"];
109. $template->send->pageSize $options["pageSize"];
110. $template->send->mailCount count$messages );
111. $template->send->numberOfPages $numberOfPages;
112. 
113. // Create an array to be passed to the template, which holds the headers the mails
114. // in currentPage and other useful information like mail IDs
115. $mailListing = array();
116. for ( $i 0$i count$mails ); $i++ )
117. {
118.     $mailListing[$i] = array( 'number' => $messages[$i],
119.                               'id' => $mailIDs[$i],
120.                               'from' => $mails[$i]->from,
121.                               'subject' => $mails[$i]->subject,
122.                               'size' => $sizes[$i],
123.                               'received' => $mails[$i]->timestamp
124.                             );
125. }
126. $template->send->mails $mailListing;
127. 
128. // Process the template
129. $template->process"mail_listing.ezt" );
130. 
131. // Display the output of the template
132. echo $template->output;
133. ?>

app.ini

Contains the settings of this small example. You can set which folders to use for the templates, how many mails per page to display, and various IMAP settings such as server, username and password and which mailbox is the default one.

[TemplateOptions]
# Directories used by the template engine
TemplatePath = /templates
CompilePath = /compiled_templates

[MailOptions]
# How many emails to display per page
PageSize = 10

# Server options
Server = Please specify a server name
User = Please specify an user name
Password = Please specify a password
Mailbox = Inbox

app/paging_links.php

Contains a definition of a template custom block used to display links to other pages in the mail listing (e.g. 1 | 2 | 3 , where each number is a link to the respective page).

  1. <?php
  2. /**
  3.  * Provides a custom block for templates used to insert page links for a provided mailbox.
  4.  */
  5. class PagingLinks implements ezcTemplateCustomBlock
  6. {
  7.     /**
  8.      * What characters to use to separate the page links (default: 1 - 2 - 3).
  9.      */
 10.     const DEFAULT_DELIMITER '-';
 11. 
 12.     /**
 13.      * Required method to implement.
 14.      *
 15.      * @param string $name
 16.      * @return ezcTemplateCustomBlockDefinition|false
 17.      */
 18.     public static function getCustomBlockDefinition$name )
 19.     {
 20.         switch ( $name )
 21.         {
 22.             case "paging_links":
 23.                 $def = new ezcTemplateCustomBlockDefinition();
 24.                 $def->class __CLASS__;
 25.                 $def->method "htmlPagingLinks";
 26.                 $def->hasCloseTag false;
 27.                 $def->requiredParameters = array( "selected""numberOfPages""pagesize" );
 28.                 $def->optionalParameters = array( "delimiter""mailbox" );
 29.                 return $def;
 30.         }
 31.         return false;
 32.     }
 33. 
 34.     /**
 35.      * Create a list of page links for a provided mailbox.
 36.      *
 37.      * @param array(string=>mixed) $params
 38.      * @return string
 39.      */
 40.     public static function htmlPagingLinks$params )
 41.     {
 42.         $selected = (int) $params["selected"];
 43.         $numberOfPages = (int) $params["numberOfPages"];
 44.         $pageSize = (int) $params["pagesize"];
 45.         $delimiter = ( isset( $params["delimiter"] ) ) ? $params["delimiter"] : self::DEFAULT_DELIMITER;
 46.         $mailbox = ( isset( $params["mailbox"] ) ) ? $params["mailbox"] : 'INBOX';
 47. 
 48.         $result "";
 49.         for ( $i 1$i <= $numberOfPages$i++ )
 50.         {
 51.             if ( $selected === $i )
 52.             {
 53.                 $result .= "{$i}";
 54.             }
 55.             else
 56.             {
 57.                 $result .= "<a href=\"?mailbox={$mailbox}&page={$i}\">{$i}</a>";
 58.             }
 59.             if ( $i $numberOfPages )
 60.             {
 61.                 $result .= " {$delimiter} ";
 62.             }
 63.         }
 64.         return $result;
 65.     }
 66. }
 67. ?>

templates/mail_listing.ezt

Contains an html template used in mail.php. Uses the custom block paging_links defined in the app/paging_links.php file.

{use $mails, $mailCount, $selected, $pageSize, $numberOfPages, $mailbox, $mailboxes, $debug}
<html>
<head>
	<title>{$mailbox}</title>
	{literal}
	<style>
	th {
		background: #CCCCCC;
		border-bottom: 1px solid #999999;
	}
	td {
		border-bottom: 1px solid #CCCCCC;
	}
	</style>
	{/literal}
</head>
<body>

{$debug}
<hr />

Mailboxes:
{foreach $mailboxes as $m}
	{delimiter} | {/delimiter}
	{if $mailbox == $m}
		{$mailbox}
	{else}
		<a href="?mailbox={$m}">{$m}</a>
	{/if}
{/foreach}
<hr />

{paging_links selected=$selected numberOfPages=$numberOfPages pagesize=$pageSize delimiter="|" mailbox=$mailbox}
<br /><br >

<table border="0" cellpadding="2" cellspacing="0">
<tr>
    <th width="10" align="center"><input type="checkbox" name="mail" value="ALL" /></th>
    <th width="60" align="left">Sender</th>
    <th width="150" align="left">Subject</th>
    <th width="80" align="right">Size</th>
    <th width="120" align="right">Received</th>
</tr>

{foreach $mails as $mail}
{if $mail["subject"] == null}
	{$mail["subject"] = "[no subject]"}
{/if}
{if $mail["from"] == null}
	{$mail["from"] = "[none]"}
{/if}
<tr>
	<td align="center"><input type="checkbox" name="mail" value"{$mail["id"]}" /></td>
	<td align="left">{$mail["from"]}</td>
	<td align="left"><a href="/message.php?mailbox={$mailbox}&id={$mail["id"]}" target="_blank">{$mail["subject"]}</a></td>
	<td align="right">{str_number( $mail["size"] / 1024, 1, ".", "," )} KB</td>
	<td align="right">{date_format_timestamp( "D M-d, Y", $mail["received"] )}</td>
</tr>
{/foreach}

</table>
</body>

Speed considerations

By using paging in a mail listing and parsing only the headers of the mails for this (using the method top() instead of fetch*() from IMAP/POP3), the mail listing is quite fast, around 0.3 seconds instead of around 1.1 seconds (or more if there are large mails in the current mailbox), for a page size of 10 mails per page.

Extending this example

This example shows just a basic way to do a mail listing. More features can be added by a developer, for example:

  • login with an username and password instead of reading those from an ini file
  • implement sorting of the mails based on date, subject, sender, size
  • implement flags support (with the IMAP methods fetchFlags(), setFlag(), clearFlag())
  • implement mail operations (select all mails, delete, move, copy, set flags)
Last updated: Wed, 28 Nov 2007