HTML E-Mail with PHP: 5 Pointers to Get ‘er DONE!

Sending e-mail can be pretty useful with PHP. It’s also really easy… until you want to send HTML that is.

I used these two tutorials to learn how to send HTML e-mails in PHP:

sitepoint.com advanced e-mail tutorial
webcheatsheets.com sending e-mail tutorial

For something that requires very strict accurate guidelines to be followed, you would think they wouldn’t just gloss over them or ignore them entirely. But they did.

So, here are five pointers to get you off on the right foot:

1. Use Content-Type: multipart/alternative; with a random hash

Don’t just send the e-mail as HTML. Many e-mail providers don’t allow for HTML e-mails, so you need alternative content. You will need a boundary string, but you will also want it to be random hash. Why? Well, I’m not really sure. I can easily imagine one scenario, which would be that if you are sending mail on behalf of someone, and they figure out your static boundary string, they could do some sort of injection attack and send some nasty thing through with your e-mail. Not really sure if this would work, or if this is the reason, but everyone else uses a random hash, so you should too!

<?php
//create a boundary string. It must be unique
//so we use the MD5 algorithm to generate a random hash
$random_hash = md5(date('r', time()));
//define the headers we want passed. Note that they are separated with \r\n
$headers = "From: webmaster@example.com\r\nReply-To: webmaster@example.com";
//add boundary string and mime type specification
$headers .= "\r\nContent-Type: multipart/alternative; boundary=\"PHP-alt-$random_hash\"";
?>

2. Don’t use HEREDOC syntax

At first I was trying to just do this:

$msg <<<HERE
--PHP-alt-$random_hash
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

Plain text stuff

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

<html>
<body>
<p>
Blah blah blah $var blah!
</p>
</body>
</html>
--PHP-alt-$random_hash--
HERE;

But it just wouldn’t work! I figured out you have to do it like this:

$message = "--PHP-alt-$random_hash\n\r" .
"Content-Type: text/plain; charset=\"iso-8859-1\"" .
"Content-Transfer-Encoding: 7bit\n\r" .  

"Hello World!!! \n\r" .
"This is simple text email message. \n\r" .  

"--PHP-alt-$random_hash\n" .
"Content-Type: text/html; charset=\"iso-8859-1\"" .
"Content-Transfer-Encoding: 7bit\n\r" .  

"<h2>Hello World!</h2>\n\r" .
"<p>This is something with <b>HTML</b> formatting.</p> \n\r" .  

"--PHP-alt-$random_hash--";

Pay special attention to where you are putting your \ns and \rs!!!

3. Get the from right!

When building your headers, don’t forget to include a from. This will make your e-mail more recognizable and professional. Don’t just include the from though, include a human readable value as well!

$headers = "From: An actual name <email@email.com>\r\n";

4. Don’t forget those trailing “–” after the final bondary!

Don’t forget those last two dashes on your final boundary:

--==Multipart_Boundary_{$semi_rand}x--

See them there at the end? You don’t put those on the others, so they are easy to forget on the final one. Also, it’s boundary with an “a”, not “boundry”… Yeah, I misspelled it the first time…

5. If things aren’t working, experiment

It took me a good hour and a half to get this working right. It all came down to those little \r and \n things in the end. I had to carefully add and remove them from different places until I got everything just right. The webcheatsheet code conveniently uses some buffer trickery to avoid this, but my web host does not support that, so I had to figure it all out myself. Here is a version of their code that actually works on my web hose (Dreamhost):

<?php
//define the receiver of the email
$to = 'email@gmail.com';
//define the subject of the email
$subject = 'Test HTML email';
//create a boundary string. It must be unique
//so we use the MD5 algorithm to generate a random hash
$random_hash = md5(date('r', time()));
//define the headers we want passed. Note that they are separated with \r\n
$headers = "From: webmaster@example.com\r\nReply-To: webmaster@example.com";
//add boundary string and mime type specification
$headers .= "\r\nContent-Type: multipart/alternative; boundary=\"PHP-alt-$random_hash\"";
//define the body of the message.
$message = "--PHP-alt-$random_hash\n\r" .
"Content-Type: text/plain; charset=\"iso-8859-1\"" .
"Content-Transfer-Encoding: 7bit\n\r" .  

"Hello World!!! \n\r" .
"This is simple text email message. \n\r" .  

"--PHP-alt-$random_hash\n" .
"Content-Type: text/html; charset=\"iso-8859-1\"" .
"Content-Transfer-Encoding: 7bit\n\r" .  

"<h2>Hello World!</h2>\n\r" .
"<p>This is something with <b>HTML</b> formatting.</p> \n\r" .  

"--PHP-alt-$random_hash--";

//send the email
$mail_sent = mail( $to, $subject, $message, $headers );
//if the message is sent successfully print "Mail sent". Otherwise print "Mail failed"
echo $mail_sent ? "Mail sent" : "Mail failed";
echo $message;
?>

Have fun! Feel free to comment if you have any other tips/questions.

Tags: , , ,

6 Responses to “HTML E-Mail with PHP: 5 Pointers to Get ‘er DONE!”

  1. SchizoDuckie says:

    Why re-invent the wheel? Use PHPMailer!

  2. admin says:

    Maybe that should have been pointer #1. ;)

    Problem being that it isn’t a standard part of PHP, so I didn’t know about it. It does look like a good library though… Thanks!

  3. cool thanks for posting this

  4. Hi there cos i so totally dig your great site, i wuold feel very special if you would want me to publish a site review about your great website in my iPod Newssite http://kh3.us would you grant me permission to? XoX,

  5. lol, sure, go for it! Thanks.

  6. I’m happy I found this blog site, I couldnt discover any info on this subject matter before. thanks

Leave a Reply