@@ -279,6 +279,13 @@ class Email
279279 */
280280 protected $ SMTPAuth = false ;
281281
282+ /**
283+ * Which SMTP AUTH method to use ('LOGIN', 'PLAIN')
284+ *
285+ * @var string
286+ */
287+ protected $ SMTPAuthMethod = 'LOGIN ' ;
288+
282289 /**
283290 * Whether to send a Reply-To header
284291 *
@@ -1920,9 +1927,9 @@ protected function SMTPConnect()
19201927 $ this ->SMTPConnect ,
19211928 true ,
19221929 STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT
1923- | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
1924- | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
1925- | STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT,
1930+ | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
1931+ | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
1932+ | STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT,
19261933 );
19271934
19281935 if ($ crypto !== true ) {
@@ -2015,54 +2022,87 @@ protected function sendCommand($cmd, $data = '')
20152022 */
20162023 protected function SMTPAuthenticate ()
20172024 {
2018- if (! $ this ->SMTPAuth ) {
2025+ if (!$ this ->SMTPAuth ) {
20192026 return true ;
20202027 }
20212028
2022- if ($ this ->SMTPUser === '' && $ this ->SMTPPass === '' ) {
2029+ // If no username or password is set
2030+ if ($ this ->SMTPUser === '' || $ this ->SMTPPass === '' ) {
20232031 $ this ->setErrorMessage (lang ('Email.noSMTPAuth ' ));
2024-
20252032 return false ;
20262033 }
20272034
2028- $ this ->sendData ('AUTH LOGIN ' );
2029- $ reply = $ this ->getSMTPData ();
2035+ switch ($ this ->SMTPAuthMethod ) {
2036+ case 'LOGIN ' :
2037+ $ this ->sendData ('AUTH LOGIN ' ); // Start authentication
2038+ if (!$ this ->checkSMTPAuthResponse ($ this ->getSMTPData ())) {
2039+ return false ;
2040+ }
20302041
2031- if (str_starts_with ($ reply , '503 ' )) { // Already authenticated
2032- return true ;
2033- }
2042+ // Send encoded username
2043+ $ this ->sendData (base64_encode ($ this ->SMTPUser ));
2044+ if (!$ this ->checkSMTPAuthResponse ($ this ->getSMTPData ())) {
2045+ return false ;
2046+ }
20342047
2035- if (! str_starts_with ($ reply , '334 ' )) {
2036- $ this ->setErrorMessage (lang ('Email.failedSMTPLogin ' , [$ reply ]));
2048+ // Send encoded password
2049+ $ this ->sendData (base64_encode ($ this ->SMTPPass ));
2050+ $ reply = $ this ->getSMTPData ();
20372051
2038- return false ;
2039- }
2052+ // Authentication success (235 expected)
2053+ if (!str_starts_with ($ reply , '235 ' )) {
2054+ $ this ->setErrorMessage (lang ('Email.SMTPAuthPassword ' , [$ reply ]));
2055+ return false ;
2056+ }
2057+ break ;
2058+ case 'PLAIN ' :
2059+ // Generate single command for PLAIN authentication
2060+ $ authString = "\0" . $ this ->SMTPUser . "\0" . $ this ->SMTPPass ;
20402061
2041- $ this ->sendData (base64_encode ($ this ->SMTPUser ));
2042- $ reply = $ this ->getSMTPData ();
2062+ $ this ->sendData ('AUTH PLAIN ' . base64_encode ($ authString ));
20432063
2044- if (! str_starts_with ($ reply , '334 ' )) {
2045- $ this ->setErrorMessage (lang ('Email.SMTPAuthUsername ' , [$ reply ]));
2064+ if (!$ this ->checkSMTPAuthResponse ($ this ->getSMTPData ())) {
2065+ return false ;
2066+ }
20462067
2047- return false ;
2068+ break ;
2069+ default :
2070+ $ this ->setErrorMessage (lang ('Email.noSMTPAuthMethod ' ));
2071+ return false ;
2072+ break ;
20482073 }
20492074
2050- $ this ->sendData (base64_encode ($ this ->SMTPPass ));
2051- $ reply = $ this ->getSMTPData ();
2075+ if ($ this ->SMTPKeepAlive ) {
2076+ $ this ->SMTPAuth = false ; // Prevent re-authentication for keep-alive sessions
2077+ }
20522078
2053- if (! str_starts_with ( $ reply , ' 235 ' )) {
2054- $ this -> setErrorMessage ( lang ( ' Email.SMTPAuthPassword ' , [ $ reply ]));
2079+ return true ;
2080+ }
20552081
2082+
2083+ private function checkSMTPAuthResponse ($ replyData )
2084+ {
2085+ // 503 already authenticated || 235 authentication success ('AUTH PLAIN')
2086+ if (str_starts_with ($ replyData , '503 ' ) || str_starts_with ($ replyData , '235 ' )) {
2087+ return true ;
2088+ }
2089+
2090+ if (str_starts_with ($ replyData , '535 ' )) { // Authentication failed (bad credentials)
2091+ $ this ->setErrorMessage (lang ('Email.failedSMTPLogin ' , [$ replyData ]));
20562092 return false ;
20572093 }
20582094
2059- if ($ this -> SMTPKeepAlive ) {
2060- $ this -> SMTPAuth = false ;
2095+ if (str_starts_with ( $ replyData , ' 334 ' )) { // Server requesting username or password
2096+ return true ;
20612097 }
20622098
2063- return true ;
2099+ // Unexpected response
2100+ $ this ->setErrorMessage (lang ('Email.SMTPUnexpectedResponse ' , [$ replyData ]));
2101+ return false ;
20642102 }
20652103
2104+
2105+
20662106 /**
20672107 * @param string $data
20682108 *
0 commit comments