Tuesday, November 17, 2009

Gotcha Of The Day: More PHP Malformed MIME Mail Issues

What is it with me and PHP MIME mail? The Mail_Mime package couldn't be easier to use, and has a straightforward tutorial that sums up everything you need to know.

Why then, today, when I wanted to attach a file to a mail message, were my messages consistently coming in malformed? Specifically, messages came in the following shape:

Date: Tue, 17 Nov 2009 14:26:12 -0500  « Headers start here
Message-Id: 
To: foo@bar.com
Subject: Foo needs some bar
MIME-Version: 1.0
From: bar@foo.com


--=_4817ceeae1593a82dcfe475697feb180 « Body starts here
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="ISO-8859-1"

In other words, the body MIME content delimiter was considered as though it was part of the body.

My code was essentially right from the tutorial:

  $mime = new Mail_mime("\r\n");

  $send_to = 'foo@bar.com';
  $from    = 'bar@foo.com;
  $subject = "Need more Foo!";
  $message = "Please <b>send foo's</b> immediately";

  $mime->setHTMLBody($message);
  $mime->setTXTBody(strip_tags($message));
  $mime->addAttachment(file_get_contents($path), 
                       'application/octet-stream',"My Data.xls", false);
                         

  $headers = array('From' => $from,
                   'Subject' => $subject);

  $headers = $mime->headers($headers);
  $body    = $mime->get();

  $mail =& Mail::factory('mail');

What I eventually determined was the headers generated by $mime->headers(...) was missing critical ones like Content-Type.

But why?!

And then I realized one key difference between my code and the docs. I made the following switch:

  $mime = new Mail_mime("\r\n");

  $send_to = 'foo@bar.com';
  $from    = 'bar@foo.com;
  $subject = "Need more Foo!";
  $message = "Please <b>send foo's</b> immediately";

  $mime->setHTMLBody($message);
  $mime->setTXTBody(strip_tags($message));
  $mime->addAttachment(file_get_contents($path), 
                       'application/octet-stream',"My Data.xls", false);
                         

  $headers = array('From' => $from,
                   'Subject' => $subject);

  $body    = $mime->get();             // <- Must be first!
  $headers = $mime->headers($headers); // <- Must be second

  $mail =& Mail::factory('mail');

Sure enough, the call to $mime->get() has side effects, which make $mime->headers(...); properly function.

Man, that strikes me as poor style. Chalk this up to another vote for side effect free programming, will you?

OK, I think I've now had every issue I can have with PHP and MIME e-mail. It's time for a new gotcha.

2 comments:

  1. Oh that is ugly hehe.

    ReplyDelete
  2. Big time.

    Slowly, but surely, PHP is evolving. The latest release has closures, which is slick.

    Still, I think it'll be some time before folks in the PHP camp realize how valuable functional programming can be. But my guess is, eventually they'll get there. Right around the same time they add in continuation based web facilities...

    ReplyDelete