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.