UTF-8 emails with PHP and Mail_Mime

The web application I’m developing as a student job needs to send emails. „Unfortunately“ these emails sometimes contain non-ASCII characters like umlauts or whatever. Stumbled upon broken characters the first time I used the first solution that came along (cited from php.net):

  1. <?
  2.   function mail_utf8($to, $subject = '(No)', $msg = '', $header = '') {
  3.       $header_ = 'MIME-Version: 1.0' . "\r\n"
  4.       $header_ .= 'Content-type: text/plain; charset=UTF-8' . "\r\n";
  5.       mail($to, '=?UTF-8?B?'.base64_encode($subject).'?=', $msg, $header_ . $header);
  6.   }
  7. ?>

Then some day a mail server which received one of the mails sent with this function replied with a delivery status notification which said:

Your message WAS SUCCESSFULLY RELAYED to: <foo@bar.com>
 INVALID HEADER: INVALID 8-BIT CHARACTERS IN HEADER SECTION


So this mail server relayed the email (like all the others too) but also kindly informed me that there is a violation of the email standard defined in RFC5322. The reason for this is that emails, according to the standard, only may consist of ASCII characters and the above function does not cover header fields (and body). The way to overcome this is to use MIME (Multipurpose Internet Mail Extensions) which describes how non-ASCII headers and messages can be sent. It is also used to transfer email attachments.

Mail_Mime – A simple but sufficient mail package

To please the above mail server and being standard compliant I began to look for an uncomplicated way to send emails containing UTF-8 characters. I ended up with the Mail_Mime pear package which satisfies my needs. Using it is easy. First, the pear packages Mail and Mail_Mime must be installed, which can be done with the following shell commands if pear is available:

  1. pear install Mail
  2. pear install Mail_Mime

Sending an Email with Mail_Mime

The following code shows the basic usage of Mail_Mime:

  1. <?
  2. require_once "Mail.php";
  3. require_once "Mail/mime.php";
  4. // array of headers with the header field as key and its contents as value
  5. $headers = array("From" => "John Doe <john.doe@example.com>",
  6.                  "Reply-To" => "Some One <replyto@example.com>",
  7.                  "Subject" => "The email's subject",
  8.                  "X-Custom" => "A custom header");
  9. // original, not encoded receiver string
  10. $to = "Max Mustermüller <mustermüller@example.com>";
  11. // prepare plaintext and html body (mail clients will only display
  12. // one of them so they should be "the same")
  13. // it is sufficient to use/set either portion, html or plaintext
  14. $txtMsg = "This *is* the plaintext _portion_ of the email body.";
  15. $htmlMsg = "<html><body>This <b>is</b> the html <u>portion</u> of the email body."
  16.                                                                  . "</body></html>";
  17. // create new Mail_mime instance, set utf-8 charset
  18. $mail = new Mail_mime(array("text_charset" => "utf-8",
  19.                             "html_charset" => "utf-8",
  20.                             "eol" => "\n"));
  21. // set email body
  22. $mail->setTXTBody($txtMsg);
  23. $mail->setHTMLBody($htmlMsg);
  24. // prepare headers
  25. foreach ($headers as $name => $value){
  26.     $headers[$name] = $mail->encodeHeader($name, $value, "utf-8",
  27.                                                            "quoted-printable");
  28. }
  29. // also encode to value
  30. $to = $mail->encodeHeader("to", $to, "utf-8", "quoted-printable");
  31. // fetch message
  32. $msgDone = $mail->get();
  33. // let Mail_Mime finish the headers (adds e.g. MIME info)
  34. $headers_done = $mail->headers($headers);
  35. // send the email
  36. $mailSend = Mail::factory('mail');
  37. $mailSend->send($to, $headers_done, $msgDone);
  38. ?>

Troubleshooting

With this there should be no more problem with non standard compliant emails. However, if you encounter problems with the representation of some characters on the receiver side, one possible cause for this may be a wrong charset for user input. In Apache 2 this can be fixed with adding AddDefaultCharset utf-8 to the configuration applying for the respective page.

Comments (3)

stJuli 29th, 2011 at 02:53

Ich hab kein richtiges guestbook gefunden, deshalb muss ich mal die comments missbrauchen.^^
Find ich Top was du hier machst, pyro, gute Sache :A
Gruß ST

VickyJanuar 2nd, 2013 at 22:24

The clearest explanation I have found yet (and I have been searching for 2 days, including wading through PEAR manuals and discussions anout quails and other geek talk) – thank you!!!!

MikkaAugust 19th, 2013 at 20:31

Thank you very much! I’ve been stuck on this problem for a few days … I’m not very familiar with PHP, but your explanation is very clear and easy to understand!

Leave a comment

Your comment

(required)