2012/05/17

PHP, mail, attachment

I've only had a handful of occasions where attaching files to an email was required, or even warranted.  Inevitably I would turn to Google, spend an hour or two wading through various dark arts involving base64, mime-types, mail headers and virgin sacrifices at the altar of SMTP.  Today ended up being no different.

It's been at least six months since i've had to attach a file to a mail message.  Yes, it can be done.  Yes, I have done it before.  No, I don't want to do it again.  And it turns out there is a good reason why.  Go to Google and search for the keywords "php mail attachment" and the following five sites pop-up:
  1. PHP mail attachment script - PHP function | PHP Forums
  2. PHP: mail - Manual
  3. PHP: Sending Email (Text/HTML/Attachments)
  4. How to send emails with attachments using PHP's "mail()" function ...
  5. send email with attachment | DaniWeb
Start with number one.  Copy the code, tweak very minorly to make work (sending to my own inbox, referencing a local file).  And...an email has shown up, no attachment.  Somehow the attachment file contents have been splattered all over the message body in all it's base64 glory.  Ugh.  The second link, the official man page out of the PHP Bible is of little help.  Links 3 and 4 have code snippets that differ little from the first and give the same results.  And #5 is a FORUM!?  Those worthless things are still aroung?  Scoll, search, find the code snippet, find, abandon.

None of this works.  No really, none of it.  Spin up a vm and throw a lamp server together, nothing.  Wamp chuckles and sputters.  Wisp throws up everywhere, but somehow I have thirty emails in my inbox and not a single file-attachment.  ARRGGH!

Heres the problem, it's 2012 now.  Look at those links (go ahead and click on them.  it won't hurt.  much.  except for #5).  Most of these articles were written in 4-5 years ago.  The web, PHP and development in general has moved so far past this stuff that it's unfair to expect archaic solutions like muddling with mime-types to work.  We need something better, something cleaner, something that gets the job done without wondering if my file has been ended with the proper delimiter.

Enter Zend_Mail.  Zend Framework is a tool that I honestly feel gets overlooked far more than it ought (read: I should use it more often but don't).  It's laziness, why go and get a hydraulic lift when I have a perfectly good scissor jack right here?  If i'm losing you, i'll excuse you to go back to carving wooden wheels, thank you for your time.

The rest of us need things to get easier.  mime-types are one example of a handful of technology that is SO last decade.  We need to move past it.  We need to expand our toolbox and get smarter.  faster.  evolved.  or something.

The unfortunately named Zend Framework is many things to many people.  Is it a framework?  Maybe.  Is it  MVC?  It can be.  Is it a library?  Sure.  When you get right down to it it's really just an assembly of classes and extensions that allow you to make what you will of it.  And it is as integral today as PEAR was 5 years ago.

So how can ZF help us today?  Consider the following code from Mr. Van Zyl that solved a problem a LONG TIME AGO.

<?php

  $to = "someone@somewhere.com";
  $subject = "A test email";

  $random_hash = md5(date('r', time()));

  $headers = "From: noreply@geekology.co.za\r\nReply-To: noreply@geekology.co.za";
  $headers .= "\r\nContent-Type: multipart/mixed; boundary=\"PHP-mixed-".$random_hash."\"";

  $attachment = chunk_split(base64_encode(file_get_contents("geekology.zip")));

  $output = "
  --PHP-mixed-$random_hash
  Content-Type: multipart/alternative; boundary='PHP-alt-$random_hash'
  --PHP-alt-$random_hash
  Content-Type: text/plain; charset='iso-8859-1'
  Content-Transfer-Encoding: 7bit

  Hello World!
  This is the simple text version of the email message.

  --PHP-alt-$random_hash
  Content-Type: text/html; charset='iso-8859-1'
  Content-Transfer-Encoding: 7bit

  <h2>Hello World!</h2>
  <p>This is the <b>HTML</b> version of the email message.</p>

  --PHP-alt-$random_hash--

  --PHP-mixed-$random_hash
  Content-Type: application/zip; name=geekology.zip
  Content-Transfer-Encoding: base64
  Content-Disposition: attachment

  $attachment
  --PHP-mixed-$random_hash--";

  echo @mail($to, $subject, $output, $headers);

?>
That's frightening. Seriously, yikes. Using a random hash as a delimiter. Sometimes with two-dashes on just one side, other times dashes on both. chunking and encoding and concatenating and ... I just wanted to attach a file to an email.

<?php

require_once( 'Zend/Mail.php' );

$filename = "geekology.zip";

$finfo = finfo_open( FILEINFO_MIME_TYPE );
$mimetype = finfo_file( $finfo, $filename );
finfo_close( $finfo );

$mailer = new Zend_Mail();
$atf = $mailer->createAttachment( file_get_contents( $filename ), $mimetype );
$atf->filename = $filename;

$mailer->setFrom( 'no-reply@geekology.co.za' );
$mailer->addTo( 'someone@somewhere.com' );
$mailer->setSubject( 'A test email' );

$mailer->setBodyText( 'Hello World! This is the simple text version of the email message.' ):
$mailer->send();
unset( $mailer );

?>
Look at that.  Object-oriented, dead-simple, and best of all IT WORKS!  first try, no fiddling, WORKS!  And there's not a single "multipart" to be found!

And it does so much more!  Check out the api and the manual for more details.

I'm not bagging on getting under the hood completely.  Once in a while you have to get into the nitty-gritty and check the Content-Disposition for yourself.  But we've got tools, and we need to be conscious of them. Hopefully the next time I need a refresher on attaching files to an email, i'll find Zend Mail at the top of the list.  But knowing that Zend Mail is there, "php, mail, attachment" is more than likely one query i'll never bother Google with again.

1 comment:

  1. Wow that was strange. I just wrote an extremely long comment but after I clicked submit my comment didn't show up. Grrrr... well I'm not writing all that over again.

    Anyhow, just wanted to say fantastic blog!

    Visit my blog post - cpa affiliate network :: :
    :

    ReplyDelete