Zeta Components - high quality PHP components

eZ Components - Mail

Introduction

The Mail component provides functionality to send, retrieve and parse mail messages. If you require an easy way to send a mail, use the ezcMailComposer class, which allows you to send HTML mails with images, attachments and an optional text part. If you require more advanced mail messages, you can build the complete message yourself using the ezcMailPart derived classes. You can retrieve mail messages from different sources using the supported transports.

Class overview

This section gives you an overview of the main classes in the Mail component.

ezcMailComposer
This is a convenience class that allows you to send plain text or HTML messages with attachments, without having to construct the parts of the message yourself. Most users will use this class.
ezcMail
If ezcMailComposer does not have the functionality you require, you can use the ezcMail class to build MIME-structured mail from scratch. This requires basic knowledge about how a mail is structured.
ezcMailAddress
This small class represents a mail address with an optional name. It is used by both ezcMailComposer and ezcMail to set recipient addresses.
ezcMailParser
This class parses mail messages from text into ezcMail structures. You can use it together with the mail retrieval transport classes.
ezcMailSmtpTransport
Sends mails using an SMTP server. After sending a mail, the connection can be kept alive so that the next mail sent uses the same connection, speeding up the process.
ezcMailMtaTransport
Sends mails using the PHP mail() function.
ezcMailPop3Transport
Connects to a POP3 server and allows the fetching and deleting of mails.
ezcMailImapTransport
Connects to an IMAP server and allows operations on mails in a mailbox (fetch, delete) and operations on mailboxes (create, delete, rename, append).

Usage

Transport protocols

The Mail component provides transport protocols for both sending and retrieving mail.

For sending mail, the following protocols are supported:

For mail retrieval we currently support the following protocols:

Mail retrieval from other sources include:

Mail parsers

After using a mail retrieval transport to fetch a set of mails, a mail parser can be used to go through the set and extract the needed information like subject, sender, date and attachments from each mail in the set. The ezcMailParser class is used for this purpose.

Mail parts

The ezcMail component supports a wide variety of mail parts that can be used when sending or retrieving mails:

Mail tools

In the ezcMailTools class, you will find various useful static methods that can be used in your applications:

See the ezcMailTools example below for information on how to use these methods.

Building and sending mail

eZ components provides two ways to create mail. The simplest is to use the composer class ezcMailComposer. Using the composer you can send plain text messages, HTML messages with images and messages with attachments. If you require more advanced messages you can also customize them entirely by building it from the scratch using the various part types in ezcMail. The part types are structured the same way as the underlying mail MIME types.

Sending a mail with the composer

Sending a mail using the composer is very straightforward. This small example displays how to send a normal text message.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new mail composer object
  4. $mail = new ezcMailComposer();
  5. // Specify the "from" mail address
  6. $mail->from = new ezcMailAddress'sender@example.com''Adrian Ripburger' );
  7. // Add one "to" mail address (multiple can be added)
  8. $mail->addTo( new ezcMailAddress'receiver@example.com''Maureen Corley' ) );
  9. // Specify the subject of the mail
  10. $mail->subject "This is the subject of the example mail";
  11. // Specify the body text of the mail
  12. $mail->plainText "This is the body of the example mail.";
  13. // Generate the mail
  14. $mail->build();
  15. // Create a new MTA transport object
  16. $transport = new ezcMailMtaTransport();
  17. // Use the MTA transport to send the created mail object
  18. $transport->send$mail );
  19. ?>

Sending a mail with HTML, inline images and attachments

This example shows how to send a mail with HTML text, images and attachments using the ezcMailComposer class.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new mail composer object
  4. $mail = new ezcMailComposer();
  5. // Specify the "from" mail address
  6. $mail->from = new ezcMailAddress'john@example.com''John Doe' );
  7. // Add one "to" mail address (multiple can be added)
  8. $mail->addTo( new ezcMailAddress'cindy@example.com''Cindy Doe' ) );
  9. // Specify the subject of the mail
  10. $mail->subject "Example of an HTML email with attachments";
  11. // Specify the plain text of the mail
  12. $mail->plainText "Here is the text version of the mail. This is displayed if the client can not understand HTML";
  13. // Specify the html text of the mail
  14. $mail->htmlText "<html>Here is the HTML version of your mail with an image: <img src='file://path_to_image.jpg' /></html>";
  15. // Add a file as an attachment to the mail
  16. $mail->addFileAttachment'path_to_attachment.file' );
  17. // Add a string as an attachment to the mail, with 'filename' as the name of the attachment in the mail
  18. $contents 'contents of the attachment'// can be a binary string, eg. contents of an image file
  19. $mail->addStringAttachment'filename'$contents );
  20. // Build the mail object
  21. $mail->build();
  22. // Create a new MTA transport object
  23. $transport = new ezcMailMtaTransport();
  24. // Use the MTA transport to send the created mail object
  25. $transport->send$mail ); 
  26. ?>

The mime-type of the attachment can be specified if needed. See the documentation for the functions addFileAttachment() and addStringAttachment() for more details.

Securing HTML mails which include file:// in image tags

By default, if the htmlText property contains an HTML image tag with file:// in href, that file will be included in the created message.

Example:

<img src="file:///home/me/image.jpg" />

This can be a security risk if a user links to another file, for example logs or password files. With the automaticImageInclude option (default value true) from ezcMailComposerOptions, the automatic inclusion of files can be turned off.

Example:

$options = new ezcMailComposerOptions(); $options->automaticImageInclude = false; // default value is true $mail = new ezcMailComposer( $options ); // ... add To, From, Subject, etc to $mail $mail->htmlText = "<html>Here is the image: <img src="file:///etc/passwd" /></html>"; // ... send $mail

After running the above code, the sent mail will not contain the file specified in the htmlText property.

Building a mail from scratch

The class structure of the Mail component follows that of the mail MIME. This means that you can build advanced MIME messages part by part.

The first example displays how to build a similar message to the one above.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new mail object
  4. $mail = new ezcMail();
  5. // Specify the "from" mail address
  6. $mail->from = new ezcMailAddress'sender@example.com''Boston Low' );
  7. // Add one "to" mail address (multiple can be added)
  8. $mail->addTo( new ezcMailAddress'receiver@example.com''Maggie Robbins' ) );
  9. // Specify the subject of the mail
  10. $mail->subject "This is the subject of the example mail";
  11. // Specify the body text of the mail as a ezcMailText object
  12. $mail->body = new ezcMailText"This is the body of the example mail." );
  13. // Create a new MTA transport object
  14. $transport = new ezcMailMtaTransport();
  15. // Use the MTA transport to send the created mail object
  16. $transport->send$mail );
  17. ?>

As you can see, there is not much difference compared to the composer version. In the next example we will add an attachment to our manually built mail:

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new mail object
  4. $mail = new ezcMail();
  5. // Specify the "from" mail address
  6. $mail->from = new ezcMailAddress'sender@example.com''Bernard Bernoulli' );
  7. // Add one "to" mail address (multiple can be added)
  8. $mail->addTo( new ezcMailAddress'receiver@example.com''Wendy' ) );
  9. // Specify the subject of the mail
  10. $mail->subject "This is the subject of the example mail";
  11. // Create a text part to be added to the mail
  12. $textPart = new ezcMailText"This is the body of the example mail." );
  13. // Create a file attachment to be added to the mail
  14. $fileAttachment = new ezcMailFile"~/myfile.jpg" );
  15. // Specify the body of the mail as a multipart-mixed of the text part and the file attachment
  16. $mail->body = new ezcMailMultipartMixed$textPart$fileAttachment );
  17. // Create a new MTA transport object
  18. $transport = new ezcMailMtaTransport();
  19. // Use the MTA transport to send the created mail object
  20. $transport->send$mail );
  21. ?>

By default the generated message will contain a text which is displayed by e-mail clients lacking MIME-support:

This message is in MIME format. Since your mail reader does not understand this format, some or all of this message may not be legible.

This text can be changed or removed by setting the property noMimeMessage on the multipart, before generating the mail or sending it. Example:

$part = new ezcMailMultipartMixed( $textPart, $fileAttachment ); $part->noMimeMessage = 'Your e-mail client does not understand MIME.'; $mail = new ezcMail(); $mail->body = $part;

Building MIME structures that work

When you build mail mail from scratch most combinations of MailParts will produce valid messages. Unfortunately, even though a message is valid structurally that does not mean that all mail clients will display it properly. This section gives a few hints on what to do and what not to do.

  1. Ommit Multipart/Mixed parts with only one part. Some mail clients like Mozilla Thunderbird do not display these correctly. Of course, they are not necessary either.

  2. Mail with alternative text/HTML parts and common attachments can be implemented in many ways. However, we have only found one structure that seems to work across all clients: MultipartMixed( MultipartAlternative( TextPart, TextPart ), FilePart, ... )

Sending a mail using SMTP

This example shows how to send a mail with SMTP, by using an SSLv3 connection:

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new mail composer object
  4. $mail = new ezcMailComposer();
  5. // Specify the "from" mail address
  6. $mail->from = new ezcMailAddress'sender@example.com''Adrian Ripburger' );
  7. // Add one "to" mail address (multiple can be added)
  8. $mail->addTo( new ezcMailAddress'receiver@example.com''Maureen Corley' ) );
  9. // Specify the subject of the mail
  10. $mail->subject "This is the subject of the example mail";
  11. // Specify the body text of the mail
  12. $mail->plainText "This is the body of the example mail.";
  13. // Generate the mail
  14. $mail->build();
  15. // Create a new SMTP transport object with an SSLv3 connection.
  16. // The port will be 465 by default, use the 4th argument to change it.
  17. // Username and password (2nd and 3rd arguments) are left blank, which means
  18. // the mail host does not need authentication.
  19. // The 5th parameter is the $options object which specifies a SSLV3 connection
  20. // (default is ezcMailSmtpTransport::CONNECTION_PLAIN).
  21. $options = new ezcMailSmtpTransportOptions();
  22. $options->connectionType ezcMailSmtpTransport::CONNECTION_SSLV3;
  23. $transport = new ezcMailSmtpTransport'mailhost.example.com'''''null$options );
  24. // The option can also be specified via the option property:
  25. $transport->options->connectionType ezcMailSmtpTransport::CONNECTION_SSLV3;
  26. // Use the SMTP transport to send the created mail object
  27. $transport->send$mail );
  28. ?>

Using stronger authentication methods with the SMTP transports

The SMTP transports supports various authentication methods: DIGEST-MD5, CRAM-MD5, NTLM, LOGIN, PLAIN. Not all methods are supported by all servers, and some servers don't support authentication at all. NTLM authentication requires the mcrypt PHP extension.

By default, the SMTP transport tries to login anonymously to the SMTP server (if an empty username and password have been provided), or to authenticate with the strongest method supported by the server (if username and password have been provided). The preferred authentication method can be changed with the option preferredAuthMethod. See the ezcMailSmtpTransport class for a list of supported authentication methods.

If the preferred method is specified via options, only that authentication method will be attempted on the SMTP server. If it fails, an exception will be thrown.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create an SMTP transport and demand NTLM authentication.
  4. // Username and password must be specified, otherwise no authentication
  5. // will be attempted.
  6. // If NTLM authentication fails, an exception will be thrown.
  7. // See the ezcMailSmtpTransport class for a list of supported methods.
  8. $options = new ezcMailSmtpTransportOptions();
  9. $options->preferredAuthMethod ezcMailSmtpTransport::AUTH_NTLM;
  10. $transport = new ezcMailSmtpTransport'mailhost.example.com''username''password'null$options );
  11. // The option can also be specified via the option property:
  12. $transport->options->preferredAuthMethod ezcMailSmtpTransport::AUTH_NTLM;
  13. // Use the SMTP transport to send the created mail object
  14. $transport->send$mail );
  15. ?>

Avoid Bcc headers appearing in the sent mails

By default the Mail component leaves it to the SMTP server to strip the Bcc header from the sent mails. Some SMTP servers will not strip the Bcc header. If you want to be sure that the Bcc header will not appear in sent mails, use the stripBccHeader option from ezcMailOptions:

$options = new ezcMailOptions(); $options->stripBccHeader = true; // default is false $mail = new ezcMail( $options );

Character encoding

Most of the world does not speak and write US ASCII and thus requires more advanced character encoding to display mail correctly.

The following example shows how to send a mail with the body and subject encoded with iso-8859-1 and a custom header encoded with iso-8859-1:

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new mail object
  4. $mail = new ezcMail();
  5. // Specify the "from" mail address
  6. $mail->from = new ezcMailAddress'sender@example.com''Norwegian characters: æøå''iso-8859-1' );
  7. // Add one "to" mail address (multiple can be added)
  8. $mail->addTo( new ezcMailAddress'reciever@example.com''More norwegian characters: æøå''iso-8859-1' ) );
  9. // Specify the subject of the mail
  10. $mail->subject 'Oslo ligger sør i Norge og har vært landets hovedstad i over 600 år.';
  11. // Specify the charset of the subject
  12. $mail->subjectCharset 'iso-8859-1';
  13. // Add a header with the default charset (us-ascii)
  14. $mail->setHeader'X-Related-City''Moscow' );
  15. // Add a header with a custom charset (iso-8859-5)
  16. $mail->setHeader'X-Related-Movie''James Bond - Å leve og la dø''iso-8859-1' );
  17. // Specify the body as a text part, also specifying it's charset
  18. $mail->body = new ezcMailText'Oslo be grunnlagt rundt 1048 av Harald Hardråde.''iso-8859-1' );
  19. // Create a new MTA transport object
  20. $transport = new ezcMailMtaTransport();
  21. // Use the MTA transport to send the created mail object
  22. $transport->send$mail );
  23. ?>

You can of course choose and combine any available character sets. Make sure that the input text is encoded as specified, or you may get unexpected results.

Extending the Mail component

It is possible to extend the Mail component if you require part types that are not supported by default. The following two examples shows how you can implement support for digest mail messages as attachments to your mail. This functionality is available through the ezcMailRfc822Digest class. For the sake of this example, we will recreate it in the MailRFC822Digest class.

The mail system already supports sending attachments through the ezcMailMultipartMixed type. Unfortunately directly inserting an ezcMail object as a part does not work. This is because mail digests are a special case: they require two extra headers that are separated by the normal mail headers.

To make it work, we create the class RFC822Digest to add these headers:

  1. <?php
  2. class RFC822Digest extends ezcMailPart
  3. {
  4.     private $mail null;
  5.     public function __constructezcMail $mail )
  6.     {
  7.         $this->mail $mail;
  8.         $this->setHeader'Content-Type''message/rfc822' );
  9.         $this->setHeader'Content-Disposition''inline' );
  10.     }
  11.     public function generateBody()
  12.     {
  13.         return $this->mail->generate();
  14.     }
  15. }
  16. ?>

Our new class extends the ezcMailPart class. This is required for all parts of a mail. ezcMailPart provides two important methods that we can override: ezcMailPart::generateHeaders() and ezcMailPart::generateBody(). These two methods are called in succession by the parent part and should return the headers and the body text of the part.

We do not need to override generateHeaders() since we can simply set the headers we want directly on the object. We do need to override generateBody(), since we want to include the full text of the mail digest.

The new class can be used directly when building a mail. The example assumes that a valid ezcMail object is available in the $digest variable.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new mail object
  4. $mail = new ezcMail();
  5. // Specify the "from" mail address
  6. $mail->from = new ezcMailAddress'sender@example.com''Largo LaGrande' );
  7. // Add one "to" mail address (multiple can be added)
  8. $mail->addTo( new ezcMailAddress'receiver@example.com''Wally B. Feed' ) );
  9. // Specify the subject of the mail
  10. $mail->subject "This is the subject of the mail with a mail digest.";
  11. // Create a text part to be added to the mail
  12. $textPart = new ezcMailText"This is the body of the mail with a mail digest." );
  13. // Specify the body of the mail as a multipart-mixed of the text part and a RFC822 digest object
  14. // where $digest is an ezcMail object
  15. // and RFC822Digest is the class from the previous example
  16. $mail->body = new ezcMailMultipartMixed$textPart, new RFC822Digest$digest ) );
  17. // Create a new MTA transport object
  18. $transport = new ezcMailMtaTransport();
  19. // Use the MTA transport to send the created mail object
  20. $transport->send$mail );
  21. ?>

Using the ezcMailTools class

In this example, we use the various methods from the ezcMailTools class.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. $mailAddresses = array(
  4.                         new ezcMailAddress'john@example.com''Jøhn Doe''ISO-8859-1' ),
  5.                         new ezcMailAddress'jane@example.com''Jane Doe' )
  6.                       );
  7. $addresses '=?ISO-8859-1?B?SsO4aG4gRG9l?= <john@example.com>, Jane Doe <jane@example.com';
  8. // Convert ezcMailAddress to string representation
  9. var_dumpezcMailTools::composeEmailAddress$mailAddresses[0] ) );
  10. var_dumpezcMailTools::composeEmailAddresses$mailAddresses ) );
  11. // Convert string to ezcMailAddress
  12. var_dumpezcMailTools::parseEmailAddress$addresses ) );
  13. var_dumpezcMailTools::parseEmailAddresses$addresses ) );
  14. // Validate an email address (with a regular expression, without checking for MX records)
  15. $isValid ezcMailTools::validateEmailAddress'john.doe@example.com' );
  16. // Validate an email address with MX records check.
  17. // MX record checking does not work on Windows due to the lack of getmxrr()
  18. // and checkdnsrr() PHP functions. The ezcBaseFunctionalityNotSupportedException
  19. // is thrown in this case.
  20. // set this to your mail server, it is used in a
  21. // 'HELO SMTP' command to validate against MX records
  22. ezcMailTools::$mxValidateServer 'your.mail.server';
  23. // set this to a mail address such as 'postmaster@example.com', it is used in a
  24. // 'MAIL FROM' SMTP command to validate against MX records
  25. ezcMailTools::$mxValidateAddress 'email.address@mail.server';
  26. $isValid ezcMailTools::validateEmailAddress'john.doe@example.com'true );
  27. // Create a new mail object
  28. $mail = new ezcMail();
  29. $mail->from $mailAddresses[1];
  30. $mail->addTo$mailAddresses[0] );
  31. $mail->subject "Top secret";
  32. // Use the lineBreak() method
  33. $mail->body = new ezcMailText"Confidential" ezcMailTools::lineBreak() . "DO NOT READ" );
  34. $mail->generate();
  35. // Create a reply message to the previous mail object
  36. $reply ezcMailTools::replyToMail$mail, new ezcMailAddress'test@example.com''Reply Guy' ) );
  37. ?>

Mail retrieval and parsing

Many applications need to interact with a message store. The Mail component makes this easy through the class ezcMailParser and the mail retrieval transport classes. Mail is fetched, parsed and returned to you in the same structure that is used to send mail.

The Mail component currently allows you to fetch and parse mail messages from POP3, IMAP, mbox files, single mail files and from variables. The parser fully supports mail in all character sets, multipart mail (attachments), HTML mail, HTML mail with images and digest messages.

Retrieving mail using POP3

The following example shows how to fetch messages from a POP3 account using various methods and to parse the messages for use.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new POP3 transport object by specifying the server name
  4. $pop3 = new ezcMailPop3Transport"pop3.example.com" );
  5. // Authenticate to the POP3 server
  6. $pop3->authenticate"user""password" );
  7. // Get the number of messages on the server and their combined size
  8. // in the variables $num and $size
  9.     $pop3->status$num$size );
  10. // Get the list of message numbers on the server and their sizes
  11. // the returned array is something like: array( 1 => 1500, 2 => 45200 )
  12. // where the key is a message number and the value is the message size
  13.     $messages $pop3->listMessages();
  14. // Get the list of message unique ids on the server and their sizes
  15. // the returned array is something like: array( 1 => '00000f543d324', 2 => '000010543d324' )
  16. // where the key is an message number and the value is the message unique id
  17.     $messages $pop3->listUniqueIdentifiers();
  18. // Usually you will call one of these 3 fetch functions:
  19.     // Fetch all messages on the server
  20.     $set $pop3->fetchAll();
  21.     // Fetch one message from the server (here: get the message no. 2)
  22.     $set $pop3->fetchByMessageNr);
  23.     // Fetch a range of messages from the server (here: get 4 messages starting from message no. 2)
  24.     $set $pop3->fetchFromOffset2);
  25. // Delete a message from the server
  26.     $pop3->delete);
  27. // Use this to keep the connection alive
  28.     $pop3->noop();
  29. // Create a new mail parser object
  30. $parser = new ezcMailParser();
  31. // Parse the set of messages retrieved from the server earlier
  32. $mail $parser->parseMail$set );
  33. ?>

The parser returns an array of ezcMail messages with parts organized according to the MIME structure of the mail.

Retrieving mail using IMAP

The following example shows how to fetch messages from an IMAP account using various functions and to parse the messages for use.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new IMAP transport object by specifying the server name
  4. $imap = new ezcMailImapTransport"imap.example.com" );
  5. // Authenticate to the IMAP server
  6. $imap->authenticate"user""password" );
  7. // Select the Inbox mailbox
  8. $imap->selectMailbox'Inbox' );
  9. // Get the number of messages on the server, combined size, number of recent
  10. // messages and number of unseen messages
  11. // in the variables $num, $size, $recent, $unseen
  12.     $imap->status$num$size$recent$unseen );
  13. // Get the list of message numbers on the server and their sizes
  14. // the returned array is something like: array( 1 => 1500, 2 => 45200 )
  15. // where the key is a message number and the value is the message size
  16.     $messages $imap->listMessages();
  17. // Get the list of message unique ids on the server and their sizes
  18. // the returned array is something like: array( 1 => '15', 2 => '16' )
  19. // where the key is an message number and the value is the message unique id
  20.     $messages $imap->listUniqueIdentifiers();
  21. // Usually you will call one of these fetch functions:
  22.     // Fetch all messages on the server
  23.     $set $imap->fetchAll();
  24.     // Fetch one message from the server (here: get the message no. 2)
  25.     $set $imap->fetchByMessageNr);
  26.     // Fetch a range of messages from the server (here: get 4 messages starting from message no. 2)
  27.     $set $imap->fetchFromOffset2);
  28.     // Fetch messages which have a certain flag
  29.     // See the function description for a list of supported flags
  30.     $set $imap->fetchByFlag"DELETED" );
  31.     // Fetch a range of messages sorted by Date
  32.     // Use this to page through a mailbox
  33.     // See the function description for a list of criterias and for how to sort ascending or descending
  34.     $set $imap->sortFromOffset110"Date" );
  35.     // Sort the specified messages by Date
  36.     // See the function description for a list of criterias and for how to sort ascending or descending
  37.     $set $imap->sortMessages"1,2,3,4,5""Date" );
  38.     // Fetch messages which match the specified criteria.
  39.     // See the section 6.4.4. of RFC 1730 or 2060 for a list of criterias
  40.     // (http://www.faqs.org/rfcs/rfc1730.html)
  41.     // The following example returns the messages flagged as SEEN and with
  42.     // 'release' in their Subject
  43.     $set $imap->searchMailbox'SEEN SUBJECT "release"' );
  44. // Delete a message from the server (message is not physically deleted, but it's
  45. // list of flags get the "Deleted" flag.
  46.     $imap->delete);
  47. // Use this to permanently delete the messages flagged with "Deleted"
  48.     $imap->expunge();
  49. // Use this to keep the connection alive
  50.     $imap->noop();
  51. // Create a new mail parser object
  52. $parser = new ezcMailParser();
  53. // Parse the set of messages retrieved from the server earlier
  54. $mail $parser->parseMail$set );
  55. ?>

The parser returns an array of ezcMail messages with parts organized according to the MIME structure of the mail.

Additional usage of the IMAP transport

The IMAP transport supports multiple mailboxes. In the following example, we work with mailboxes and flags.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new IMAP transport object by specifying the server name
  4. $imap = new ezcMailImapTransport"imap.example.com" );
  5. // Authenticate to the IMAP server
  6. $imap->authenticate"user""password" );
  7. // Select the Inbox mailbox
  8. $imap->selectMailbox'Inbox' );
  9. // List the capabilities of the IMAP server
  10.     $capabilities $imap->capability();
  11. // List existing mailboxes
  12.     $mailboxes $imap->listMailboxes"""*" );
  13. // Fetch the hierarchy delimiter character (usually "/")
  14.     $delimiter $imap->getHierarchyDelimiter();
  15. // Create a new mailbox
  16.     $imap->createMailbox"Reports 2006" );
  17. // Delete a mailbox
  18.     $imap->deleteMailbox"Reports 2005" );
  19. // Rename a mailbox
  20.     $imap->renameMailbox"Reports 2006""Reports" );
  21. // Copy messages from the selected mailbox (here: Inbox) to another mailbox
  22.     $imap->copyMessages"1,2,4""Reports" );
  23. // Set a flag to messages
  24. // See the function description for a list of supported flags
  25.     $imap->setFlag"1,2,4""DELETED" );
  26. // Clears a flag from messages
  27. // See the function description for a list of supported flags
  28.     $imap->clearFlag"1,2,4""SEEN" );
  29. // Append a message to a mailbox. $mail must contain the mail as text
  30. // Use this with a "Sent" or "Drafts" mailbox
  31.     $imap->append"Sent"$mail );
  32. ?>

Refering messages by their unique IDs in IMAP

With IMAP it is possible to refer to messages using their unique IDs, which usually never change, unlike message numbers. Unfortunately this is not possible yet in POP3.

The next example shows how to enable refering to messages by their unique IDs. To see the list of the methods which support unique IDs referencing, consult the documentation for the ezcMailImapTransport class.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new IMAP transport object by specifying the server name, default port
  4. // and that the IMAP commands will work with unique IDs instead of message numbers
  5. $options = new ezcMailImapTransportOptions();
  6. $options->uidReferencing true;
  7. $imap = new ezcMailImapTransport"imap.example.com"null$options );
  8. // Authenticate to the IMAP server
  9. $imap->authenticate"user""password" );
  10. // Select the Inbox mailbox
  11. $imap->selectMailbox'Inbox' );
  12. // The other IMAP examples apply here, with the distinction that unique IDs are
  13. // used to refer to messages instead of message numbers
  14. ?>

Working with transport options

The POP3, IMAP and SMTP transports allow options to be specified when calling the transport constructors. These options are implemented in the classes ezcMailPop3TransportOptions, ezcMailImapTransportOptions and ezcMailSmtpTransportOptions. In the following example, we specify options when calling the POP3 transport constructor.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new POP3 transport with a plain connection (default port is 110,
  4. // you can specify a different one using the second parameter of the constructor).
  5. // A timeout option is specified to be 10 seconds (default is 5).
  6. // Another option to be specified is the authenticationMethod as APOP (default is plain text)
  7. $options = new ezcMailPop3TransportOptions();
  8. $options->timeout 10;
  9. $options->authenticationMethod ezcMailPop3Transport::AUTH_APOP;
  10. $pop3 = new ezcMailPop3Transport"pop3.example.com"null$options );
  11. // Authenticate to the POP3 server
  12. $pop3->authenticate"user""password" );
  13. ?>

Using SSL with POP3 and IMAP

The POP3 and IMAP transports allow SSL connections (if the mail server supports them). In the following example, we connect to an IMAP server using an SSL connection.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new IMAP transport with an SSL connection (default port is 993,
  4. // you can specify a different one using the second parameter of the constructor).
  5. $options = new ezcMailImapTransportOptions();
  6. $options->ssl true;
  7. $imap = new ezcMailImapTransport"imap.example.com"null$options );
  8. // Authenticate to the IMAP server
  9. $imap->authenticate"user""password" );
  10. // Select the Inbox mailbox
  11. $imap->selectMailbox'Inbox' );
  12. ?>

Retrieving mail from mbox files

The following example shows how to fetch all messages from an mbox file and to parse the messages for use.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new Mbox transport object by specifiying an existing mbox file name
  4. $mbox = new ezcMailMboxTransport"/path/file.mbox" );
  5. // Fetch all messages from the mbox file
  6. $set $mbox->fetchAll();
  7. // Create a new mail parser object
  8. $parser = new ezcMailParser();
  9. // Parse the set of messages retrieved from the mbox file earlier
  10. $mail $parser->parseMail$set );
  11. ?>

The parser returns an array of ezcMail messages with parts organized according to the MIME structure of the mail.

Parsing a message set

The following example shows how to parse a message set retrieved from an IMAP or POP3 account, an mbox file, a single mail file or a variable.

  1. <?php
  2. require_once 'tutorial_autoload.php';
  3. // Create a new mail parser object
  4. $parser = new ezcMailParser();
  5. // $set is a message set got from an IMAP, POP3 account or Mbox file
  6. // like for example:
  7. // $mbox = new ezcMailMboxTransport( "/path/file.mbox" );
  8. // $set = $mbox->fetchAll();
  9. $mail $parser->parseMail$set );
  10. for ( $i 0$i count$mail ); $i++ )
  11. {
  12.     // Process $mail[$i] such as use $mail[$i]->subject, $mail[$i]->body
  13.     echo "From: {$mail[$i]->from}, Subject: {$mail[$i]->subject}\n";
  14.     // Save the attachments to another folder
  15.     $parts $mail[$i]->fetchParts();
  16.     foreach ( $parts as $part )
  17.     {
  18.         if ( $part instanceof ezcMailFile )
  19.         {
  20.             rename$part->fileName'/path/to/save/to/' basename$part->contentDisposition->displayFileName ) );
  21.         }
  22.     }
  23. }
  24. ?>

Because the parser will delete the temporary attachments after the script ends, it is needed to save those files to another directory. On lines 19-26 a way of how to do this is shown. The contentDisposition->displayFileName property of $part was used, as the fileName property of $part contains the raw file name from the mail.

For a more detailed example on how to use a mail object, please see the display example.

For an example on how to display a listing of mails, please see the mail listing example.

For a list of supported mail-related RFCs, please see the RFCs list.

Displaying HTML mail with inline images

In order to display HTML mail with inline images, you need to make sure that the attached images are accessible by the web server. Besides this, you also need to replace the internal mail references to the images with references to the file in the document root. In the following example we use ezcMailTools::replaceContentIdRefs() to do exactly this.

  1. <?php
  2. require 'tutorial_autoload.php';
  3. // Create a mail set from a file, a parser, and parse the e-mail.
  4. $set = new ezcMailFileSet( array( 'test-mail.mail' ) );
  5. $parser = new ezcMailParser();
  6. $mail $parser->parseMail$set );
  7. /**
  8.  * This class is used in the callback for each part that is walked below. It
  9.  * takes care of copying the files and registering both file parts and the HTML
  10.  * text.
  11.  */
  12. class collector
  13. {
  14.     function saveMailPart$context$mailPart )
  15.     {
  16.         // if it's a file, we copy the attachment to a new location, and
  17.         // register its CID with the class - attaching it to the location in
  18.         // which the *web server* can find the file.
  19.         if ( $mailPart instanceof ezcMailFile )
  20.         {
  21.             // copy files to tmp with random name
  22.             $newFile tempnam$this->dir'mail' );
  23.             copy$mailPart->fileName$newFile );
  24.             // save location and setup ID array
  25.             $this->cids[$mailPart->contentId] =
  26.                 $this->webDir '/' basename$newFile );
  27.         }
  28.         // if we find a text part and if the sub-type is HTML (no plain text)
  29.         // we store that in the classes' htmlText property.
  30.         if ( $mailPart instanceof ezcMailText )
  31.         {
  32.             if ( $mailPart->subType == 'html' )
  33.             {
  34.                 $this->htmlText $mailPart->text;
  35.             }
  36.         }
  37.     }
  38. }
  39. // create the collector class and set the filesystem path, and the webserver's
  40. // path to find the attached files (images) in.
  41. $collector = new collector();
  42. $collector->dir "/home/httpd/html/test/ezc";
  43. $collector->webDir '/test/ezc';
  44. // We use the saveMailPart() method of the $collector object function as a
  45. // callback in walkParts().
  46. $context = new ezcMailPartWalkContext( array( $collector'saveMailPart' ) );
  47. // only call the callback for file and text parts.
  48. $context->filter = array( 'ezcMailFile''ezcMailText);
  49. // use walkParts() to iterate over all parts in the first parsed e-mail
  50. // message.
  51. $mail[0]->walkParts$context$mail[0] );
  52. // display the html text with the content IDs replaced with references to the
  53. // file in the webroot.
  54. echo ezcMailTools::replaceContentIdRefs$collector->htmlText$collector->cids );
  55. ?>

Using a custom mail class

When parsing a mail, an object of class ezcMail is created by default. You can change this by specifying a custom mail class to the parser before parsing. The custom mail class must extend ezcMail.

Example:

$parser = new ezcMailParser(); $parser->options->mailClass = 'myCustomMailClass'; // extends ezcMail $parser->parseMail( $set );

Using a custom file class

When parsing a mail, an object of class ezcMailFile is created by default for each file attachment. You can change this by specifying a custom file class to the parser before parsing. The custom file class must extend ezcMailFile.

Example:

$parser = new ezcMailParser(); $parser->options->fileClass = 'myCustomFileClass'; // extends ezcMailFile $parser->parseMail( $set );

Troubleshooting

MTA: Qmail

Qmail insists on only using "\n" line breaks and will send garbled messages with the default "\r\n" setting. To fix this issue, use ezcMailTools::setLineBreak( "\n" ) before sending mail.

MTA: Sendmail relaying denied

This can happen when the SMTP server you try to use has disabled the sending of mail from computers not connected to its network, or if it requires authentication. Talk to the administrator of the SMTP server to see what the requirements are to send mail.

Check also that sendmail is installed and configured correctly.

For Windows, you need to specify a valid SMTP server in php.ini, or you can download a "fake" sendmail from the internet.

IMAP: Authentication failed

Sometimes the IMAP transport fails to authenticate, in which case the authenticate() method will return false. The application should detect when this occurs and attempt authentication again (for example, for a preset number of times such as three).

IMAP: Could not read from the stream

While using the IMAP methods, it is possible that an ezcMailTransportException is thrown, in which case the connection to the IMAP server is closed. The application should catch this exception and decide how to handle this situation (show an error, reconnect).

Parsing: iconv() notices

If the mail that you try to parse is not encoded properly, the iconv () function will throw notices (from the function convertToUTF8Iconv() in ezcMailCharsetConverter).

To avoid the notices you can use your own conversion function:

1. Create a new function which is similar to convertToUTF8Iconv() from ezcMailCharsetConverter, but which supresses notices and errors (with @ in front of iconv ()):

class myConverter { public static function convertToUTF8IconvNoNotices( $text, $originalCharset ) { if ( $originalCharset === 'unknown-8bit' || $originalCharset === 'x-user-defined' ) { $originalCharset = "latin1"; } return @iconv( $originalCharset, 'utf-8', $text ); } }

2. Use the created function instead of the normal one (set this before parsing mail):

ezcMailCharsetConverter::setConvertMethod( array( 'myConverter', 'convertToUTF8IconvNoNotices' ) );

Parsing: missing characters

If the mail that you try to parse is not encoded properly, the iconv () function will throw notices (from the function convertToUTF8Iconv() in ezcMailCharsetConverter).

To avoid the missing characters you can use your own conversion function:

1. Create a new function which is similar to convertToUTF8Iconv() from ezcMailCharsetConverter, but which uses one of the options //IGNORE or //TRANSLIT for iconv ():

class myConverter { public static function convertToUTF8IconvIgnore( $text, $originalCharset ) { if ( $originalCharset === 'unknown-8bit' || $originalCharset === 'x-user-defined' ) { $originalCharset = "latin1"; } return iconv( $originalCharset, 'utf-8//TRANSLIT', $text ); } }

2. Use the created function instead of the normal one (set this before parsing mail):

ezcMailCharsetConverter::setConvertMethod( array( 'myConverter', 'convertToUTF8IconvIgnore' ) );

See the other examples in ezcMailCharsetConverter, and see also the documentation for the iconv () function to find out how //IGNORE and //TRANSLIT work.

Parsing: broken headers

If the mail contains headers with broken text (eg. 8-bit characters with no character set specified), then the parsed header will contain broken text or missing characters.

For example, when parsing a mail with this header:

Subject: Un Fax a été émis

Then $mail->subject will contain 'Un Fax a t mis' (because the 8-bit characters could not be parsed correctly by ezcMailTools::mimeDecode() due to the missing character set).

In order to be able to get the correct value of the header, use $mail->getHeader( 'Subject' ), which is the raw value of the header (MIME-encoded). Other headers are available as raw through the getHeader() function.

The raw headers (obtained via the function getHeader of ezcMailPart) are MIME-encoded for non-broken headers (eg. '=?iso-8859-1?Q?=E6=F8=E5?='), so if you want to decode them use ezcMailTools::mimeDecode() or implement your own MIME-decoding function.

Parsing: multiple-value headers

Mail headers such as Received can appear multiple times in a mail message. By default the mail parser will only recognize the first value of the header it encounters, and will disregard the others.

To retrieve all the values of a header from a mail in an array, use the second argument for the function $mail->getHeader() with the value true.

Example:

$mail->getHeader( 'Received', true );

This will return an array which looks like this:

array( "from punisher.example.com (punisher.example.com...", "from localhost (localhost [127.0.0.1])...", "from punisher.example.com ([127.0.0.1])...", "from www.example.com (unknown [216.198.224.130]) by...", "from localhost (localhost) by www.example.com..." );

instead of only the first value as a string if the second parameter to getHeader() was not specified.

Parsing: text attachments as file parts

By default, the mail parser creates ezcMailTextPart objects for text attachments found in the mail.

To create ezcMailFile objects instead (for example on servers where internal memory is limited), set this option to the mail parser before parsing:

$parser = new ezcMailParser(); $parser->options->parseTextAttachmentsAsFiles = true; // call $parser->parseMail( $set );

Parsing: attachment file names

When parsing a mail with attachments you can use a code similar to the one in section . The mail part that contains the attachment ($part) has the fileName property which contains the raw file name, contentDisposition->displayFileName which contain the MIME-decoded file name. Use the contentDisposition->displayFileName value to copy the temporary files saved during parsing which contain the attachments, and which will not be available on the next request.

Security

Excluding the User-Agent header

By defaul the Mail component will add the "User-Agent" header containing the string "Zeta Components". This can be considered a security issue. If you do not want to get this header sent along with the email you can use the following code:

$mail = new ezcMailComposer(); // [...] $mail->appendExcludeHeaders(array('User-Agent'));