Sending mixed-type messages with PEAR::Mail_Mime

Emails that were sent using PEAR::Mail should be no different from our previous scripts, as we are not doing anything special just yet. However, PEAR::Mail was just there to lay the groundwork for our use of attachments. You see, there is a very close cousin of PEAR::Mail called PEAR::Mail_Mime, and this has a number of features to make sending attachments with PEAR::Mail emails very easy.

The first type of attachment we are going to send does not even look like an attachment on the source. Previously we looked at sending HTML mail by adding "Content-type: text/html" to the headers. The problem with this is that people without a HTML mail reader cannot read the message because they will receive a huge chunk of HTML and will have to dig through it by hand to find the message.

The solution here is to send the message in both plain text and HTML-encoded format, by attaching the HTML message separately. When the email is received by mail readers, they will automatically choose the correct one to display.

Author's Note: Mailing lists, particularly those attached to the open source community, take a very strong stance against HTML emails. The reason for this is that your message gets sent twice inside the one email - once in plain text and once in HTML. While this is fine for sending personal mails and mails to a controlled list who are willing to receive this, it does waste space in people's email inboxes.

We can do this very simply using PEAR::Mail and PEAR::Mail_Mime, particularly as the latter has a very simple way of attaching both a plain text mail and a HTML mail. Here is how it looks:

<?php
    include('Mail.php');
    include('Mail\mime.php');

    $message = new Mail_mime();
    $text = file_get_contents("mail_text.txt");
    $html = file_get_contents("mail_html.html");

    $message->setTXTBody($text);
    $message->setHTMLBody($html);
    $body = $message->get();
    $extraheaders = array("From"=>"me@example.com", "Subject"=>"My Subject 7");
    $headers = $message->headers($extraheaders);

    $mail = Mail::factory("mail");
    $mail->send("best@friend.com", $headers, $body);
?>

Some parts of that will look familiar, but the majority is new. This time we have to include both PEAR::Mail and PEAR::Mail_Mime, as it takes both classes to get the full email sent.

This time, rather than handling our message as a text string, the message is an instance of Mail_mime. In the example, the message is stored in the $message variable. Next, both the plain text and HTML messages are retrieved from disk using file_get_contents() and stored in $text and $html respectively.

Once we have the content loaded, we can put it into the message using the setTxtBody() and setHTMLBody() methods of our $message variable. These both take a string as their only parameter, so just pass in the appropriate return value from file_get_contents().

The body for the message, still stored in $body, now comes from the return value of $message->get(). This retrieves the full message text to send, and is a combination of the HTML and text information all encoded for sending over the Internet. If you want to see how the system works behind the scenes, echo out $body and have a look through.

With the line starting, "$extraheaders = ", things start getting a little more complicated. Last time you saw that PEAR::Mail->send() takes its headers as an array, and, to accommodate this, PEAR::Mail_Mime also returns its headers as an array. You see, when sending complex emails, you need to have a special set of headers in there that tells the mail reader what to expect. So, once you have your content in place, you just call headers() to get the header information. As you still need to use the old headers (from, subject, etc), you can pass into headers() an array of existing headers, and it will add these to the array it returns.

For example, calling headers() on its own might return something like this:

array(2) {
    ["MIME-Version"]=>
    string(3) "1.0"
    ["Content-Type"]=>
    string(64) "multipart/mixed;
    boundary="=_067d506611ba7a0da2b6106b54282d16""
}

However, passing our array $extraheaders in as the only parameter, headers() returns this:

array(4) {
    ["MIME-Version"]=>
    string(3) "1.0"
    ["From"]=>
    string(14) "me@example.com"
    ["Subject"]=>
    string(12) "My Subject 7"
    ["Content-Type"]=>
    string(64) "multipart/mixed;
    boundary="=_307c199ae5303dac356d5cf48c89fc7c""
}

Note that the "boundary" string in Content-Type is randomised, so yours will be different.

Once we have the complete list of headers, this is passed into the send() call at the end, which is otherwise unchanged. Now when the mail is received, mail readers should automatically pick the best format for them and display it.

 

Want to learn PHP 7?

Hacking with PHP has been fully updated for PHP 7, and is now available as a downloadable PDF. Get over 1200 pages of hands-on PHP learning today!

If this was helpful, please take a moment to tell others about Hacking with PHP by tweeting about it!

Next chapter: Sending attachments (at last!) >>

Previous chapter: Easier mail sending with PEAR::Mail

Jump to:

 

Home: Table of Contents

Copyright ©2015 Paul Hudson. Follow me: @twostraws.