eZ components “Mail” to save the day 5



A few days ago I was asked to develop a simple script for a solidarity campaign. The idea is that people send their photos as attachements to some email. The script would download all images attached and insert a record for that in the database.

I got introduced to eZ components during my last visit to Norway to attend the eZ systems conference. I decided to give it a shot, and oh boy it’s just amazing, probably the cleanest and simplest API ever.

I managed to find the package “Mail”:

The components allows you construct Mail messages conforming to the RFCs. It has support for attachments, multipart messages and HTML mail. It also interfaces with SMTP to send the e-mail. Reading and parsing mail messages comes in version 1.1.

The package is well documented and includes many examples. Here’s the script I ended up writing (edited version):

[coolcode lang="php"]
< ?php
define( 'PHOTOS_DIR', 'email_photos/' );
define( 'FILE_PARSED_MAILS', '.fpm' );

require_once 'Base/src/base.php';
function __autoload( $className )
{
ezcBase::autoload( $className );
}

//get the list of emails that we alread processed
$parsedEmailsIds = array();
$parsedEmailsIds = @unserialize( file_get_contents(FILE_PARSED_MAILS) );

if( 'array' != gettype($parsedEmailsIds) ){
$parsedEmailsIds = array();
}

$pop3 = new ezcMailPop3Transport( 'mail.example.org' );
$pop3->authenticate( ‘username’, ‘password’ );

//get the list of emails from the server
$severEmailsIds = $pop3->listUniqueIdentifiers();
$emailsToFetch = array_diff($severEmailsIds, $parsedEmailsIds);
if( !count($emailsToFetch) ){
//no emails to get!
exit;
}

$set = $pop3->fetchAll(false, $emailsToFetch );
$parser = new ezcMailParser();
$parser->setTmpDir( ‘tmp/’ );
$mails = $parser->parseMail( $set );

foreach ( $mails as $mail )
{

//Get email parts
foreach( $mail->body->getParts() as $part ){
if( get_class($part) == ‘ezcMailFile’ ){

//get the destination file name after some cleanups
$fileName = nameToSafe( basename($part->fileName) );

//the new destintation filename, this function makes sure we get a unique file name everytime
$destFileName = PHOTOS_DIR . nameToSeq(PHOTOS_DIR,$fileName);

rename( $part->fileName, $destFileName );

}

//after we’re done, we need to update the file that stores the list of parsed emails
file_put_contents( FILE_PARSED_MAILS, serialize( $severEmailsIds ) );

?>

[/coolcode]

I’m sure there’s a better way to get the new emails only, probably with var_export()

Note: The only problem I faced, which is VERY strange, is the ability to fetch a single email or list of emails. Surprisingly, the API didn’t provide such feature. I did an ugly hack to “Mail/transports/pop3/pop3_transport.php” to function fetchAll(), I should have created another function, but I was in a hurry. Here’s the modified version:

[coolcode lang="php"]
/**
* @throws ezcMailTransportException if the mail could not be retrieved.
* @param bool $deleteFromServer
* @param array $messages
* @return ezcMailParserSet
*/
public function fetchAll( $deleteFromServer = false, $messages = null )
{
if( !isset($messages) ){
$message = $this->listMessages();
}
return new ezcMailPop3Set( $this->connection, array_keys( $messages ), $deleteFromServer );
}

[/coolcode]

Tags: , , , , , , , , , , , , , , , , , , ,