-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
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
SMTP::get_lines() timing out and returning empty string #1683
Comments
This nothing to do with get_lines. It’s the call to stream_select that’s failing, which suggests a problem with network or PHP config. |
@Synchro thanks for your prompt response. The code is in |
If you search on here for stream_select, you’ll find the reasons for the change in the original issue. |
I assume you are referring to #604. I have read this already. I added more debugging and noticed the following behavior:
Unfortunately, in the original code when stream_select() returns 0, an empty response for get_lines() is returned and everything fails afterwards. Kind of looks like the PHP bug referenced here, but that should be fixed as per bug. One of the notes in PHP documentation indicates that stream_select() shouldn't be called on blocking streams. So as I see why it was added, it seems to have introduced regression at least for some environments with healthy servers. The code was introduced to protect against unhealthy SMTP servers that never respond. |
There's discussion in #604 about the use of |
Unfortunately, there is no perfect solution here. You can either:
I suspect that with the same PHP environment and OS, it is likely that this won't work either since in my case EC2 -> AWS SES is as responsive as localhost, so not much benefit and likely to hit same bug. Also I think the benefit of using PHPMailer over mail() function is to be able to send to other servers. Also this enables the ability for the app to make the SMTP server configurable and less environment dependencies and settings. |
I had an absolutely same issue. It's randomly freeze on the following line: Sometimes it works, sometimes does not. Unfortunately this issue forced me to stop using SMTP-based PHPMailer and swith to default mail()-based functionality. Except only one website where mail() is intentionally disabled in "php.ini". I fixed this issue simply switching to Here is the code for
I guess that it's not the perfect solution, but it still works. I'm not sure why it ever requires that streams at all, because works with out streams with simple
Here is an output: 2019-05-26 18:45:53 SERVER -> CLIENT: 250-favor.com.ua Hello test.favor.com.ua [127.0.0.1] |
Changing back to the old code will simply return to the old and broken behaviour, which doesn't help anyone. |
The code of method get_lines in 6.1.2 have the stream_select call and seem to work well (CentOS 7 towards old Windows email server). However, maybe related to above issue, after receiving a short reply from server of 334 and line end (5 chars read), the info returned from stream_get_meta_data after the fgets indicate blocked=1 and unread_bytes=0. Instead of returning this short reply line, the while loop enter another stream_select call that eventually fail with timeout, THEN returning the previously read data. I added another case after the stream_get_meta_data checking for a complete line and no more to read, that seem to fix the long wait. Can't really say if this only applies to me or would improve things for others too...? The if-case just BEFORE the meta_data call checks for a space as fourth character (index 3) in a read chunk of data - I guess this case would apply to the "334\r\n" response if it also included \r as break character, which would be a shorter fix than mine:
|
That seems reasonable. The docs for fgets say that the line ending is included in the returned string, and that may mean that the tests for line length may not be correct. I wonder if it would be a good idea to switch to using stream_get_line instead, since that has more control over line breaks, and is apparently a little faster. Alternatively I wonder if it's worth applying an What I don't quite get is why it would fail to complete (i.e. break out of the loop) given an input string of
i.e. perhaps we should be checking The source refers to RFC5321 S 4.2, specifically:
One oddity there is that it says that senders should not send bare codes - but senders don't send codes at all, only receivers. RFC quirk I guess, unless they mean that receivers are the senders of codes, which is a little obtuse! |
I believe "the oddity" is my mail server replying with ONLY 334\r\n in 5 chars, i.e. NO space after the three status digits and nothing more to read on the socket - which cause a time out. Is 334\r\n a "bare code" that should be accepted? Perhaps not according to standard, but I fixed it with "both" the exit after line end AND a simpler check in the somewhat strange if(...$str[3]==" "...) - extended to break also on \r or \n in that position. |
Yes, that is indeed a bare code. Overall I'd say that the code in I don't think checking for a space as the 4th char is strange, since that's what the RFC says to look for, and nearly everything in there is looking at the beginnings of lines, not the ends. It would be very useful to have a reproducible test for this. |
Can you see if changing it to this works:
This should catch anything that's just a bare code because |
Fascinating that such a central core function as get_lines in the SMTP module where all data from the server pass through still cause problems/confusion (also involving bugs in PHP as I understand it).
into:
which I have in my running code now... |
Also: as fgets returns full lines, it's not possible to receive "250 OK" split into two halves. If the server was like when using telnet as SMTP client (i.e. telnet localhost 25 and typing along) the fgets would still return full lines and not individual characters, right? :-) |
Indeed, it's a rats nest in there! This particular issue is only triggered by non-compliant servers, but reality dictates that we need to deal with it! I slightly favour the I think the split scenario is indeed unlikely - though it's possible if we hit the length limit on |
Yeah 515 just like that surprised me too - define('SMTP_MAX_LINE_LENGTH', 515); and fgets(...SMTP_MAX_LINE_LENGTH); would be understandable (if that is what it is). |
I think we can simplify that if to:
We don't need to check I can't find any reference to 515 in RFC5321, but there is a 512-char limit on both commands and replies (which is what we're looking at here). This limit includes the trailing |
@ErikLtz any thoughts on this? |
Yes, nice and simple with minimal change. I currently run with:
and removed the previously added longer check for CRLF at end of string. Seems to work well :-) |
Hi. I found this thread and have read through it a couple of times. I am hoping that someone can give me an idea what to look at. I experience this even with the latest version of PHPMailer. However, I only experience it when I try am trying to connect to mail.domain.com (I can ping it) or if I put in the IP address. If I use domain.com it is fine. I am sure this is my lack of understanding of something....I just don't know what. I was hoping that someone here who knows more than I might be able to give me a hint. Cheers in advance. |
That sounds more like a TLS problem. Please open a new ticket with all your debug output as it doesn't sounds like you're having the issue described here. |
Thank you. I believe I have solved this. |
Problem description
getLines() times out and returns empty string.
Environment
PHP 7.0.33-0ubuntu0.16.04.2
PHPMailer 6.0.6
Using Amazon SES - older versions of PHPMailer 5.x works.
Linux mis2-us 4.4.0-1075-aws #85-Ubuntu SMP Thu Jan 17 17:15:12 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
Debug output
Code to reproduce
Here is the code that sends out the email via PHPMailer/SMTP:
https://github.com/mantisbt/mantisbt/blob/master/core/email_api.php#L1252
Cause Found
Removing the following block from the SMTP.php get_lines() function fixes the issue:
The text was updated successfully, but these errors were encountered: