The Zend Framework provides an extremely handy component for sending out Emails from your web applications – Zend_Mail
You no longer have to struggle with the nitty-gritty of smtp headers. Sending HTML mail using this component is pretty straight-forward:
$mail = new Zend_Mail();
$mail->setBodyHtml($msg);
$mail->setFrom($from_email);
$mail->setSubject($subject);
$mail->addTo($toAddress);
$mail->send();
The code shown above is the “minimal” configuration, and gets the job done in most cases. However, with spam control being widely adopted, it is imperative that you follow certain guidelines so that your mail does not get blocked or sent to the spam or junk folder (in Outlook).
It took me a day of tweaking to figure out the issues with my code above that were causing MS Outlook to redirect mails, that were generated by the code above, to the “Junk” folder.
The first step is to fixing this is to understand the “internet headers” that get generated when email is sent. In Outlook 2007, You can view this information by right-clicking on the message and selecting “Message Options”. The internet headers are displayed at the bottom in a read-only text area.
Our work email server uses a Barracuda spam filter(additionally). Barracuda uses a set of rules to deduce whether an email is “spam-like”. Outlook uses a similar engine to compute the spam probability of EVERY mail that it receives. The higher the score (sum of points), the more likely it is that the email is spam.
The barracuda spam report gets conveniently included in the internet headers for us, and is a good starting point to figure out the problem areas. Here is what my header looks like:
X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.2.15034
Rule breakdown below
pts rule name description
—- ———————- ————————————————–
0.00 NO_REAL_NAME From: does not include a real name
0.00 HTML_MESSAGE BODY: HTML included in message
0.00 MIME_HTML_ONLY BODY: Message only has text/html MIME parts
0.01 BSF_SC0_SA_TO_FROM_DOMAIN_MATCH Sender Domain Matches Recipient
DomainX-MS-Exchange-Organization-SCL: 5
X-MS-Exchange-Organization-PCL: 2
Note that the X-MS-Exchange-Organization-SCL score is ‘5’. This is the Exchange “Spam Confidence Level” on a range of 0-9. A number >=5 automatically classifies the email as Junk.
Notice that the “points” assigned for the first 3 items are “0”. So, from the Barracuda point of view, it is informational only. However, Outlook assigns different points to these items (and, we have no way of viewing the score assigned by Outlook). So, we need to take a look at ALL the barracuda messages one by one.
1. NO_REAL_NAME : Easy fix.. use the overloaded forms of setFrom, addTo, addCC, addBcc that allow including the real name.
2 & 3. HTML_MESSAGE and MIME_HTML_ONLY:
These messages are linked. Most modern email clients allow users the option of viewing “text-only” versions. So, whenever you send out HTML mail, you SHOULD ALSO ALWAYS use the setBodyText() method to send the alternative plain text mail.
4. BSF_SC0_SA_TO_FROM_DOMAIN_MATCH : This means that the domain from where we are sending emails matches the destination. Yes.. we are trying to send emails internally within the organization… so, we just have to take this as an informational message and move along.
After making the above changes, our code looks like:
$mail = new Zend_Mail();
$mail->setBodyText(strip_tags($msg));
$mail->setBodyHtml($msg);
$mail->setFrom($from_email,”my name”);
$mail->setSubject($subject);
$mail->addTo($toAddress,$toName);
$mail->send();
I have used the strip_tags PHP function to generate a text only version of the HTML message.
A couple of important pointers here:
- The html and text version should differ .. Otherwise, it will trigger another rule (Note the MPART_ALT_DIFF message) :
X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.2.15146
Rule breakdown below
pts rule name description
—- ———————- ————————————————–
0.00 HTML_MESSAGE BODY: HTML included in message
0.14 MPART_ALT_DIFF BODY: HTML and text parts are different
0.01 BSF_SC0_SA_TO_FROM_DOMAIN_MATCH Sender Domain Matches Recipient
Domain - Do ensure that the HTML message that you send into in the setBodyHtml is WELL FORMED. Errors in your html will cause the message to be classified as spam.
- The “from address” MUST be a valid/existing email address.. Using fictitious email addresses is a sure way to increase the spam score.
After the modifications, mail was being routed correctly. Here’s a peek at the internet header of the delievered mail:
X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.2.15375
Rule breakdown below
pts rule name description
—- ———————- ————————————————–
0.00 HTML_MESSAGE BODY: HTML included in message
0.01 BSF_SC0_SA_TO_FROM_DOMAIN_MATCH Sender Domain Matches Recipient
Domain
X-MS-Exchange-Organization-SCL: 4
X-MS-Exchange-Organization-PCL: 2
Ok.. so now, notice that the MS-Exchange-Organization-SCL score is at 4.
UPDATE (Nov 24, 2009): The above process worked yesterday.. but today, the score is back to 5. The kicker is that it is not consistent! Some emails get redirected to the junk and some are delivered ok.
So, finally, I decided to avoid HTML email altogether. I changed my emails to include only text along with a URL to view detail in all HTML glory. Outlook has made it too cumbersome to dependably send HTML formatted email.