Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_Mail_Read Component Proposal

Proposed Component Name Zend_Mail_Read
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Mail_Read
Proposers Nico Edtinger, Telekom Austria
Revision 1.0 - 26 June 2006: Merged previous proposals (Zend_Mime_Decode, Zend_Mail_Read, Zend_Mail_List). (wiki revision: 25)

Table of Contents

1. Overview

Mail is one of the most important services on the internet. In addition to
sending mails it's also important for many websites to read and receive mail
messages, be it simple webmail interfaces, archives of mailing lists or
cron jobs that need to read incoming mails.

There are many existing mail libs, even in PHP, but they often don't fit
well. Some of them are to strict or to sloppy, others are made for a specific
application. And then there is some code written in C, that's good, but
not part of the default PHP distribution.

The goal is to offer classes for Mbox, Maildir, POP3 and IMAP and reuse
the existing code of the mail sending classes. Also links between these two
are possible, like reply to a message or sending to an IMAP folder.

Note: Some methods or parameters needed for IMAP may be missing in
this proposal (folder, flags, save message)

2. References

Inspirations: (the good, the bad and the ugly - in no particular order)

3. Component Requirements, Constraints, and Acceptance Criteria

  • Create an easy and common API to fetch messages from mail storages.
  • Make it possible to access additonal functionality of mail storages without coding for one specific mail storage (via capabilities).
  • Make the transport class reusable and add not additional logic to the protocol.
  • Split MIME decoding in its own class without changing existing mail and mime classes.
  • Map mail reading functions to PHP with Zend_Mail_List (implementing all the funky interfaces for accessing the mail storage as array and iteration)
  • obey the standards
  • be lax with received data without violating the standards

4. Dependencies on Other Framework Components

  • Zend_Exception
  • Zend_Mime - for decoding and as base for message class

5. Theory of Operation

Zend_Mime_Decode

The class has no internal logic. It's used to collect all decoding functions as static methods
for mime and mail classes. Normally this methods would be used by other framework components.

Zend_Mail_*(Pop3,Imap,Mbox,Maildir)

The classes are divided in:

  • transport classes
  • mail classes
  • message classes

All mail messages are stored in a message storage. If the
storage is external (not read from a file resource) a transport
class is used to translate the used protocol in PHP structures.

Based on this classes are the mail classes, or if an internal
storage is used the mail classes can read directly from the
storage. These classes extend an abstract mail class defining
the common interface.

Each message is returned as message class, which can be specialized
to support mail storage specific functions like late fetching of
the whole message or parts of a message.

If the message is a multipart message it can return each part, which
could itself be multipart.

Zend_Mail_List

Zend_Mail_List translates the interfaces, which the PHP engine needs, to the
mail reading APIs. ArrayAccess and Countable are implemented to access
a specific message and count all messages. Iterator is used for iterating
over all messages.

6. Milestones / Tasks

zone: Missing {zone-data:milestones}

7. Class Index

  • Zend_Mime_Decode
  • Zend_Mail_Message
  • Zend_Mail_Abstract
  • Zend_Mail_Mbox
  • Zend_Mail_POP3
  • Zend_Mail_Transport_POP3
  • Zend_Mail_Maildir
  • Zend_Mail_Imap
  • Zend_Mail_Transport_Imap
  • Zend_Mail_List

8. Use Cases

Zend_Mime_Decode
Zend_Mail_List
Zend_Mail_Mbox
Zend_Mail_* full functional demo

9. Class Skeletons

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Jun 25, 2006

    <p>Mbox and POP3 can already be seen and tested. Code is in current incubator: <a class="external-link" href="http://framework.zend.com/svn/framework/trunk/incubator/library/Zend/Mail/">http://framework.zend.com/svn/framework/trunk/incubator/library/Zend/Mail/</a></p>

    <p>Examples: <a class="external-link" href="http://nico.edtinger.at/pub/2006/examples/">http://nico.edtinger.at/pub/2006/examples/</a><br />
    and the tests: <a class="external-link" href="http://framework.zend.com/svn/framework/trunk/incubator/tests/Zend/Mail/">http://framework.zend.com/svn/framework/trunk/incubator/tests/Zend/Mail/</a></p>

  2. Aug 01, 2006

    <p>Would these classes understand the on-disk file and directory naming formats and conventions used by Maildir and IMAP implementations like Courier and Dovecot?</p>

    <p><a class="external-link" href="http://www.squirrelmail.org/wiki/MailDir">http://www.squirrelmail.org/wiki/MailDir</a></p>

    1. Aug 21, 2006

      <p>At our company we want to use the maildir class to replace our IMAP server (at least for the most common tasks) - AFAIK we're using a Courier. I use Dovecot for testing, so expect the first implementation to work at least with that server/format <ac:emoticon ac:name="wink" /></p>

      <p>At first I thought about having maildir readonly like mbox, but it's not that complicated with the locking issues and adding/removing messages, so I'm already sure we want to add nearly all functionality as in the IMAP class (except stuff like searching).</p>

      <p>PS: Sorry to all commenters for the late replies. Had holiday and needed so time to catch-up.</p>

  3. Aug 04, 2006

    <ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Comments on Zend_Mail_Read</ac:parameter><ac:rich-text-body>
    <p>We are accepting this proposal and offer the following feedback:</p>

    <ul>
    <li>Not Zend_Mail_Transport; use Zend_Mail_Storage instead
    <ul>
    <li>These are not really transports (i.e., used for transporting mail), but storage containers/formats. Zend_Mail_Abstract then would also become Zend_Mail_Storage_Abstract.</li>
    </ul>
    </li>
    <li>Merge Zend_Mail_List and Zend_Mail(_Storage)_Abstract
    <ul>
    <li>Each storage container needs the ability to count and iterate over messages. Since Zend_Mail_List simply implements several interfaces and uses values in Zend_Mail(_Storage)_Abstract to implement the functionality, merge the classes.</li>
    </ul>
    </li>
    <li>Zend_Mail_Message
    <ul>
    <li>Need clarification
    <ul>
    <li>Could this be eliminated in favor of Zend_Mail? or extend Zend_Mail to define the transport methods (send(), setDefaultTransport()) as unusable and allow decoding of message parts (for that matter, could the differences in Zend_Mail and Zend_Mail_Message be merged)? Basically, I'm not certain if a new class is needed here.</li>
    </ul>
    </li>
    </ul>
    </li>
    <li>Zend_Mail(_Storage)_Abstract
    <ul>
    <li>declare as 'abstract'</li>
    </ul>
    </li>
    <li>Zend_Mail_Storage_* classes that support trees
    <ul>
    <li>have each implement RecursiveIterator
    <ul>
    <li>This would make traversing more intuitive when using nested folders (ala IMAP or Maildir)</li>
    </ul>
    </li>
    </ul>
    </li>
    </ul>
    </ac:rich-text-body></ac:macro>

    1. Aug 21, 2006

      <ul>
      <li>Zend_Mail_List.<br />
      Sure merging it is the best solution. It only was a seperate class, because it wasn't clear if it fits the ZF (back in spring - a long time ago <ac:emoticon ac:name="wink" />)</li>
      </ul>

      <ul>
      <li>declare as abstract<br />
      Isn't it already? Did I miss something?</li>
      </ul>

      <ul>
      <li>RecursiveIterator<br />
      That could be added to Zend_Mail_Abstract. Even the Mbox class can support folders, given a base dir. POP3 would be the only exception. With the hasFolder flag we can check in the current instance if folders are supported.</li>
      </ul>

      <ul>
      <li>Transport vs. Storage<br />
      Currently the transport classes really only impemented the network/protocol stuff. Mbox and Maildir both have no Mail_Transport_... class. We could:
      <ul>
      <li>Move Zend_Mail_* classes to Zend_Mail_Storage_* and keep the Zend_Mail_Transport_* classes</li>
      <li>Move as above and merge Zend_Mail_Tranport_* with Zend_Mail_Storage_*</li>
      <li>Just rename Zend_Mail_Transport_* to Zend_Mail_Storage_* and keep the Zend_Mail_* classes<br />
      I like the way it's now because the transport classes really only handle handle getting messages/data from the server and "new Zend_Mail_Pop3(...);" isn't too long to write. However I'll follow any order.</li>
      </ul>
      </li>
      </ul>

      <ul>
      <li>Naming issues, duplicated classes<br />
      I guess Zend_Mail_Message should be a Zend_Mime_Message object. But I have problems using Zend_Mime_Message and Zend_Mime_Part, because they are too specific and were made for sending messages. My approach would have been to use Zend_Mail_Message and Zend_Mail_(Message_)Part and merge them with the Zend_Mime_* classes later.<br />
      Also both classes should be extendable so we can implement "late fetch" for the different mail storage implementations. I though about returning an empty Zend_XXX_Message_Pop3 class in Zend_Mail_Pop3::getMessage() and load headers and body when needed. It would also allow an easy copy to a stream (like in "save attachment to file ...").</li>
      </ul>

  4. Aug 08, 2006

    <p>Note that both POP3 and IMAP have non-standard "extensions" allowing the transmission of emails. For POP3, Eudora, Qpopper, and CommuniGate support the "xtnd xmit" extension. I'm not sure about the popularity of this extension.</p>

    <p>Some IMAP servers also support sending mail using a convention that moving a message to the "outbox" initiates sending it. Numerous forces are at work to push IMAP towards facilitating composition and sending of emails:</p>

    <p><a class="external-link" href="http://tools.ietf.org/html/rfc4469">http://tools.ietf.org/html/rfc4469</a>
    <a class="external-link" href="http://tools.ietf.org/html/rfc4468.txt">http://tools.ietf.org/html/rfc4468.txt</a>
    <a class="external-link" href="http://flyingfox.snowshore.com/i-d/lemonade/">http://flyingfox.snowshore.com/i-d/lemonade/</a>
    <a class="external-link" href="http://www.ietf.org/html.charters/lemonade-charter.html">http://www.ietf.org/html.charters/lemonade-charter.html</a></p>

    <p>Even if support for sending emails were included (low priority), I'd still expect different classes for the synchronization of messages and a mechanism to actually send an email.</p>

    <p>For those new to PHP's SPL classes, and the RecursiveIterator class, see this short introduction to this implementation of tree traversal, but notice the typo for "implements RecursiveIteratorIterator", which should be "implements RecursiveIterator": <a class="external-link" href="http://wiki.cc/php/RecursiveIterator">http://wiki.cc/php/RecursiveIterator</a></p>

    1. Aug 21, 2006

      <p>The current POP3 class only supports the most simple and common standard and no nice-to-haves. It even ignores the capabilities for TOP and instead just tries to send that command, because you may to it. Also some mail hoster aren't honest with their CAPA response - i.e. we had GMX, which does support TOP but doesn't say so in the capas.</p>

      <p>The IMAP class will support message storage. It's also needed for moving a message to trash or coping a message from a different mail storage. It should be easy to add a class for mail sending best on the IMAP class.</p>

      <p>For other extensions I'd say let's get the simple things done and then see what fits the 80/20 rule and would be a useful addition.</p>

  5. Aug 24, 2006

    <p>After playing with this for a bit, there is one thing that's really annoying. When I have a Zend_Mail_Message, there is no way to get back the original raw data that was used to instantiate the object and split into header and content components.</p>

    <p>This is especially annoying since if I'm using Zend_Mail_Mbox and I am pulling out a message, the Zend_Mail_Message object is returned, which is nice, but prevents me from being able to get at the raw source of the email.</p>

    <p>Please allow Zend_Mail_Message to maintain the original text. This could be a flag that is set somewhere when constructing the object. Thanks and I hope someone else agrees</p>

    1. Aug 28, 2006

      <p>Sounds like you want a method Zend_Mail_Message::getRaw(). Would definitely be handy for saving a copy of i.e. a Pop3 storage to a maildir. A flag to getMessage() seems more like a functional approach - a new method feels more OO <ac:emoticon ac:name="wink" /></p>

      <p>It would also work great with the steam methods I'm planing. So you could call Zend_Mail_Message::getRawSocket() and use that to save the whole message content to a file with a stream to stream copy.</p>

      <p>Does that sound acceptable to you? Thanks for your input.</p>

      1. Aug 28, 2006

        <p>Sounds good to me. The reason for the flag would be to include/exclude the raw message functionality and overhead. For example, if you don't care about the raw message, there's no reason to keep it around in-memory. But yes, if you add the getRaw() method, that would be awesome. Thanks</p>

  6. Jan 03, 2007

    <p>for classes suggested in the Mail_Transport_* they only implements the net/protocol, i believe that would have in the following way: Zend_Net_* (Pop3, Imap, Smtp...). In similar way to PEAR, this is util for other components of framework that also they use sockets, as Zend_Mail_Transport_Smtp, Zend_Http_Client_Adapter_Proxy (in the Incubator)</p>

    <p>References:
    <a class="external-link" href="http://pear.php.net/manual/en/package.networking.net-pop3.php">http://pear.php.net/manual/en/package.networking.net-pop3.php</a></p>

    <p>Thanks.</p>

  7. Mar 18, 2009

    <p>This hasn't been worked on in quite some time. I'm archiving it for now.</p>