Bug Description
In SMTPServer::sendCommand(), any response code >= 400 from the previous command causes the next sendCommand() call to throw immediately:
if ($this->lastResponseCode >= 400) {
throw new SMTPException(...);
}
This is incorrect for RCPT TO commands. In SMTP, a 5xx response to RCPT TO is a per-recipient rejection — not a session failure. The client should continue sending RCPT TO for remaining recipients and only fail if all are rejected.
Steps to Reproduce
- Create an email with multiple recipients:
valid@example.com, invalid@example.com, also-valid@example.com
- The SMTP server rejects
invalid@example.com with 550 User not found
- The next
sendCommand() call (for also-valid@example.com) throws SMTPException without even being sent
Expected Behavior
- Rejected
RCPT TO addresses should be collected/logged but not abort the session
- Remaining recipients should still be attempted
DATA should proceed if at least one recipient was accepted
- Only throw if all recipients were rejected
QUIT should always be sent to cleanly close the connection
Actual Behavior
- First
RCPT TO rejection aborts the entire send
- Remaining valid recipients never receive the message
QUIT is never sent, leaving the TCP connection dangling until server timeout
- No way to know which recipients were accepted vs rejected
WebFiori Version
v2.1.1
PHP Version
8.1+
Operating System
Linux
Additional Context
Suggested approach — modify receiversCommandHelper() to handle rejections gracefully:
private function receiversCommandHelper($type): int {
$server = $this->getSMTPServer();
$accepted = 0;
foreach ($this->receiversArr[$type] as $address => $name) {
$server->sendCommand('RCPT TO: <' . $address . '>');
if ($server->getLastResponseCode() < 400) {
$accepted++;
}
// Log rejection but don't throw
}
return $accepted;
}
Then in send(), check total accepted count and throw only if zero.
This requires sendCommand() to not throw on the next call after a 4xx/5xx — the check should be contextual rather than blanket.
Bug Description
In
SMTPServer::sendCommand(), any response code >= 400 from the previous command causes the nextsendCommand()call to throw immediately:This is incorrect for
RCPT TOcommands. In SMTP, a 5xx response toRCPT TOis a per-recipient rejection — not a session failure. The client should continue sendingRCPT TOfor remaining recipients and only fail if all are rejected.Steps to Reproduce
valid@example.com,invalid@example.com,also-valid@example.cominvalid@example.comwith550 User not foundsendCommand()call (foralso-valid@example.com) throwsSMTPExceptionwithout even being sentExpected Behavior
RCPT TOaddresses should be collected/logged but not abort the sessionDATAshould proceed if at least one recipient was acceptedQUITshould always be sent to cleanly close the connectionActual Behavior
RCPT TOrejection aborts the entire sendQUITis never sent, leaving the TCP connection dangling until server timeoutWebFiori Version
v2.1.1
PHP Version
8.1+
Operating System
Linux
Additional Context
Suggested approach — modify
receiversCommandHelper()to handle rejections gracefully:Then in
send(), check total accepted count and throw only if zero.This requires
sendCommand()to not throw on the next call after a 4xx/5xx — the check should be contextual rather than blanket.