Qafoo GmbH - passion for software quality ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :Author: Kore Nordmann :Date: Fri, 16 Sep 2016 11:44:49 +0200 :Revision: 5 :Copyright: All rights reserved ======================================== Apache Zeta Components: Doing mail right ======================================== :Keywords: apache zeta components, php, mail, html, attachment, image, send, receive, smtp, imap, ez components, zeta components, tutorial, example :Description: The Apache Zeta Mail component allows you to send and receive complex emails very easily. This article shows you practical examples to see how it works. :Abstract: Sending and receiving mail is a regular, but often cumbersome task. Especially, when it comes to more complex mails than just plain text. HTML and alternate text parts, embedded images, attachments and digests can make your brain spin if you need to do it yourself. The Apache Zeta Mail component makes it easy for you to send such mails, but also to receive them! In this article I show you how to send HTML emails with embedded images and how to receive all mails from an IMAP server and forward them in a single mail, using a digest. Sending and receiving mail is a regular, but often cumbersome task. Especially, when it comes to more complex mails than just plain text. HTML and alternate text parts, embedded images, attachments and digests can make your brain spin if you need to do it yourself. The Apache Zeta Mail component makes it easy for you to send such mails, but also to receive them! In this article I show you how to send HTML emails with embedded images and how to receive all mails from an IMAP server and forward them in a single mail, using a digest. In following, I provide you with three more advanced examples for uses of the Zeta Mail component. To get an insight into further possibilities and full API docs, please refer to the `documentation of the Zeta Mail component`__. The `example sources`__ are also provided in our Github repository, so you can grab them easily. __ __ --------------- Getting started --------------- .. note:: Want to `be backed by a professional company`__ when using Zeta Components? **Buy Qafoo blanket our per ticket support!** __ /services/support.html To get started with Apache Zeta Mail, you need to install (at least) the Zeta Base component and of course the Mail component. At the current state, Apache Zeta Components do not have an official release, yet. So you can either use the most recent `eZ Components release`__ or check out the components from the `Zeta SVN`__. I won't go into detail on this procedure, since it is pretty well `documented on our website`__. Same applies to our autoload mechanism, for which you have multiple choices to fit it into your environment. __ __ __ So, let's get straight to the point … ------------------ Sending HTML email ------------------ Using the Zeta Mail component you can send email composed of almost arbitrary MIME parts, so sending HTML email with embedded images is an easy task:: if ( !isset( $argv[1] ) ) { die( "Missing image file to send.\n" ); } if ( ( $imagePath = realpath( $argv[1] ) ) === false ) { die( "Image file '{$argv[1]}' not found.\n" ); } require_once 'Base/src/ezc_bootstrap.php'; $mail = new ezcMail(); $mail->from = new ezcMailAddress( '', 'Some Body' ); $mail->addTo( new ezcMailAddress( '', 'Any Body' ) ); $mail->subject = 'A pic from Some Body'; $textPart = new ezcMailText( 'This email contains HTML content.' . 'Please enable viewing HTML to fully enjoy it.' ); $htmlPart = new ezcMailText( '' . '

Some Body wants you to see this image

' . ' . '' ); $htmlPart->subType = 'html'; $imagePart = new ezcMailFile( $imagePath ); $imagePart->contentId = 'included_image'; $mail->body = new ezcMailMultipartAlternative( $textPart, new ezcMailMultipartRelated( $htmlPart, $imagePart ) ); $transport = new ezcMailMtaTransport(); $transport->send( $mail ); This is a simple script you could use on your server to get uploaded images sent to you as HTML mails. After some checks for the shell parameter, the Zeta Components autoload is included using our bootstrap file. Now an instance of ``ezcMail`` is created, which represents an email. Of course an email needs a ``from`` field. Email addresses are covered in instances of ``ezcMailAddress`` in order to specify the address itself and an optional name. the ``ezcMail::addTo()`` method can be called multiple times in order to add recipients (of course ``addCc()`` and ``addBcc()`` exist, too). The subject is defined intuitively. .. note:: Do you **miss a feature in Apache Zeta Components**? Qafoo experts offer you `payed development at fair rates`__! __ /services/support.html#open-source-sponsoring So, if you are sending HTML email, it is good practice to at least include alternative plain text content which is displayed by the email client if it cannot handle HTML email or if the user simply switched it off. Therefore, an ``ezcMailText`` object is created first. The ``ezcMailText`` class (as the ``ezcMail`` class itself) extends ``ezcMailPart`` and can therefore be used to compose email bodies. HTML is nothing really more than plain text, but a corresponding MIME type must be indicated in the email source. Therefore the ``$htmlPart`` needs the ``subType`` property to be set accordingly. To include an image from a file, you need a ``ezcMailFile`` part. If you now want to reference this part in the HTML part, you need to give it a ``contentId`` (*CID*). You know with IDs they may be somehow *arbitrary*, but excluding white spaces and special chars is a good idea. The HTML part already used the CID of the included image in the ``src`` attribute of the ``img`` tag to reference it. Now all elements of the desired email have been created and the body can be composed: Since plain text and html parts should be alternatives, an ``ezcMailMultipartAlternative`` part is used to wrap them in the body. The HTML part is in addition related to the file part (the image) and is therefore put into an according container to reflect this. Now the ``ezcMail`` object is ready for sending. In order to do this, you need an instance of ``ezcMailTransport``. In the example, ``ezcMailMtaTransport`` is used, which sends mails using PHPs ``mail()`` function. Alternatively, you could connect to an SMTP server directly, using the ``ezcMailSmtpTransport``. The latter one uses PHPs socket API for connection, not an SMTP extension. You see, sending HTML email with embedded images can be so easy … -------------- Receiving mail -------------- While there are many mail sending components for PHP out there, libraries to retrieve and parse mail are no that common. The Zeta Mail component allows you to do both. So, maybe you remember the times before smart phones, when you were lucky to have your phone support email? The following script reads all mails from an IMAP inbox and creates imaginary blog entries from them:: require_once 'Base/src/ezc_bootstrap.php'; require_once 'blog_entry.php'; require_once 'blog_entry_creator.php'; $imapOptions = new ezcMailImapTransportOptions(); $imapOptions->ssl = true; $imap = new ezcMailImapTransport( '', 993, $imapOptions ); $imap->authenticate( '', 'foo23bar' ); $imap->selectMailbox( 'Inbox' ); $messageSet = $imap->fetchAll(); $parser = new ezcMailParser(); $mails = $parser->parseMail( $messageSet ); $blogEntryCreator = new qaBlogEntryCreator(); foreach ( $mails as $mail ) { $entry = $blogEntryCreator->createEntry( $mail ); $entry->save(); } The initial two ``require_once`` statements include custom classes needed in the example. These are shown below, as they are needed. In order to connect to an IMAP server with SSL encryption an options object is first created and the corresponding option is set. After that, an instance of ``ezcMailImapTransport`` is used for the actual connection. This object communicates with the server through sockets and therefore does not need any special extension. You see some of its possibilities in action in the example, but there are far more. Look them up in the `IMAP Transport documentation`__ when you need them. __ .. note:: Do you want you and your colleagues to become **experts in using Zeta Components**? Qafoo offers you a `highly customized training`__! __ /services/training.html Of course you need to authenticate against the server and select a mailbox to browse. The ``fetchAll()`` method of the IMAP transport returns a so-called mail set object, which abstracts reading mails from IMAP. You can create similar sets from e.g. mbox files. The ``ezcMailParser`` object is responsible for parsing such a set of mails into ``ezcMail`` objects. Exactly, they return you the very same data structure you use for creating mails, isn't that cute? You can see what more you can do with this in the next example. After parsing the mails into an array of ``ezcMail`` instances, we use the custom ``qaBlogEntryCreator`` class to process them:: class qaBlogEntryCreator { protected $entry; public function createEntry( ezcMail $mail ) { $this->entry = new qaBlogEntry(); $this->entry->setSubject( $mail->subject ); $walkContext = new ezcMailPartWalkContext( array( $this, 'walkPart' ) ); $walkContext->filter = array( 'ezcMailText', 'ezcMailFile' ); $mail->walkParts( $walkContext, $mail ); return $this->entry; } public function walkPart( ezcMailPartWalkContext $context, ezcMailPart $part ) { switch ( true ) { case ( $part instanceof ezcMailFile ): $this->entry->addImage( $part->contentId, $part->fileName ); break; case ( $part instanceof ezcMailText ): if ( $part->subType === 'html' ) { $this->entry->setContent( $part->text ); } break; } } } The ``createEntry()`` method is used in the example to create a blog entry from a mail object. It creates a new, rudimentary blog entry object and sets the subject for the blog entry from the emails subject. After that, a so-called *walk context* is created. This context determines a callback to which processing of a mail part (remember mail parts from the last example?) is delegated while the parts of a mail are walked recursively. In addition to that, the ``$walkContext`` is provided with a filter, determining a whitelist for interesting mail parts. For the blog entry we need an HTML content part and potential files. Walking the mail parts recursively is done by calling the mails ``walkParts()`` method with the created context and a root part to start with. .. note:: Do you want to `learn professional object oriented design`__? **Rent a Qafoo expert for your training.** __ /services/training.html During the walk, the ``qaBlogEntryCreator->walkPart()`` method is called for every ``ezcMailText`` and ``ezcMailFile`` part. Inside this method, files are added as images to the blog entry, using their content ID and file path. The attached files do already reside on your disk at this stage, so file path points into a temp dir (specified through options or system default). The content ID is needed to replace the ```` parts of the HTML content in reverse order to what you saw in the first example. The HTML content can simply be extracted. ---------------- Sending a digest ---------------- The last example in this blog entry shows how to combine receiving and sending email using the Zeta Mail component. Imagine you have a dedicated mail box for support issues, which is maintained by some of your colleagues. You don't want to be bothered by every single mail, but since you are curious, you want to receive a digest with all mails received during the day in the evening. Nothing easier than that:: require_once 'Base/src/ezc_bootstrap.php'; $imapOptions = new ezcMailImapTransportOptions(); $imapOptions->ssl = true; $imap = new ezcMailImapTransport( '', 993, $imapOptions ); $imap->authenticate( '', 'foo23bar' ); $imap->selectMailbox( 'Inbox' ); $mailSet = $imap->fetchAll(); $parser = new ezcMailParser(); $retMails = $parser->parseMail( $mailSet ); $mail = new ezcMail(); $mail->from = new ezcMailAddress( '' ); $mail->addTo( new ezcMailAddress( '', 'Any Body' ) ); $mail->subject = 'Daily digest'; $digest = new ezcMailMultipartDigest(); foreach ( $retMails as $retMail ) { $digest->appendPart( new ezcMailRfc822Digest( $retMail ) ); } $mail->body = $digest; $transport = new ezcMailMtaTransport(); $transport->send( $mail ); The first part is already known from the last example: 1. Connect to the IMAP server 2. authenticate and select the mailbox 3. receive and parse the mails. In order to send a digest, you of course need a new ``ezcMail`` object with corresponding ``from``, *to* and ``subject`` information. However, this email does not contain a plain text, HTML or combined body, but a digest. This digest is represented as an instance of ``ezcMailMultipartDigest``. To this base body part, all the retrieved mails are then added as digest parts (``ezcMailRfc822Digest``) and the part is simply set as the body of the mail. Ready to go, the mail is sent in the same way is seen in example 1. ---------- Conclusion ---------- I hope you saw that the `Zeta Mail component`__ is a very powerful tool for sending and receiving mails. If you are in the need of sending or processing mails the next time, just give it a try. __ Of course, if you are keen on mail and have a cool idea for the component or miss a feature, please join us in the `Apache Zeta Components`__ project over at the `Apache foundation`__! __ __ .. Local Variables: mode: rst fill-column: 79 End: vim: et syn=rst tw=79 Trackbacks ========== Comments ======== - Stephen S. Musoke at Mon, 29 Nov 2010 05:55:48 +0100 How does the ZetaMail compare to PHPMailer and SwiftMailer, similar examples: - PHPMailer - - Swift Mailer - - Tobias Schlitt at Wed, 01 Dec 2010 10:52:57 +0100 I don't know much about neither of them. However, I had a quick look at the code of both of them. PHPMailer looks much more monolithic and inflexible than Zeta Mail. Zeta Mail follows OOP principles quite good, while PHPMailer mainly consists of 3 huge classes (the main class source file is ~73kb). In addition, PHPMailer seems to miss mail receiving and parsing functionality, as far as I could see. The Swift Mailer code seems to be more flexible than PHPMailer one. It appears to me that it supports a huge lot of features around mail sending, but mail receiving and parsing is not supported. Furthermore I'm not sure how easy it would be to extend the library for additional MIME parts like digest. Please correct me if I'm wrong. Regards, Toby - Stephen S. Musoke at Thu, 02 Dec 2010 15:35:29 +0100 I now see what you are saying There seems to be a need to create many object instances, which while elegant will definitely make the library seem daunting to new users and adopters Is there a way of having some of the classes hidden from the developer, via public setters/getters that abstract the details For example when adding an address in PHP Mailer, you provide an email and a name (optional), the ezcMailAddress instance can be created internally I think Zend Framework has this kind of abstraction where you can provide an array of options (including) a class name and the object classes are initialized for the user Your thoughts? - Tobias Schlitt at Thu, 02 Dec 2010 15:47:10 +0100 Hi Stephen, if you don't want to deal with all the internal stuff, we have the ezcMailComposer, which provides a convenience facade for the most common cases in a single object. That is: Simple text mail, HTML mail, HTML / Text alternative, Attachements. You only need to deal with very few objects. Find an example here: However, if you need to build more complex mail, you still can do it. And I think that's the more important point here. We do not make use of classical getters and setters, but instead use overloading to allow you simple $foo->bar access to properties. Therefore we wrap the email address into a dedicated object. I personally don't consider its usage daunting, do you? I'm not sure what you mean with your last sentence. It somewhat sounds like a dependency injection container (DIC). Did I get it wrong? If now, we don't have a DIC in Zeta Components. Our way of handling configuration of components are option classes. You can create an instance of an option class, which validates the configuration values you set, and then submit it to the constructor of the class you want to instantiate. This mechanism can of course be used to integrate Zeta Components into a DIC. HTH, Toby - Stephen S. Musoke at Fri, 03 Dec 2010 09:47:14 +0100 The composer is less daunting than the example in the blog above. Under normal conditions its easy to digest a lot of code, but my experience has been that with newer developers or when searching for a solution under pressure, the more code there is, the less you an understand. Thank you for taking the time to clarify the issues, and Keep up the excellent job that you are doing. - Tobias Schlitt at Fri, 03 Dec 2010 09:49:14 +0100 Yeah, I understand that issue. However, it's not easy to provide both, flexibility to do all the nifty stuff and an easy way to get the most wanted stuff done. However, we try. :) If you want to, please subscribe to the Zeta developer list ( to give us further feedback where we could offer easier ways. Thanks for your feedback!