Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Line ending problem? v6 and PHP7 #953

Closed
arxeiss opened this issue Jan 6, 2017 · 48 comments
Closed

Line ending problem? v6 and PHP7 #953

arxeiss opened this issue Jan 6, 2017 · 48 comments

Comments

@arxeiss
Copy link

arxeiss commented Jan 6, 2017

I have a problem with emails sent via PHPMailer v6 and PHP7. It looks like a problem with line endings, because there is =0D at the end of each line. However, if I send same email, with same message etc. those symbols are not there.

This is quite big problem, cause some email clients then show empty message. So for now, v6 is totally useless for me.

Problem happen with latest PHPMailer v6, but with v5.2.21 email is OK

@Synchro
Copy link
Member

Synchro commented Jan 6, 2017

=0D is a quoted-printable-encoded Unix line break. It means that your message body text (what you're assigning to Body) is using Unix LF line breaks, but the overall message is using RFC-standard Windows CRLF breaks (which changed in 6.0 - in 5.2 it's inconsistent), which is how it should be. If you convert your message body to CRLF breaks, does that help? Does changing the sending mechanism (e.g. isSMTP() rather than isMail()) make a difference?

@arxeiss
Copy link
Author

arxeiss commented Jan 6, 2017

Cannot use SMTP, so I'm using only mail function.
But I still think, that this is wrong. You have in code:

/**
 * The default line ending.
 *
 * @note The default remains "\n". We force LE where we know
 *        it must be used via static::LE.
 * @var  string
 */
public $LE = "\n";

/**
 * SMTP RFC standard line ending.
 *
 * @var string
 */
const LE = "\r\n";

Everywhere in your code you are using static::LE which actually points to const LE so public $LE is never used. So even if I change all my Windows endings \r\n to UNIX ones \n before assigning to Body, after all procedures inside your script, I receive email again with those =0D everywhere.

@Synchro
Copy link
Member

Synchro commented Jan 6, 2017

The public property needs deleting, thanks for spotting that. You're not meant to be able to change it any more, though the constant is static so you can override it easily. I'll need to double-check what is happening to the body.

The mail function requires a local mail server, so what is stopping you connecting to localhost on port 25?

@arxeiss
Copy link
Author

arxeiss commented Jan 6, 2017

No no.. Probably misunderstanding.. Email is sent, that is OK. I don't have a problem with isMail()...

Problem is, that if message is full of those characters =0D then some email clients show empty message, even I received 30kB message. This is happening to Body and AltBody as well, so even I change view from HTML to plain text, or vice versa, I still see nothing.

@Synchro
Copy link
Member

Synchro commented Jan 6, 2017

I've been testing this. I can't get it to do anything wrong, sending via both mail and SMTP. Line break formats in bodies are preserved. If I use Unix line breaks, they get converted into =0A in quoted-printable encoding. Note that although I send the messages with CRLF breaks, postfix converts them to LF when saved to disk (I'm on OS X).

Are you setting $mail->Encoding = 'quoted-printable';? If not, does your content contain very long lines?

I got the wrong char earlier =0D is a carriage return (CR) char, not a line feed (LF), which is a bit of a mystery. CR is used as the line break format on old MacOS, so I don't know why you'd end up with it in there. Could you email me your code and some example content to me at phpmailer at synchromedia dot co dot uk so I can try to reproduce it?

@swiffer
Copy link

swiffer commented Jan 11, 2017

I think I stumpled exactly the same problem. While everything works fine in PHPMailer 5.2.22 Outlook 2016 is showing an empty Message body when using PHPMailer 6.0

(PHP 5.6 is used)

@arxeiss
Copy link
Author

arxeiss commented Jan 11, 2017

Sorry for my late answer. I will send it to your email, but also type it here:

I'm not changing Encoding, so it stays 8bit. But incoming email is quoted-printable. Here is my code:

$mailer = new \PHPMailer(true);
$mailer->CharSet = 'UTF-8';
$mailer->isHTML(true);
$mailer->setFrom(EMAIL_FROM, EMAIL_FROM_NAME);
$mailer->Subject = $this->emailSubject;
$mailer->addAddress($orderData['email'], $orderData['name']." ".$orderData['surname']);

// Email normally contains also PDF attachments
/ But for testing, this was commented, and email source codes are without attachments
for ($i=0; $i < count($orderData['tickets']); $i++) {
    $mailer->addStringAttachment(
        $this->generateTicketPDF($orderData['tickets'][$i], $this->ticketTemplate),
        $orderData['tickets'][$i]['code'].".pdf"
    );
}
// Getting from template, can be changed to get_file_contents()
$mailer->Body = $tpl->render(true);
$mailer->AltBody = $tpl_plain->render(true);

$mailer->send();

I'm using Windows, so my files contains \r\n. Problem is with both Body and AltBody. Here you can download templates and also received source code: Templates and Email source codes. In my code I also tried before assigning to Body and AltBody replace \r\n to \n by this code, but happen the same:

// Getting from template
$mailer->Body = str_replace("\r\n", "\n", $tpl->render(true));
$mailer->AltBody = str_replace("\r\n", "\n", $tpl_plain->render(true));

@Synchro
Copy link
Member

Synchro commented Jan 11, 2017

If it's switching to quoted-printable automatically, it means you're passing in content with very long lines. It's the only way to build messages that have very long lines without breaking them, and is the same behaviour used by other apps, for example Apple Mail does the same. There are some other issues in here relating to that. It seems that outlook is particularly prone to mishandling long lines and QP-encoding.

@Synchro
Copy link
Member

Synchro commented Jan 11, 2017

Try wrapping your content to say 65 chars and see if that makes a difference.

@swiffer
Copy link

swiffer commented Jan 17, 2017

for me its still not working in PHPMailer 6.0 while it's working in 5.2.22 (sort of, line breaks are not shown in Outlook 2016)

I dumped the PHPMailer objects, PHPMailer is not using SMTP, can it be server configuration problems?

https://www.diffchecker.com/vcHMpOvG

(i dumped before adding the receiver via addAddress so this is missing in both)

@Synchro
Copy link
Member

Synchro commented Jan 17, 2017

The difference in config isn't apparently important; what matters is the exact binary of the sent message. It's a bit difficult to get hold of this because many MTAs (e.g. postfix) "correct" line breaks automatically on receipt. I think the closest we can get is to send the same message in 5.2 and 6.0 and grab the resulting message using preSend() followed by getSentMIMEMessage(), write them directly to a file and compare the two in a hex dump. It's very hard to find text editors that don't alter line breaks! I really want to fix this before 6.0 is released, but it's proving very difficult to reproduce.

@swiffer
Copy link

swiffer commented Jan 17, 2017

ok, i'll try the best I can

attached two screenshots created with exactly the same message content, line endings definitly are not the same

PHPMailer 5.2

phpmailer52

PHPMailer 6.0

phpmailer60

the files were dumped as you told in your comment above, and then saved to disk via

$mailHandler->preSend();
$message = $mailHandler->getSentMIMEMessage();

$fhandle = fopen("PHPMailer60.dump", "w");
fwrite($fhandle, $message);
fclose($fhandle);

@swiffer
Copy link

swiffer commented Jan 17, 2017

Think I got it in PHP's manual

Note: If messages are not received, try using a LF (\n) only.
Some Unix mail transfer agents (most notably » qmail) replace LF by CRLF automatically (which leads to doubling CR if CRLF is used).
This should be a last resort, as it does not comply with » RFC 2822.

So while the new behaviour is ok there must be an option to force LF only for older mail agents?

@arxeiss
Copy link
Author

arxeiss commented Jan 17, 2017

I tried it as well and I got the same result. wrapText() did not help and when viewing message in binary mode, got different line endings:
Version 5:
image
Version 6:
image

Also this printed message with PHP with replacing line endings like this:

header("Content-type: text/plain");
$mailer->preSend();
$msg = $mailer->getSentMIMEMessage();
$f = fopen("v5.bin", "wb");
fwrite($f, $msg);
fclose($f);
$msg = str_replace(["\n", "\r"], ["\\n\n", "\\r"], $msg);
echo $msg;

Version 5:

takto zobrazit\n
\n
\n

Version 6:

takto zobrazit\r\n
\r\n
\r\n

@Synchro
Copy link
Member

Synchro commented Jan 17, 2017

@swiffer thanks for those. The next interesting thing to try would be to send a single message: grab it directly from PHPMailer, and compare that with what turns up in your outlook client - that will tell us if the messages changes between sending and receiving. This will also be visible in debug output. Ideally we'd get a control in there too, for example to BCC it to a gmail account, which will help eliminate/blame receiver-side processing.

I can see that the reason that the message does not render is that it lacks a double line break between the header and body; this bit:

Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable
=0D
<!DOCTYPE html>=0D

As for was we should be doing, the specs are absolutely clear. RFC5322 S 2.3 says:

CR and LF MUST only occur together as CRLF; they MUST NOT appear independently in the body.

RFC 2046 (MIME) S 4.1.1 says:

The canonical form of any MIME "text" subtype MUST always represent a
line break as a CRLF sequence. Similarly, any occurrence of CRLF in
MIME "text" MUST represent a line break. Use of CR and LF outside of
line break sequences is also forbidden.

(incidentally, this same section also mandates automatic switching of transfer encoding for content with lines that are too long - I had thought this was just good practice, but it's actually an RFC recommendation too).

In other words, 5.2.x is undeniably doing it wrong, which is why 6.0 is switching this way, however, something is clearly upsetting Outlook somehow. As has been mentioned earlier in this thread, it seems that only some configurations of Outlook have this issue, and it looks like it might be some kind of filter service because tests I've done in Outlook do not have any issues at all, and I have yet to manage to create an outbound message that looks anything like these corrupted received messages.

@swiffer
Copy link

swiffer commented Jan 18, 2017

is it different configuration of outlook (mine is using office365 in background) or is it some outgoing mail agents like qmail auto adding a second CR as mentioned in the PHP manual ?

at least in some moodle blogs i can see the following code used:

https://github.com/VERSION2-Inc/moodle-block_quickmailjpn/blob/master/locallib.php#L45-L50

(opening the email in office 365 for web shows the same results outlook 2016 shows -> empty message in 6.0, normal message text without linebreaks in 5.2)

What do you mean by sending a single message, didn't get what I should do now

@Synchro
Copy link
Member

Synchro commented Jan 18, 2017

I mean send a message to an outlook account with PHPMailer; BCC it to a gmail (or other neutral provider); capture it using getSentMIMEMessage; grab the delivered message from outlook. The key thing here is you're sending only one original message, so everything should be pretty much identical (save a few headers added by receivers) across all the places it ends up. If the message that turns up in gmail does not have the =0D corruption in it, we know it's something that outlook is doing (and conversely, if it does, we know it's either an issue with our source mail server or PHPMailer), and we can also check it against the original message we submitted. For bonus points, having SMTPDebug = 2 set allows you to inspect it during message submission too, giving us 4 views of the exact same message that we can compare.

@Synchro
Copy link
Member

Synchro commented Jan 18, 2017

I posted about this previously - using someone else's troublesome content (posted in this thread) results in a perfectly good message in my outlook webmail.

@swiffer
Copy link

swiffer commented Jan 18, 2017

Ok, as i was Not using smtp i Switched to smtp (Office 365 smtp server) and everything works Fine Right now- at least in my case was a Problem of direct sender as far as i Can tell

@arxeiss
Copy link
Author

arxeiss commented Jan 18, 2017

isMail

Note that I'm still using isMail() to send email.

I just tried send the same message as above into my 3 accounts. GMail, Outlook (outlook.com) and Centrum.cz (Czech mail service).
In GMail it works perfectly, viewing source code of message, there are no =0D .
In Outlook.com it says Empty message, but viewing source code, there are no =0D but there are much more new headers.
In Centrum.cz it also says Empty message, but viewing source code show =0D in every line.

Output in file is same as in my previous post.
After I changed like this: const LE = "\n"; It works perfectly in GMail, Outlook.com and Centrum.cz.

isSMTP

Now I also tried IsSMTP() with my university SMTP server (vsb.cz)

If I tried to send email with SMTP, everything works in all those clients mentioned above. If I check source code, there is no =0D anywhere. (Yes, I changed const LE back to \r\n before I tried isSMTP)

@Synchro
Copy link
Member

Synchro commented Jan 19, 2017

Thanks @swiffer and @arxeiss, that's really helpful. Can you tell me what mail server you are using locally, when sending via isMail()?

@arxeiss
Copy link
Author

arxeiss commented Jan 19, 2017

Sadly I cannot. I'm using it on webhosting, not VPS or something similar and I cannot get more info about it. I will try to reproduce this error on different webhostings I have access to, but not sure that somewhere else I can find more info...

@Synchro
Copy link
Member

Synchro commented Jan 19, 2017

If you telnet localhost 25 it will often say. For example on my Mac it says:

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 Mac.localdomain ESMTP Postfix

@arxeiss
Copy link
Author

arxeiss commented Jan 23, 2017

I cannot telnet my webhosting. It is blocked. That problem is happening on webhosting, where I don't have full access. It is regular webhosting as many others.

@Synchro
Copy link
Member

Synchro commented Jan 24, 2017

I've managed to make my local postfix do something strange with line breaks that looks like it may be the underlying cause of this. PHP itself appears to add headers with a platform-specific line break type, which results in mixed line breaks in the message, which can lead to bad quoted-printable decoding. I need to look at PHP's source code to see exactly what it's up to.

@ASchmidt1
Copy link

ASchmidt1 commented Feb 1, 2017

Your "legacy" challenge is the use of the PHP mail function, which (until PHP 5) has been reconciling two directly opposing requirements

  • mail() under Linux was designed to talk to a (command line) mailer, some of which had flat-out required the input to be operating system line end (single line feed) and rejected/mangled any SMTP compliant CR/LF.
  • mail() under win32 on the other hand is talking directly to SMTP, which absolutely mandates RFC compliant line-ends.

Up to PHP 5, they had taken the logical/pragmatic step of simply adapting the win32 implementation to fix any lone LF (which kept everyone happy).

PHP eliminated the automatic fix-up for v7 and clarified the documentation that RFC-compliant CR LF should be used in for additional headers (with a footnote to try lone LF if they legacy Linux mailer has issues). They have also stated intentions that change this "string" parameter to an "array", thus completely eliminating ANY line end issues.

For maximum compatibility with PHP 5 vs PHP 7 on Linux vs. PHP 7 on Windows, you could make the $LE default depending on the mailer AND operating system platform:

  • If the mailer is SMTP (e.g, if PHP 7 reports win32, and the mailer is mail() ) THEN the default $LE absolutely MUST be the RFC compliant CRLF.
  • However if the mailer is NOT direct SMTP (e.g., PHP mail() and not win 32), THEN you COULD allow $LE to use a lone LF as the default to maintain backward compatibility.

This might provide for best backward compatibility while achieving standards compliance:

if ( $this->Mailer == 'smtp' || ( $this->Mailer == 'mail' && stripos(PHP_OS, 'WIN') === 0 ) { // SMTP, mandates RFC compliant line ending
$LE = '\r\n';
}
else {
$LE = PHP_EOL; // maintain backward compatibility for legacy Linux command line mailers
}

@Synchro
Copy link
Member

Synchro commented Feb 1, 2017

Thanks @ASchmidt1 - great analysis. I think it's PHP itself causing the problem I'm seeing. If I submit a pure CRLF-break message, mail() prepends some extra headers which use LF (I'm on macOS); postfix is adaptive and uses the format of the first break it encounters as being the break it uses for the rest of the message, which then doesn't match, and you end up with with a corrupt message. I've not got around to checking the PHP source to confirm precisely what it does, but otherwise your example code looks reasonable.

@Synchro
Copy link
Member

Synchro commented Feb 13, 2017

I've had a look in PHP's code and it does indeed use hard-coded \n literals in header line breaks in the mail function implementation, for example when it adds the X-PHP-Originating-Script header, and also when injecting To and Subject headers. This explains the mixed line breaks issue. I've not seen any conditional code that would suggest that it handles it differently on Windows, suggesting that platform detection is not necessary - in fact it may even be harmful.

I will make some changes to reflect this and we can see whether it fixes these issues.

@ASchmidt1
Copy link

Fixed by PHP (https://bugs.php.net/bug.php?id=74005) in February snapshot so that it's backward compatible with PHP 5.
The fix missed the 7.0.16 cut-off, but should be part of 7.0.17.

@ASchmidt1
Copy link

FWIW - if you are using PHP mail, then it would be prudent to follow the manual, which explicitly states that all additional headers should be passed with CRLF (but that a lone LF could be attempted if one has to work around a qmail quirk). With the latest bug fix, the normalizing of headers in PHP 7 mail() has been reinstanted the way it had done it in PHP 5.

@Synchro
Copy link
Member

Synchro commented Feb 13, 2017

Thanks. That is a real mess! From what I read in the code, if I pass in headers containing CRLF (as you suggest I do by following the docs), then it's guaranteed to break because it will inject headers containing LF, and postfix for example will produce the problem we're seeing in here already. sendmail will accept either LF or CRLF, but it must be consistent, and will make a mess of mixed-format breaks.

Are you saying that the code you posted previously will work though the forest of PHP versions that were affected by this?

@ASchmidt1
Copy link

Hi,

It might help to see this in the historical context, because it explains why this clash of two philosophies was not recognized initially/early on - leaving all of us today with two incompatible, legacy branches. As you know, on Linux \n is the operating system line end. Any command line tool that expects input will look for \n. Since the PHP mail() function was conceived as a front-end to a Linux command line tool (sendmail), it made sense to work with "\n".

When Windows hosting of PHP (and with that, the eventual hosting of PHP applications) became "a thing" PHP at some point recognized that there was no "standard" command line mailer and eventually started using the more convenient direct SMTP for the Win32 implementation.

Eventually, Anti-Spam/Anti-Virus efforts in the SMTP world caught up and started enforcing strict RFC compliance and suddenly lone LF headers under Windows (or qmail doubled up CRLFCR under Linux) caused emails to not be delivered to certain recipients ("my gmail users don't get my emails...")

At first, the answer for PHP seemed simple - stick to the RFCs and require CRLF. But then qmail failed because it translates each lone CR and each LF into CRLF. So the Linux site pointed out that mail() was never meant to be "SMTP" it was meant to be a sendmail frontend. (On top of that, people had abused the "additional_header" parameters to stuff entire nested MIME entities into it - so now they even contained data!)

Conclusion:

  • Keeping \n is necessary, because it will prevent breaking legacy Linux mailers that don't understand \r\n.
  • Conditionally using \r\n for SMTP will prevent delivery problems (specially under Windows, where \n was never a thing)

As far as my code snippet:

  • I can only speak to the Windows side of things with confidence, because that's where I have been patching various emailer code/components of various CMS for many years and through many PHP versions. Although I have hosted a Linux server here and there, I don't have a good testing platform.

@Synchro
Copy link
Member

Synchro commented Feb 13, 2017

I've just pushed some changes to attempt to address this - please give it a try.

There are lots of things touched by this - quoted-printable encoding (the PHP built-in function does not allow you to specify a line break format), and the DKIM functions are affected too, so it would be good to test those if you can.

@Synchro
Copy link
Member

Synchro commented Feb 17, 2017

Is this working for everyone? Anyone?

@arxeiss
Copy link
Author

arxeiss commented Feb 19, 2017

Hi,
I cannot test DKIM, but I tried to send email as I did before and it works in same clients perfectly without changes. So for regular sending I can say, it is fixed.
I did test for isMail() and isSMTP(), both works perfectly.

@ASchmidt1
Copy link

ASchmidt1 commented Feb 20, 2017

Hi, I pulled the phpmailer.php 6.0 labeled "Attempt solution to line break issue, see #953" from a few days ago, then I used WordPress 4.7.2 on Windows, added the WordPress Exception class, and then replaced their 5.x version with the new "class_phpmailer.php".

Using an unpatched PHP 7.1.2 on Windows 2012 R2 WordPress was able to use phpmailer to send messages to a the native Windows IIS SMTP server. However, the result were the following headers:

Subject: [develop] Please moderate: "Hello world!"\r\n
To: [email protected]\r\n
X-PHP-Originating-Script: 0:class-phpmailer.php\n
Date: Mon, 20 Feb 2017 17:23:05 +0000\r\n
From: WordPress <[email protected]>\r\n
Message-ID: <[email protected]>\r\n
X-Mailer: PHPMailer 6.0.0 (https://github.com/PHPMailer/PHPMailer)\r\n
MIME-Version: 1.0\r\n
Content-Type: text/plain; charset=UTF-8\r\n
Return-Path: [email protected]\r\n

The good news - nothing broke due to your changes. Basically, all the custom headers had proper CRLF endings, EXCEPT...
for the X-PHP-Originating header that is injected by the php mail() function based on the PHP.ini setting: mail.add_x_header = On.

THAT one has a lone \n, which will cause these emails to be bounced by RFC enforcing SMTP relays or servers. PHP has developed a fix for THAT bug which is scheduled to be included in the next 7.x updates.

@ASchmidt1
Copy link

I now retested with the today's PHP 7.1.3 snapshot which includes the fix for the X-PHP-Originating header. With that, all headers are sent with proper \r\n from Wordpress->phpmailer->mail()->SMTP under Windows:

Subject: [develop.anamera] Please moderate: "Hello world!"\r\n
To: [email protected]\r\n
X-PHP-Originating-Script: 0:class-phpmailer.php\r\n
Date: Mon, 20 Feb 2017 17:56:38 +0000\r\n
From: WordPress [email protected]\r\n
Message-ID: [email protected]\r\n
X-Mailer: PHPMailer 6.0.0 (https://github.com/PHPMailer/PHPMailer)\r\n
MIME-Version: 1.0\r\n
Content-Type: text/plain; charset=UTF-8\r\n
Return-Path: [email protected]\r\n

Therefore, it seems that under Windows, your new code results in proper mail headers from WordPress now, regardless if the (otherwise necessary) 7.x fix is in place - or not. Also, since the 7.x fix simply restores the (unintentionally omitted) header normalization that had been in place in 5.x, I feel comfortable that your code will also work with PHP 5.x (although I have NOT test that explicitly).

@Synchro
Copy link
Member

Synchro commented Feb 20, 2017

@ASchmidt1 Great, thanks for checking. So are there any versions of PHP that this will still be broken in?

@ASchmidt1
Copy link

The only problem I'm aware of is sites with 7.x before 7.0.17 and before 7.1.3. They will have to specify mail.add_x_header = 0 to circumvent the PHP 7 bug, if they configured a (most likely Windows) SMTP server that blocks or doesn't fix-up lone LF headers. But at least if they do that, then the "to" and "additional_headers" parameters that PHPmailer 6 passes to the mail() function will be able to go through now.

I'm not aware of any clashes with your updated PHPmailer 6 code and the mail() function of PHP 5.

Without your updated code, users of PHP 7x before 7.0.17 and before 7.1.3 would have to explicitly set $LE = '\r\n', which of course is a customization of "core" code that would be beyond the ability of most CMS end users.

@Synchro
Copy link
Member

Synchro commented Feb 21, 2017

Looking at the docs for mail.add_x_header, it says it defaults to 0, however, I've never looked at it before and it was enabled by default in my build, so I checked in the current PHP source and it is enabled by default in the stock php.ini files provided with PHP - so the documentation is wrong and as a consequence, unsafe. I've reported it as a PHP bug. I don't see any good reason to ever have that enabled in production (it's an unnecessary information leak), so I propose disabling it unconditionally, which will, conveniently, also avoid the line break bug in older PHP versions.

@Synchro
Copy link
Member

Synchro commented Feb 21, 2017

Grrr. mail.add_x_header is a PHP_INI_PERDIR setting, so can't be changed from scripts. Now contemplating a noisy error instead...

@ASchmidt1
Copy link

Yes, I had checked into the possibility to suppress this PHP setting for the affected 7.0/7.1 versions and came to the same conclusion. Frankly, now that a 7.x fix is out, at least it will be reasonable to advise folks to upgrade to the latest update for the current release.

My gut feeling is that by the time PHPmailer 6 will be widely adopted (where any noisy error could be seen) by the various CMS, many PHP 7.x installations may have already installed current/fixed updates. Also, listing the PHP bug among the issues "circumvented" with PHPmailer will further help affected installations "discover" the need to upgrade to the current update of their PHP 7.x version, when googling for their symptoms.

If it makes you feel any better: Keep in mind, that PHP bug had been able to linger for so long, because many MTAs will of course whitelist their own users (either by IP or with SMTP AUTH) - so the emails are always accepted. Many MTA might even fix up the headers as they are injecting their own Received headers before relaying it - thus also suppressing it. That's why it took me quite a bit to track this down, because of my two different Windows MTAs, only ONE brand kept the faulty headers intact so for the longest time, I never actually observed the lone line feed while trying to produce it until I tested with our secondary MTA.

@Synchro
Copy link
Member

Synchro commented Feb 28, 2017

I'm on macOS running PHP 7.1.2 (i.e. without the fix), mail.add_x_header is on and it's adding the X-PHP-Originating-Script with a \n break, and I'm receiving in a local postfix configured to save files to disk, and not to alter line breaks - and all looks good.

In this scenario, PHP_EOL is natively \n, which matches the hard-coded break PHP adds in that header, so using the conditional break setting we've got, the message turns up with all \n line breaks, as expected, and not broken. As far as I can see, the only time this will not match is if PHP_EOL is \r\n (i.e. on Windows) and thus the error will never occur on macOS or Linux. I don't think we ever established in all the posts above (at least since the suggestion to fall back to PHP_EOL) that the problem was specific to Windows clients, though with hindsight it may have been apparent!

Anyway, I've now added a noisy warning if this magical combination is true:

  • Sending using mail()
  • Running Windows
  • Running PHP 7.0.0 - 7.0.16 or 7.1.0 - 7.1.2
  • mail.add_x_header is enabled

Thoughts?

@ghost
Copy link

ghost commented Feb 28, 2017

Linux Mint (Ubuntu and Debian editions) (Laptop and Desktop) and PHP 7.1.2, using the PHP_EOL, I haven't seen any of the above issues.

@ASchmidt1
Copy link

One possible combination is someone who (maybe for historical reasons) is actually using a sendmail-like command line mailer on Windows rather than SMTP. Early adopters of PHP under Windows might have had to go that route.

In that case their INI would have:
SMTP =
smtp_port =
sendmail-path = x:\path\to\mailer.exe

Obviously the result would depend on each specific mailer program, however, since they all do expect a Windows file or pipe as input, it would be reasonable to assume that they all will expect \r\n, but may also have also been designed to fix-up lone \n. In which case, these would have never been effected by any of the back and forth and thus might not need to be "warned".

@Synchro
Copy link
Member

Synchro commented Feb 28, 2017

In that case they could use PHPMailer's alternative isSendmail() option, which would not trigger the warning, and does not use mail() at all, or disable mail.add_x_header . Can you think of a better alternative? We need to make it very clear to anyone using broken stuff that there's a problem that's not PHPMailer's fault!

@ASchmidt1
Copy link

Agreed, other than changing their code to isSendmail(), just disabling mail.add_x_header for those PHP versions is the most sensible temporary alternative if someone encounteres issues, until they can install their fixed PHP release.

@long76
Copy link

long76 commented Mar 16, 2017

PHP 7.1.3/7.0.17
Fixed bug #74005 (mail.add_x_header causes RFC-breaking lone line feed).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants