PHP Classes
elePHPant
Icontem

Fast PHP Mass Mailer Smart Optimizations - MIME E-mail message sending package blog

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  All package blogs All package blogs   MIME E-mail message sending MIME E-mail message sending   Blog MIME E-mail message sending package blog   RSS 1.0 feed RSS 2.0 feed   Blog Fast PHP Mass Mailer ...  
  Post a comment Post a comment   See comments See comments (18)   Trackbacks (0)  

Author: Manuel Lemos

Posted on:

Package: MIME E-mail message sending

Sending email messages to many recipients is an heavy duty task. But using smart optimizations it is possible to send messages to millions of users in a reasonable amount of time from your own PHP server without consuming too much resources.

Read this article to learn how the MIME E-mail message sending class takes advantages to efficiently send personalized messages to many recipients.




Contents

PHP and the Myth of the Slow Interpreted Language

Composing and Sending Email Messages to Many Recipients

Optimizing Newsletters with the Same Body for All Recipients

Sending Personalized Messages to Many Recipients

Optimizations for the Latest PHP Versions

Optimizing the Mail Server Communication Process

Cloud Mailing Service APIs

Conclusion


PHP and the Myth of the Slow Interpreted Language

The fact that most PHP applications run directly from PHP source code makes many developers believe that PHP is necessarily slow because it needs to interpret the source code to be executed.

Since PHP 4.0 when Zend Engine 1 was introduced, PHP source code is not interpreted during execution. Instead PHP is compiled into byte code before executing just like other languages, such as Java and C#. Only after the compilation process PHP is executed by the Zend Engine. This fact makes PHP code execute much faster than many developers imagine.

However, there is a factor that makes PHP even run much faster for heavy duty tasks. That factor is that PHP provides many functions that can process large amounts of data and the speed of lower level languages such as C and C++.

As a matter of fact those functions are written in C, rather than PHP code that is compiled into byte code. PHP acts only as glue language that passes data to those C functions.

This factor makes PHP suitable for performing many types of heavy duty tasks like for instance sending email messages to many recipients.

As a matter of fact PHP comes built-in with many functions specifically to encode data to compose email standards compliant messages very efficiently.

This MIME message class uses as much as possible many of those functions to compose and send email with great efficiency.

Composing and Sending Email Messages to Many Recipients

Very often PHP applications need to send messages to many users. That is the case of sites that need to send newsletters or other types of mass mailings.

One optimization that this class provides for mass mailing is the SetBulkMail function. It hints the class to prepare itself to send many messages, one after another.

What this function does in practice depends on the actual way the message is sent. The base class email_message_class uses the PHP mail() function to deliver the message. In this case the SetBulkMail does not do anything.

However for specific sub-classes like the smtp_message_class that uses a SMTP server, it prevents the class to close the connection with the server between sending messages to two recipients. This avoids the overhead of closing and reopening the SMTP server connection.

In the case of the sendmail_message_class it sets the delivery_mode variable to a value that tells the sendmail email server to store the message in a local queue instead of waiting to deliver the message to the destination SMTP server.

In the case of the qmail_message_class the SetBulkMail function does not make a difference because qmail always stores messages in the local queue instead of attempting to send it to the destination SMTP server immediately.

Here is sample code to initialize the sendmail_message_class in preparation for mass mailing. This class is suitable for use when you are running PHP on a server that has Sendmail or another compatible mail server like Postfix, Qmail, Exim, etc..


$message=new sendmail_message_class; $message->SetBulkMail(true);

Optimizing Newsletters with the Same Body for All Recipients

The simplest case of mass mailing is of newsletters that have the same body content for all recipients. This means that the message body is the same, only the message headers may vary from recipient to recipient.

The MIME message class has a variable named cache_body that when set to true it tells the class to cache the assembled body of the message when it sends it to the first recipient, so it avoids the overhead of reassembling the message for subsequent recipients.

Here is a sample message delivery loop for sending messages with the same body to many recipients:


$message->SetEncodedHeader('Subject', 'Some subject'); /* * Define the recipients list */ $to=array( array( "address"=>"peter@gabriel.org", "name"=>"Peter Gabriel" ), array( "address"=>"paul@simon.net", "name"=>"Paul Simon" ), array( "address"=>"mary@chain.com", "name"=>"Mary Chain" ) ); /* * Create a place holder text message body part */ $text = 'Hello, some text message'; $message-> CreateQuotedPrintableTextPart( $text, '', $text_part ); /* * Create a place holder HTML message body part */ $html = 'Hello, some HTML message'; $message-> CreateQuotedPrintableHtmlPart( $html, '', $html_part ); /* * Assemble the text and HTML parts as alternatives */ $alternative_parts = array($text_part, $html_part); $message->AddAlternativeMultipart( $alternative_parts); /* * Cache the message for all recipients */ $message->cache_body = true; /* * Iterate for each recipient. */ foreach($to as $recipient) { /* Personalize the recipient address. */ $message->SetEncodedEmailHeader('To', $recipient['address'], $recipient['name']); /* Send the message checking for eventually acumulated errors */ $error=$message->Send(); if(strlen($error)) break; }

Sending Personalized Messages to Many Recipients

Sending messages with personalized message bodies is a bit more complex because you need to set a different body data for each recipient.


/* * Create a place holder text message body part */ $text_template = 'Hello {name}, some text message'; $message-> CreateQuotedPrintableTextPart( $text_template, '', $text_part); /* * Create a place holder HTML message body part */ $html_template = '<html><body>Hello {name}, some HTML message</body></html>'; $message-> CreateQuotedPrintableHtmlPart( $html_template, '', $html_part); /* * Assemble the text and HTML parts as alternatives */ $alternative_parts = array($text_part, $html); $message->AddAlternativeMultipart( $alternative_parts); /* * Iterate for each recipient. */ foreach($to as $recipient) { /* Personalize the recipient address. */ $message->SetEncodedEmailHeader('To', $recipient['address'], $recipient['name']); /* Create personalized body parts */ $text = str_replace('{name}', $recipient['name'], $text_template); $message-> CreateQuotedPrintableTextPart( $message->WrapText($text), '', $text_part); $html = str_replace('{name}', HtmlSpecialChars($recipient['name']), $html_template); $message-> CreateQuotedPrintableHtmlPart($html, '', $html_part); /* Make the personalized parts replace the initially empty part */ $message->ReplacePart($alternative_parts[0], $text_part); $message->ReplacePart($alternative_parts[1], $html_part); /* Send the message checking for eventually acumulated errors */ $error=$message->Send(); if(strlen($error)) break; }

Optimizations for the Latest PHP Versions

When you want to reduce the time and CPU usage of queueing messages for a mass mailing campaign, it is necessary to optimize the code that is inside the recipient iteration loop.

In this case what takes most CPU is the encoding of the messages to form the MIME message envelopes that are sent to the mail server.

For regular HTML messages with alternative body parts as defined in the examples above, what takes most CPU is the encoding message bodies using the quoted-printable algorithm. This encoding is necessary to encode message, so they  do not contain special characters that are illegal, as they could confuse mail server gateways.

Older PHP versions did not provide a core function to encode message bodies using quoted-printable. You could use the imap_8bit function for this purpose, but this required that the PHP IMAP extension be enabled.

Therefore the email_message_class provides a pure PHP implementation of the quoted-printable encoding algorithm. This is not a very fast solution, especially when you need to send personalized messages to many recipients.

Since PHP 5.3 there is a function named quoted_printable_encode for this purpose. The email_message_class uses this function in PHP versions that support it, thus making it much faster for mass mailing.

Optimizing the Mail Server Communication Process

The other part of the delivery loop that takes more time is the communication with the mail server. In this case there is not much more to do besides what the classes already do.

Anyway, if possible use the specialized delivery sub-class that uses sendmail or equivalent, like Postfix, Qmail, Exim. This is most times faster than trying to queue the messages in the mail server via SMTP protocol.

That is because the SMTP servers often use a program equivalent to sendmail to store the messages in their queues, so you woudl be adding the TCP/IP communication protocol overhead to server communication process.

I noticed that some developers believe SMTP queueing is faster than sending messages via sendmail. That may be the case when sendmail is configured to attempt to immediately send the message to the destination SMTP server.

As mentioned above, when you use the SetBulkMail function, the sendmail_message_class will pass parameters to sendmail, so it just stores the message in the mail server queue, rather than trying to immediately send the message to the destination SMTP server.

Another aspect is sending messages to remote SMTP servers of third-party mail server providers. This makes deliveries even slower because of the overhead of communicating with remote SMTP servers that are in different data centers.

Cloud Mailing Service APIs

Not covered by this article are the solutions based on APIs of cloud mailing services. These mailing services are usually only recommended for sending bulk mail for a small number of recipients.

The cost of sending messages to many recipients is often very high. Depending on the purposes of your mass mailing application, it may not be worth hiring those services.

That is the case of PHP Classes which sends between 3 to 5 million newsletters and alert messages a month to the site subscribers.

That is why the MIME message sending package does not provide any direct support to those mailing service APIs. I may add support to some of those APIs though if there is enough demand from the users. Just let me know if you have interest, so I can evaluate the implementation of sub-classes that support those APIs.

Conclusion

As you may have read, it is possible to implement heavy duty task like mass mailing in PHP with great efficiency.

The MIME message class has been under active development since 1999, so nowadays it is very mature. It implements many smart optimizations that provide significant performance improvements to mass mailing applications.

This article provides guidance on how to take advantage of those optimizations to achieve top mass mailing performance. Please post your comments and questions to this article if you need further clarification on how to take the most out of this package.


You need to be a registered user or login to post a comment

Login Immediately with your account on:

FacebookGmail
HotmailStackOverflow
GitHubYahoo


Comments:

4. it was not possible to open sendmail input pipe - Siddiq Ansari (2014-09-26 22:37)
mail not sent, error is generated... - 8 replies
Read the whole comment and replies

3. Well done - dan (2013-10-28 01:26)
It is a great how you explained it all... - 5 replies
Read the whole comment and replies

3. There seems to be an error? - dan (2013-10-24 19:16)
it was added a part without Content-Type: defined... - 5 replies
Read the whole comment and replies

2. Thanks - Sanjay Maurya (2013-09-20 01:46)
Not tried yet but looks cool.... - 1 reply
Read the whole comment and replies

1. Great post - Antonino (2013-09-19 19:42)
Interesting... - 0 replies
Read the whole comment and replies




  Post a comment Post a comment   See comments See comments (18)   Trackbacks (0)  
  All package blogs All package blogs   MIME E-mail message sending MIME E-mail message sending   Blog MIME E-mail message sending package blog   RSS 1.0 feed RSS 2.0 feed   Blog Fast PHP Mass Mailer ...