Share via:

PHP: mail

How to use the mail function, and why you should not use it.

104 views

Edited: 2019-11-02 15:38

PHP article image

PHP's mail function can be used to send e-mail from PHP applications, but usage of the bare function should be avoided. In general, it is recommended to not rely on the bare mail() function for broader use, and it is important you understand why. So, please take the time and read about it.

An issue mentioned in the official php.net reference has to do with performance when sending larger volumes of e-mail. But, there are more important reasons to avoid fiddling with the mail function yourself.

You might think that sending e-mail from PHP is easy, since it appears to be working with little effort, and even when sending HTML e-mails with attachments.. This was what I thought for a long time, until I noticed header duplication for no apparent reason. This led me to read the RFCs, and suddenly I realized that I might run into other problems.

E-mails might "silently" get malformed without you realizing, and this might happen even if you do things right in your code.

The correct way to send a HTML e-mail from PHP:

$from = 'John Doe <john@example.com>';
$to = 'John Doe 1 <john1@example.com>'; // Can be a comma separated list

$headers = array();
$headers[] = 'MIME-Version: 1.0';
$headers[] = 'Content-type: text/html; charset=UTF-8';

$headers[] = 'From: ' . $from;
$headers[] = 'Reply-To: ' . $from_email;
// $headers[] = 'Cc: '; // Everyone can see these recipients
// $headers[] = 'Bcc: '; // Secret recipients

mail($to, $subject, $message, implode(PHP_EOL, $headers));

Formatting of headers

Each header must end with CRLF. Postfix automatically replaces the EOL, so it does not matter if you use "\r\n" or just "\n". In a PHP script, it can be added via the double quoted string: "\r\n", but, for maximum portability PHP_EOL may be used.

Also, when using postfix, you must be consistent throughout your script, and not suddenly start using only "\n" if you have been using "\r\n".

According to the postfix mailing list where someone asked about this specifically, the answer was that postfix will look at the first line, and then determines what your EOL is from that. Quoting Victor Duchovni:

> So how does postfix determine what format you are using?
> Is there a way to explicitly tell it what to expect?

By looking at how the first line of message content is terminated. All subsequent lines must be terminated the same way.

By Victor Duchovni

Also, the creator of Postfix, Wietse Venema, wrote this:

  1. Postfix receives local submissions in (LF or CRLF) format, SMTP submissions in SMTP format (CRLF), and QMQP submissions in a format that does not use CR or LF.

    Specifically, Postfix accepts local submissions in UNIX format (LF) or MSDOS format (CRLF) format BUT YOU MIST NOT MIX FORMATS.

  2. Postfix stores mail in the queue in a format that does not use CR or LF.

  3. Postfix delivers local mail in UNIX (LF) format, SMTP mail in SMTP format (CRLF).

It would be really good if PHP application programmers formatted email messages in a consistent manner. For example, they could use a variable that contains the END-OF-LINE terminator, instead of hard-coding LF or CRLF line terminators all over the place.

That is basic software engineering practice.

By Wietse Venema

So, the headers should be formatted like this in your code:

$headers = array();
  $headers[] = 'MIME-Version: 1.0' . PHP_EOL;
  $headers[] = 'Content-type: text/html; charset=UTF-8' . PHP_EOL;
  $headers[] = 'To: ' . $to  . PHP_EOL; 
  $headers[] = 'From: ' . $from  . PHP_EOL;
  $headers[] = 'Reply-To: ' . $from_email . PHP_EOL;

Note the use of PHP_EOL instead of "\r\n". Postfix works with both "\r\n" and "\n", but for your script to also work on Windows, PHP_EOL is a better choice than hard-coding it in your script.

PHP_EOL will match the "\r\n" line break used on Windows, and "\n" on Linux. Postfix works with both and will automatically separate the headers using "\r\n" when sending the e-mail.

Limitations and maximum line length

The unfortunate reality is that e-mail is a very old standard, and suffers from a number of limitations and bad implementations. It is not a small task to make your e-mails broadly compatible with commonly used e-mail clients. Besides problems with sending your e-mail with the correct formatting and headers, HTML is also poorly supported and while basic formatting is fine, more complex layouts might break due to differences in how clients handle HTML and CSS.

The maximum body line length is 998 characters, and if folded at the wrong place, this could ruin the formatting of a HTML e-mail.

The maximum line length of mail header fields is tiny. I think it is just around 72 characters, at which point a header should be "folded". The way this works is by inserting ([CRLF] + [SPACE]) or "\r\n " in PHP.

If you are using Swiftmailer, PEAR, or PHPMailer, such issues should be automatically handled without you having to study the RFCs and potential differences in implementation.

I hope this helps.

Links

  1. Long header folding adds additional spaces #1525 - github.com
  2. RFC2047 - ietf.org

Comments