Multipart MIME email example in PHP

November 23, 2007

Let’s see how we can use some simple tools and create a functional example of how multipart MIME actually works in practice. With both of my hands in the carburetor (a car repair term for getting down to business and having things done fast) I sit down and get busy with creating the necessary form and php script. Before I get into more details I want to make clear that you will need PHP set up correctly. For the purposes of creating something interactive we’ll use our code in the context of an Apache 2 web server which will make testing and using the application easier.

Prerequisites:

To get everything started we’ll prepare a web form in pure XHTML which submits the content entered by the user via POST submit to our script which will assemble the message and send it. Our script will utilize the PHP mail function so you will have that functionality enabled on your server in order to send email messages. In PHP this configuration is done in php.ini in a section called [mail function]. I am not going to get into great details but in short there will be three settings : SMTP, sendmail_from, and sendmail_path that you will have to configure. If you are configuring a Windows machine you would want to set the SMTP section to your outgoing SMTP server whereas UNIX and Linux users will have to set sendmail_path to make use of the sendmail program unless you don’t have sendmail installed or will prefer use SMTP anyway. In either case sendmail_from will refer to the email address that will appear as the default in the from section.

Getting Started:

In order to make it easier for the user to create messages from scratch we’ll provide an XHTML form with the following fields: email (that will be the sender’s email), subject, text content, and html content. Alternatively you can provide a field for the recipient(s) email but for spam purposes our public form will not utilize that. You can easily refactor it and provide that functionality by adding a single field.

<input name="email" size="20" type="text" />
<input name="subject" size="20" type="text" />
<textarea cols="40" rows="10" name="messageplain"></textarea>
<textarea cols=40 rows=10 name="messagehtml"></textarea>

Here is the full XHTML page with the form. Please ignore the plain styling – you can easily override the CSS and create some fancy styling. I will strongly suggest if doing that to get everything working first.
As you can see our form element uses the POST method and submits to the next part of our discussion: the mail.php document containing our message assembly and submission code
<form action="mail.php" method="POST">

Now let’s look closer at what happens behind the scenes and how our message gets processed. To be able to successfully accomplish our goal we need to examine the anatomy of an email message. An email consists of three components:

  • the envelope – includes routing information for your message and is used by the MTA to transfer your email over the network. Typically you don’t need to be concerned with the envelope as it is not visible by the user.
  • the headers – the headers are the most intererting part of an email containing processing information. Some are mandatory: Date From, To, (or BCC) while others are optional: Subject, Cc, Reply-To, Received, Message-Id.
  • the message body – this is the section with the actual content of your email message. The body is separated from the headers by a single blank line.

First we need to create our mail headers correctly. Let’s look at an example of what our headers need to look like:

From: <admin@nedkoko.com>
To: <recipient@domain.com>
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary=”fU3W4Vzr4G3D54f3″

Keep in mind that this is a simplified version of the headers but it works great for the purposes of our demonstration. Note that for content type “multipart/mixed” is used to send messages with different Content-Type sections (usually attachments) but for our purposes we want to use “multipart/alternative” which signifies different (“alternative”) versions of the same content.
Ok, now that we know what our headers need to look like we can start our form processing by extracting the content from our submission:

$email = $_POST['email'];
$to = 'nedko1@yahoo.com';
$subject = $_POST['subject'];
$messageplain = $_POST['messageplain'];
$messagehtml = $_POST['messagehtml'];

Now that we have our form content we need to create our boundary for separating the different parts of the message. A good way to do that is to use some kind of hashing which will guarantee uniqueness and will be different for each message. For that purpose i decided to use and MD5 hash algorithm applied on the current timestamp. That will satisfy our requirements and provide a 128bit value we can use for separation.
$mime_boundary = "----=_NextPart_X[".md5(time())."]";.
Let’s proceed next with creating a nice little header based on what we have so far:

$headers = "From: <admin@nedkoko.com>\r\n".
"To: <".$to."> \r\n".
"MIME-Version: 1.0\r\n" .
"Content-Type: multipart/alternative; ".
"boundary=\"".$mime_boundary."\"\r\n";

As you notice the “boundary” is not a separate header as it’s not separated on a new line as the specs require. That is because it is considered as a part of the “Content-Type”. It’s time to pay more attention to our actual message which will follow our headers separated by a blank line. Since we have multiple sections of our message body we will start each section with “–” followed by the boundary, followed by the content type and encoding. As we have two sections: text and HTML versions we start with the text:

“–”.$mime_boundary.”\r\n”.
“Content-Type: text/plain; charset=\”utf-8\”\r\n”.
“Content-Transfer-Encoding: quoted-printable\r\n\r\n”.
$messageplain.”\r\n\r\n”.

Then we do the same with the HTML version. Again we provide “–” with the boundary, content type and then the encoding:

"--".$mime_boundary."\r\n".
"Content-Type: text/html; charset=\"utf-8\"\r\n".
"Content-Transfer-Encoding: 8bit\r\n\r\n".
$messagehtml."\r\n\r\n".

Looks like we are finished with both versions of the message so now we have to wrap it up and specify that this is the end of our body content:

"--".$mime_boundary."--\r\n";

Note that the end is demarcated by “–” both in front and after the boundary, making if different from separator between different parts of the body. Finally, we can apply some basic form validation (optional but recommended) and call the mail function to process our mail request. It is important to mention that the mail function can be invoked with @ in order to suppress any errors it generates. Even better it returns a boolean value specifying if the message was successfully sent so we can then include some extra logic to provide feedback to the user.

if (mail($to,$subject,$message, $headers))
{
echo "<h4>Your message was sent successfully. </h4>";
}

Mission accomplished! Here you can download a zip of the full mail.php as well as see the full working version in action here. Hope this quick introduction has shed more light into email message formats and specifics of MIME.

  • Share/Bookmark

3 Responses to “Multipart MIME email example in PHP”

  1. This didn’t work for me. The email message I received just had all the content type stuff, the text version, and the html version – with all the html code included. What did I do wrong?

  2. Hi DeAnne,
    The code included here works flawlessly for hundreds of users every day – the emails I receive are proof of it. If you send me your code I will be glad to have a look and help resolve the problems you are experiencing.

    Nedko

  3. Hi Nedko,
    I tested this code.But in roundcube webmail client it is showing the html tags in the email.But in gmail,yahoo,rediff it is working fine but not in in.com,aol.com emails.

Leave a Reply

You must be logged in to post a comment.