Handling mail and mime in PHP using the Zend Framework

In: Open Source| PHP| Web development

18 Jul 2008

Handling mail is a very common requirement in web applications. Even the most basic sites usually have a contact form that sends a mail through the server instead of putting a contact mail address for spam-spiders to find. Using PHP's built in function (aptly named mail() ) is relatively straightforward - until you need slightly more advanced features, such as adding and encoding email headers or sending multiple mails efficiently.

Fortunately, the Zend Framework comes with a very capable mail component called Zend_Mail. Zend_Mail abstracts some of the more tedious aspects of mail handling with PHP, including:

  1. Adding and encoding email headers
  2. Protection against header injection
  3. Multiple mail transports (SMTP is useful for sending multiple mails)
  4. Creating and handling mime-compliant multipart messages
  5. Composing HTML emails
  6. Reading mail boxes

Sending mails

Using Zend_Mail is extremely straightforward: (Taken from the ZF documentation)

  1. require_once 'Zend/Mail.php';
  2. $mail = new Zend_Mail();
  3. $mail->setBodyText('This is the text of the mail.'); //Alternatively using setBodyHtml for HTML messages
  4. $mail->setFrom('somebody@example.com', 'Some Sender'); //Adds a 'from' header
  5. $mail->addTo('somebody_else@example.com', 'Some Recipient');
  6. $mail->setSubject('TestSubject');
  7. $mail->send();

Simple.

For sending multiple mails it is better to use the SMTP protocol for performance reasons. Doing this manually with PHP is quite elaborate however, but with Zend_Mail it is almost as simple as before:

  1. require_once 'Zend/Mail.php';
  2.  
  3. // Create transport
  4. require_once 'Zend/Mail/Transport/Smtp.php';
  5. $transport = new Zend_Mail_Transport_Smtp('localhost');
  6.  
  7. // Sending out multiple mails at once
  8. for ($i = 0; $i > 5; $i++) {
  9. $mail = new Zend_Mail();
  10. $mail->addTo('studio@peptolab.com', 'Test');
  11. $mail->setFrom('studio@peptolab.com', 'Test');
  12. $mail->setSubject('Demonstration - Sending Multiple Mails per SMTP Connection');
  13. $mail->setBodyText('...Your message here...');
  14. $mail->send($transport); //Using the SMTP transport for sending the mail
  15. }

* SMTP connections can be secured with SSL or TLS for sending sensitive mails.

This procedure reuses the SMTP connection for the lifetime of the entire process which is much better than sending out mails using the mail() function.

Reading mail boxes

Reading mail boxes is similarly simple. Zend_Mail supports POP3 and IMAP for remote connections, and Mbox and Maildir for local connections (mail boxes residing on the same server). Sample usage:

  1. $mail = new Zend_Mail_Storage_Pop3( //Configuring with host and credentials
  2. array('host' => 'example.com',
  3. 'user' => 'test',
  4. 'password' => 'test'
  5. )
  6. );
  7.  
  8. echo $mail->countMessages() . " messages found\n"; //Outputting message count in mail box
  9. foreach ($mail as $message) { //Outputting message subjects
  10. echo "Mail from " . $message->from . ": " . $message->subject . "\n";
  11. }

Using the different storage options is very similar. Messages returned are instances of the Zend_Mail_Message class, which provides an API for manipulating mail messages.

Advanced Usage

Working with multipart MIME messages is very tedious. The MIME specifications are rather complex and MIME messages aren't very readable to humans, and therefor we would like to be able to use Zend_Mail_Message API to reduce the pains of dealing with MIME messages. There are several general cases when working with MIME messages:

  1. Working with messages which are stored as strings in a database
  2. Working with messages which are read from files
  3. Working with incoming messages directly (from an input stream)

Zend_Mail_Messsage can receive either a raw message string in its constructor, a file name or a file handle. Examples of instancing a Zend_Mail_Message object with all three:

  1. //From a raw string
  2. $message = new Zend_Mail_Message(array('raw' => $rawMessage));
  3.  
  4. //From a file name
  5. $message = new Zend_Mail_Message(array('file' => '/path/to/mail/message'));
  6.  
  7. //From a file handle
  8. $handle = fopen('/path/to/mail/message');
  9. $message = new Zend_Mail_Message(array('file' => $handle));

The last one might seem a bit redundant. However it opens up creative ways to intercept mail directly using the input wrapper:

  1. $handle = fopen("php://stdin", "r");
  2. $message = new Zend_Mail_Message(array('file' => $handle));

The tricky part is directing the mail message stream into the script. You can read more about that in this nice tutorial from evolt.

Some minor bugs and fixes

Nothing is perfect however. Current version of Zend_Mail (shipped with the Zend_Framework ver. 1.5.2) has a buggy implementation of the headers encoding. This will become noticeable when working with UTF encoded mails. Fortunately there is a quick fix for that posted in the ZF issue tracker (and hopefully will be tested and integrated in the next release).

Share this article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • DZone
  • del.icio.us
  • Technorati

8 Responses to Handling mail and mime in PHP using the Zend Framework

Avatar

Oren

July 18th, 2008 at 10:13 am

Hi,

Nice post.
Why is SMTP quicker? What happens in the non-smtp way? Executing the sendmail binary like the php simple mail() command?

Avatar

Eran Galperin

July 18th, 2008 at 2:13 pm

The problem with the mail() function is that it opens a separate socket connection for each mail. The PHP manual recommends using wrappers that send mail via SMTP – http://www.php.net/manual/en/function.mail.php (scroll down to the notes).

Avatar

Chris Abernethy

July 18th, 2008 at 3:39 pm

Nice introduction to Zend_Mail! I’m currently working on porting a rather large web application to use Zend Framework, and I will definitely be looking at replacing our use of the mail() function with Zend_Mail.

Avatar

Rauan Maemirov

July 20th, 2008 at 2:21 pm

Thanks for nice post. But that fixes in bug tracker didn’t help me and completely broke my encoding instead of fixing it. I’ll try to investigate it soon.

Avatar

Eran Galperin

July 20th, 2008 at 5:58 pm

Don’t forget to contribute your findings in the bug tracker ;)

Avatar

Maxence Delannoy

December 12th, 2008 at 9:18 am

You can use the constant STDIN instead of fopen(”php://stdin”, “r”);

Avatar

kuleshwar

February 10th, 2009 at 3:11 pm

hi,
i want to use zend mail but i don’t no how to start it & what will be its structure.

Avatar

Getting started sending emails with the Zend Framework - The Disgruntled Developer

April 24th, 2009 at 11:11 am

[...] just found this tutorial on Sending Emails with the Zend Framework. This tutorial couldn’t get any simpler, and explains the process of using Zend_Mail in plain [...]

Comment Form

About this blog

Eran Galperin is an Internet entrepreneur and head of development @ Lionite.

In this Blog he writes about Internet ventures and web development.

  • thomas: hi i have 3 tables like a ,b c where a contains employee detail , b contains details of item con [...]
  • Glaubensfragen « bohuco.net: [...] Blog-Eintrag “Common misconceptions in web application development” beleuchtet einige imme [...]
  • Eran Galperin: Plain SQL :) of course, I make sure to properly filter and escape user input [...]
  • Arik Fraimovich: @Eran & @George - thank you for the information. Going to rewrite some queries now :) @Eran - [...]
  • George: @Arik Fraimovich: REPLACE and ON DUPLICATE KEY UPDATE are actually quite different. REPLACE actually [...]