Repository navigation
Mail() function not working correctly in PHP 8.x #8086
Description
Description
The following code:
<?php
mail("[email protected]", "This is the subject", "This is the body");
?>Resulted in this output of the DATA part of the communication from tcpdump on the receiving SMTP server when building container "FROM php:8.0.14-fpm-alpine" or "FROM php:fpm-alpine":
Received: by f3de6efeb3a0 (sSMTP sendmail emulation); Sat, 12 Feb 2022 06:28:10 +0100\r\n
From: "Linux User" <www-data@f3de6efeb3a0>\r\n
Date: Sat, 12 Feb 2022 06:28:10 +0100\r\n
To: [email protected]\r
\r\n
Subject: This is the subject\r
\r\n
\r
\r\n
This is the Body\r
\r\n
\r\n
And this is the resulting mail headers of the mail on the receiving SMTP server:
Return-Path: <www-data@f3de6efeb3a0>
X-Envelope-To: [email protected]
Message-ID: <[email protected]>
Received: from localhost ([127.0.0.1])
by mail.example.com with SMTP
for [email protected];
Sat, 12 Feb 2022 06:28:10 +0100
Received: by f3de6efeb3a0 (sSMTP sendmail emulation); Sat, 12 Feb 2022 06:28:10 +0100
From: "Linux User" <www-data@f3de6efeb3a0>
Date: Sat, 12 Feb 2022 06:28:10 +0100
To: [email protected]
This is the output using the exact same environment, just that the container is build using "FROM php:7.4-fpm-alpine":
Received: by ae23725475da (sSMTP sendmail emulation); Sat, 12 Feb 2022 06:27:33 +0100\r\n
From: "Linux User" <www-data@ae23725475da>\r\n
Date: Sat, 12 Feb 2022 06:27:33 +0100\r\n
To: [email protected]\r\n
Subject: This is the subject\r\n
\r\n
This is the Body\r\n
And this is the resulting mail headers of the mail on the receiving SMTP server:
Return-Path: <www-data@ae23725475da>
X-Envelope-To: [email protected]
Message-ID: <[email protected]>
Received: from localhost ([127.0.0.1])
by mail.example.com with SMTP
for [email protected];
Sat, 12 Feb 2022 06:27:33 +0100
Received: by ae23725475da (sSMTP sendmail emulation); Sat, 12 Feb 2022 06:27:33 +0100
From: "Linux User" <www-data@ae23725475da>
Date: Sat, 12 Feb 2022 06:27:33 +0100
To: [email protected]
Subject: This is the subject
The result is that when using PHP 8 there are some invalid "\r" which makes the mail format invalid and so the headers are not processed correctly on the receiving SMTP server. The result is that the email does not have a subject. I've also tried setting additional headers, but they are all invalid and not processed due to the invalid "\r".
I've tried using both sendmail and ssmtp in the container. It yields the same result.
My php.ini setting are:
sendmail_path = '/usr/sbin/sendmail -t -i -S myserver:25'
Something has changed in the PHP mail() function between PHP 7 and PHP 8
PHP Version
PHP 8.0.14 and newer
Operating System
Docker php:8.0.14-fpm-alpine and php:fpm-alpine
Activity
[-]Mail() functio nnot working in PHP 8.x[/-][+]Mail() function not working correctly in PHP 8.x[/+]cmb69 commentedon Feb 13, 2022
mail()now outputs proper email line endings (i.e.CRLFinstead ofLF). It looks like your MTAs convert that toCRCRLF, what would be a bug in those MTAs.hansherlighed commentedon Feb 13, 2022
The capture from tcpdump is taken on the PHP server, so the trace is captured when going FROM PHP to the MTA(it's the output from sendmail). So the CRCRLF seems to comes from PHP, not the MTA(unless you refer to sendmail as the MTA).
If I read the specifications correctly, PHP should output CRLF directly after each line(which it does in PHP 7.4), but does not in PHP 8.
When you say MTA, do you mean sendmail? Do you mean that it is sendmail that is converting the input from PHP to CRCRLF?
Is there anyway to see the raw output sent from PHP to sendmail?
cmb69 commentedon Feb 13, 2022
You can see the raw PHP output by e.g. writing to a file instead of using sendmail. I.e. set
sendmail_pathto something liketee mailBasic.out >/dev/null.hansherlighed commentedon Feb 13, 2022
Thanks @cmb69
I was able to get the raw output from the mail() function into a file using your advice.
You are indeed right, the raw output from PHP 8 looks like this:
and in PHP 7 it looks like this:
This issue has actually been reported to PHP way back in 2002:
https://bugs.php.net/bug.php?id=15841
The problem remains the same as reported in this bug. on UNIX systems, the line ending is expected to be "\n" as it is the native line ending for the system. Since PHP's mail() function on UNIX systems, is basically sending raw text output to a UNIX command(sendmail if you follow the documentation) the mail() function will not work as sendmail expects the line endings to be "\n" and NOT "\r\n".
By making this new change to the mail() function so it always uses "\r\n" for the build in headers for Subject: and To:, you've actually made things worse, and made your documentation invalid. It states in the mail() documentation page:
Following this note will cause the output from PHP8 to be a mix of "\r\n" and "\n" for the headers. The build in headers for "To:" and "Subject:" will still use "\r\n" even if you set the additional headers to use only "\n".
running
mail([email protected], "This is the subject", "This is the Body", "From: [email protected]\nContent-Type: text/plain");results in:The essence of the problem is that a UNIX command/program expects line endings to be "\n" and not "\r\n", and since the mail() function on UNIX systems, forwards/outputs to a UNIX command rather than talking to an SMTP server directly, it causes problems.
Why can't the mail() function use the same line endings as PHP_EOL, so that on windows it becomes "\r\n" and unix "\n"? That would make the function more platform independent.
The solution when using the "php:fpm-alpine" image is to set "sendmail_path" to:
'/usr/bin/dos2unix -u|/usr/sbin/sendmail -t -i'55 remaining items
PSMEL-274 - PHP 8 Encoding Issue
aly9 commentedon Apr 10, 2023
Dears, Is there any final class for sending emails to be used in PHP version greater than 8 without changing the sendmail_path ? Since we are not allowed to change the .ini file configuration in some shared hosting.
bukka commentedon Apr 12, 2023
@aly9 no but you should contact the hosting provider to change it globally in their configs.
djixas commentedon Apr 17, 2023
I'm experiencing this issue too and it's driving me insane , both on PHP 8,1 and 8,0, and i am not using alpine
Shardj/zf1-future#274
aly9 commentedon Apr 17, 2023
@bukka Thanks for your reply, but I have modify my sending emails script to use PHPMailer Class and it is working fine.
zaphod77 commentedon Dec 12, 2023
Sendmail binaries on linux, and pretty much every other OS using LF only are designed to parse normal text for the operating system when piped to directly.
They internally convert to match the RFC after, which causes a doubled up CR usually with php 8.x now.
Actual Sendmail does have a -ba parameter, which does place it into ARPANET mode, which will do the right thing when presented with a text file containing CRLFs for injection. specifying the -ba option in sendmail path does fix the issue, but naturally, the email tester doesn't do this. So the email test fails.
qmail's fake sendmail binary does NOT SUPPORT -ba. not even the alternate usendmail wrapper does. postfix, and most other MTAs that provide a fake sendmail binary do not support ARPANET mode like a real sendmail binary does. The only one that i've seen that does this is actual sendmail itself.
The sendmail binary has always accepted email for injection in the OS native text format. All other MTAs that have fake sendmail binaries do the same. They all still send RFC compliant emails, doing the needed conversion. When telnetting or s_clienting to the smtp port, telnet itself usually handles this part, and will convert the line endings properly.
I'm sorry, but PHP is wrong here. it's mail() function expects either smtp on windows, or a sendmail binary on linux/bsd/osx/etc. And sendmail has ALWAYS accepted messages in the UNIX (linefeed only) text scheme on unix, and it always will.
This isn't a silly RFC issue. Sendmail is NOT breaking the RFC by accepting and interpreting piped data stored in native OS text format. the RFC is for message transmission, and when using sendmail binary, php is not transmitting itself. it's handing off to the sendmail binary.
Exim is one that's smart enough to just do the right thing. It actually just strips out the \rs and then puts them back when it send the message :). I'm sure there are some others, but as we can see, it's just not widespread enough.
Now this IS something that configure should be able to catch.
actual sendmail will respond to
"sendmail -ba"
with
550 Recipient names must be specified
in this case, it's real sendmail, and -ba should be added to the options automatically.
Any other response mean sit's not actual sendmail, we can't do that.
derStephan commentedon Feb 26, 2024
I think, PHP is mixing up responsibilities. There are 2 involved parties and both of them have their own tasks.
It is PHP's responsibility to assemble all information needed by the mail agent. And it is PHP's responsibility to hand that information over to the mail agent in way that is valid for the OS and the mail agent itself.
This is where PHP's responsibilities end.
The mail agent is responsible to take the information and create a Mail that complies to the respective RFCs.
We now have the situation that the standard way of sending mails is broken due to PHP's interference in something that is not their business.
I tried the new config variable
mail.mixed_lf_and_crlf = Onand at first this seemed to work as before. All mails look nice in Outlook an Thunderbird and everywhere. But I keep getting bounces from remote mail servers along the lines ofThis is unacceptable. The only thing that seemed to work is undoing PHP's magic by setting
sendmail_path='/usr/bin/dos2unix -u|/usr/sbin/sendmail -t -i'With this config setting, mails look good in all clients and there are no bounces. Seems like my mail agent (nullmailer) cares about RFC compliance quite fine on it's own.
May I ask you to revert this broken feature? Ensuring mailing RFCs is not PHP's responsibility.
bukka commentedon Feb 26, 2024
mail.mixed_lf_and_crlf = onshould be an exact revert of the breaking change. If you see some differences between what was in PHP 7 and whatmail.mixed_lf_and_crlf = ondoes, please open a new issue (bug) with all the info and I will take a look.zaphod77 commentedon Feb 26, 2024
The CORRECT behavior is to produce standard text in the operating system's standard text format when piping to sendmail, and to use CR+LF when using SMTP, which is the circumstance where having it be CRLF matters. Funny enough this setting is used on windows, which already uses CRLF.
PHP has a responsibility to pipe stuff to sendmail binaries in the format the sendmail binary expects, which is ALWAYS the native text format used by the operating system, unless it's real sendmail in ARPANET mode.
bukka commentedon Feb 28, 2024
If you want any change to happen, you need to create a new issue. Comments in closed issues are pretty much useless because it just get forgotten.
csandanov commentedon Mar 7, 2024
I also had issues with
mail.mixed_lf_and_crlf = Oncouldn't make it work with msmtp, so I keep using
/usr/bin/dos2unixbukka commentedon Jul 20, 2025
For the record I created a new feature request to address the above: #19188 . If you have any further suggestions, please comment there.
Fix flaky extra mail header (phpGH-8086)