Creating multipart email in PHP

Sending a simple and short email in PHP is an easy task. The following lines do just that ( http://php.net/manual/en/function.mail.php )

// The message
$message = "Line 1\r\nLine 2\r\nLine 3";

// In case any of our lines are larger than 70 characters, we should use wordwrap()
$message = wordwrap($message, 70, "\r\n");

// Send
mail('caffeinated@example.com', 'My Subject', $message);

However, sending a more involved email, including attachment and several MIME parts require some more code. Fortunately, this is not very complicated. But, as the email RFC relies on very specific text layout of the message body, you can very easily screw up your entire email. Sometimes nothing at all will be sent. This always results in very poor User experience, and in the case of an advertising email, this has to be avoided.

The following code will send a Multipart MIME email which includes one attachment. It contains one HTML section and one TXT section, so that the message will be correctly displayed whatever the remote part client settings are.

First some global variables definition. This is a mixture of french and english naming, but this should not be an obstacle 😉

global $destinataire;
global $email_expediteur; 
global $email_reply; 
global $sujet; 
global $name; 
global $locale;

Then we generate the crucially important frontier pattern. This is used to separate the various message parts … and should have a very low priority of being found in the message text or attachment.

 $frontiere = '-----=' . md5(uniqid(mt_rand()));

Note the bizarre formatting of this pattern. Strictly speaking, we just need to make sure this pattern cannot be found in the message body. So, hyphens and other signs are commonly used, combined with whatever you might think of (still part of ASCII character set). Here we use a combination of random number, MD5 hash and some uniqueness pattern.

Then we compose the email header:

 $headers = "From: ".$name.' <'.$email_expediteur.'>'."\n";
 $headers .= 'Return-Path: <'.$email_reply.'>'."\n";
 $headers .= 'MIME-Version: 1.0'."\n";
 $headers .= 'Content-Type: multipart/mixed;boundary="'.$frontiere.'"';

Again, the formatting is strict and upper/lowercase should be followed. White spaces and new lines as well. The message header ends by the “frontiere” pattern defined above.

Now we create the message body itself.

Regular text part
 $message = '--'.$frontiere."\n";
 $message .= 'Content-Type: text/plain; charset="iso-8859-1"'."\n";
 $message .= 'Content-Transfer-Encoding: 8bit'."\n\n";
 $message .= $message_texte."\n\n";

See the first line ? This is using our “frontiere” and adds two hyphens at the beginning, as stated in the RFC2046, paragraph 5.1.1 . We specify the Content Type, so text/plain for our regular text part, then the character set. This is important for using (and let the recipient display correctly) accented characters. A very nice a pragmatic article on character sets can be found here .

Now following the same principle, we can add the other message parts

HTML part
$message = '--'.$frontiere."\n"; 
$message .= 'Content-Type: text/html; charset="iso-8859-1"'."\n";
$message .= 'Content-Transfer-Encoding: 8bit'."\n\n";
$message .= $message_html."\n\n";

Basically, only the Content-Type has changed, to reflect the fact this is HTML.

Attachment part:

in this case, we add a previously generated pdf file which is converted to base64, and split in chunk of 76 bytes, as per RFC2045 par. 6.8 .

$attached_file = file_get_contents($file2send);
$attached_file = chunk_split(base64_encode($attached_file));
$picname = basename($file2send);
 
$attached = "\n\n". "--" .$frontiere . "\nContent-Type: application/pdf; name=\"$picname\"\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: attachment;"

$attached .= " filename=\". $picname\"\r\n\n";
$attached .= $attached_file . "--" . $frontiere . "--";

Then we compose the message and send it

// $destinataire (recipent) and $sujet (subject) were defined before
 $message .= $attached;
 
 if(mail($destinataire,$sujet,$message,$headers)) {
      return true;
 else
      return false;

As the email message formatting is very strict, all this code should be bundled together into a function and utilized wherever needed.

For further and detailed reference, one can also look at the RFC2046 which details all the various fields and elements found in a Multipart Email, but the reading is less pleasant 😉

Leave a Reply

Your email address will not be published.