Monday, February 08, 2010

Red Condor / Visi Bouncing Emails with Error Message "554 Failed: Malformed MIME header (in reply to end of DATA command))"

For the last two weeks I've on-and-off been puzzling over this issue: every email sent to users at visi.com from a PHP script I wrote bounces back with this error message: "554 Failed: Malformed MIME header (in reply to end of DATA command))".

Today I finally found the solution.

In my early searches, Google had nothing useful to say, so I'm writing this post in the hopes of helping some future PHP programmer who's banging his or her head against a wall in angst.

Here's the setup: for our online back-to-school / class registration system at Minnehaha (that I wrote), there's a PHP script that allows users to reset their forgotten passwords. Part of this process involves sending them an email with a unique identifier. The problem is that email wasn't always being delivered: users with visi.com email addresses did not receive their message. After examining the web server's logs, I discovered the error message above, something about a malformed MIME header.

I emailed Red Condor, Visi's filtering service (their name showed up in the log next to the bounce notice), and they wrote back in about 10 minutes. Literally. I was floored at how quickly their tech support responded.

Our first place of investigation was my custom headers. I need these so that the message is sent as HTML instead of plan text, but since it's human-made, it's the most logical place for a mistake. The PHP code looks something like this:

$headers = 'MIME-Version: 1.0'."\n".
'Content-Type:text/html;charset=iso-8859-1'."\n".
'From: Name <name@domain.com>'."\n";


One possible culprit was the line endings. The mail message spec dictates that all lines in the header need to end with \r\n (carriage return and a new line. For those too young to know what a carriage return is, Google for "typewriter"; it's an old-school laptop our parents and grandparents grew up using). If you'll notice, in my code above, I only have \n, not \r\n. IMPORTANT NOTE: If you're running PHP on a UNIX or Mac OS X server, the mail() command will add \r for you! So if you manually put in \r\n, you'll end up getting \r\r\n, which is bad.

So as far as I could tell, my headers were all correct.

Next, I manually grabbed my entire inbox from the mail server and examined it in a hex editor (Mac OS X users I recommend a free program called Hex Fiend). All my line endings were as they should be (Hex values 0D 0A).

I emailed back and forth a few times with Red Condor, and my tech support person suggested I capture the email coming from the server before it gets to the mail server, and then send them those bytes. I spent a day trying to figure out how to get PHP to dump an email into a file before giving up. I thought I'd never find the solution, until...

RC tech support suggested I try a packet capture.

Well that sounds fun. I know the concept, and I found a free program (CocoaPacketAnalyzer) to let me do it easily, but could I really find what I was looking for?

Yes, turns out.

I started a capture on the webserver, told the script to send an email to one of my Visi users, and then examined the packets that were sent. After a little searching I found the packet with the actual mail message, and here's the gold: all the bytes were correct except for the X-PHP-Originating-Script header, which had the dreaded \r\r\n trailing it.

How the heck do you get rid of that? It's not an error in my custom code, it's an error in PHP's mail() code!

Our network consultant Dan suggested I disable that header to see if that would solve Red Condor's rejection issue.

Google was helpful on this front: you can disable the X-PHP-Originating-Script header by setting mail.add_x_header = OFF in your php.ini file (and then restarting web services, obviously).

Turns out, disabling that header ALSO removed the extra \r. In my next packet capture, the extra byte was GONE and the email sent successfully, no more bouncing.

It's always something so small, so innocent. I don't know if Red Condor was rejecting the X-PHP-Originating-Script header or was just unhappy about the extra carriage return byte, but either way, I'm happy it's solved!

6 comments:

Anonymous said...

Thank you for posting this! You may have helped me resolve a tough issue!

Chris said...

Thank you. I recently had a server start bouncing notification emails because of this. It's a known bug in php 5.3.0:

http://old.nabble.com/PHP-5.3-add_x_header-Broken-td23661365.html

WillyW said...

Unfortunately, I only found your post AFTER resolving the same issue.
But we didn't have any error messages, it just turns out that Outlook (or Outlook Express) will not render an HTML-mail with this extra \r in it properly: it decodes the html to text and displays the source...

Judson Mitchell said...

Thanks for this! Helped me to solve a vexing problem.

Anonymous said...

I appreciate the help too. I don't have a MAC, and the packet capture tool didn't look like it would work for me... Wireshark is a good free packet capture tool for Windows

Robbie said...

Thank you! I've been having this issue with RedCondor for quite some time now. Your code worked like a charm.