Article
Advanced email in PHP
Mixed Messages
In life, it's rarely good to send mixed messages. At least, that's what my last girlfriend told me! When it comes to email, however, mixed messages offer a whole lot of power. A single email message can contain both text and HTML versions of your message. That makes it viewable in most any email program, and you don't sacrifice the power of HTML formatting for readers that are appropriately equipped.
Be aware that mixed messages have their weaknesses. First of all, since you're sending two versions of your message, the message will typically be a lot larger than it would be if you sent just one format or the other. Also note that old email programs that don't recognize the mixed message format may display both versions of the message as file attachments (one text, the other HTML).
Let's look at a simple example of a mixed email message, and then look at the PHP code to send it:
Date: Mon, 11 Feb 2002 16:08:19 -0500
To: The Receiver <recipient@some.net>
From: The Sender <sender@some.net>
Subject: A simple mixed message
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="==Multipart_Boundary_xc75j85x"
This is a multi-part message in MIME format.
--==Multipart_Boundary_xc75j85x
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
This is the text portion of the mixed message.
--==Multipart_Boundary_xc75j85x
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
<html>
<body>
<p>This is the <b>HTML portion</b> of the mixed message.</p>
</body>
</html>
--==Multipart_Boundary_xc75j85x--
After the initial, standard headers at the top of the message, we have the MIME-Version: 1.0 header that enables the advanced email features we need. The Content-Type: header is where things start to get funky:
Content-Type: multipart/alternative;
boundary="==Multipart_Boundary_xxc75885"
We specify a content type of multipart/alternative, which is the special type that allows us to send a message with two or more alternative versions of the message (from which the recipient's email program will pick the most suitable for display). In addition, we use the Content-Type header to set a boundary string.
To keep the header lines short, this part of the header appears on a second line (as mentioned in a note above, the second line must begin with one or more spaces to indicate that it's a continuation of the previous line).
In this case, I chose "==Multipart_Boundary_xc75j85x" as the boundary string. There is no special significance to this string, other than it is unlikely to appear as part of the message itself. I used characters like equals signs and underscores, and semi-random strings of letters and numbers to help ensure this. We then use this string to divide up our message into parts.
The text "This is a multi-part message in MIME format." is included for the benefit of older mail programs, so that the user has some idea of why the email may not appear quite as expected. With that disclaimer out of the way, we use our boundary to mark the start of the first part of our message:
--==Multipart_Boundary_xc75j85x
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
This is the text portion of the mixed message.
Notice that we add two dashes (--) to the beginning of the boundary string when we actually use it.
After the first boundary, we begin the text version of the message. Each part of the message begins with a couple of headers to indicate its content type and encoding. In the case of the text part, the content type is text/plain (with the standard character set, iso-8859-1), and the encoding is 7bit (plain ASCII text). A blank line marks the end of the headers, which are followed by the message body.
The HTML version then follows:
--==Multipart_Boundary_xc75j85x
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
<html>
<body>
<p>This is the <b>HTML portion</b> of the mixed message.</p>
</body>
</html>
The headers are almost identical to the text part, but this time we specify text/html as the content type. After the body of the HTML document, all that remains is the closing boundary, to which we add an extra two dashes on the end to mark the end of the message:
--==Multipart_Boundary_xc75j85x--
As you can see, mixed messages may look complicated, but they're actually pretty simple when you take a closer look. The only tricky part from the standpoint of a PHP developer who wants to send a message like this is the task of generating a boundary string.
Here's how I like to do it:
<?php
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
?>
We take the current Unix timestamp (the number of seconds since January 1, 1970), as given by time(), and use the MD5 algorithm to convert it to a semi-random string. This string is then used to make up part of the boundary string. Feel free to use whatever method you like to generate your boundary strings.
With all this in mind, you should be well-equipped to generate mixed messages in PHP. Since mixed messages are relatively uncommon, I'll leave the actual code for you to write as an exercise. This business of splitting up messages into parts with a boundary string is important, however, when it comes to file attachments -- the subject of our final section.