2323 *
2424 * Permits email to be sent using Mail, Sendmail, or SMTP.
2525 *
26- * @see \CodeIgniter\Email\ EmailTest
26+ * @see EmailTest
2727 */
2828class Email
2929{
@@ -279,6 +279,13 @@ class Email
279279 */
280280 protected $ SMTPAuth = false ;
281281
282+ /**
283+ * Which SMTP atuh method to use ('LOGIN', 'PLAIN')
284+ *
285+ * @var bool
286+ */
287+ protected $ SMTPAuthMethod = 'LOGIN ' ;
288+
282289 /**
283290 * Whether to send a Reply-To header
284291 *
@@ -1080,10 +1087,8 @@ public function wordWrap($str, $charlim = null)
10801087
10811088 /**
10821089 * Build final headers
1083- *
1084- * @return void
10851090 */
1086- protected function buildHeaders ()
1091+ protected function buildHeaders (): void
10871092 {
10881093 $ this ->setHeader ('User-Agent ' , $ this ->userAgent );
10891094 $ this ->setHeader ('X-Sender ' , $ this ->cleanEmail ($ this ->headers ['From ' ]));
@@ -1095,10 +1100,8 @@ protected function buildHeaders()
10951100
10961101 /**
10971102 * Write Headers as a string
1098- *
1099- * @return void
11001103 */
1101- protected function writeHeaders ()
1104+ protected function writeHeaders (): void
11021105 {
11031106 if ($ this ->protocol === 'mail ' && isset ($ this ->headers ['Subject ' ])) {
11041107 $ this ->subject = $ this ->headers ['Subject ' ];
@@ -1123,10 +1126,8 @@ protected function writeHeaders()
11231126
11241127 /**
11251128 * Build Final Body and attachments
1126- *
1127- * @return void
11281129 */
1129- protected function buildMessage ()
1130+ protected function buildMessage (): void
11301131 {
11311132 if ($ this ->wordWrap === true && $ this ->mailType !== 'html ' ) {
11321133 $ this ->body = $ this ->wordWrap ($ this ->body );
@@ -1287,10 +1288,8 @@ protected function attachmentsHaveMultipart($type)
12871288 * @param string $body Message body to append to
12881289 * @param string $boundary Multipart boundary
12891290 * @param string|null $multipart When provided, only attachments of this type will be processed
1290- *
1291- * @return void
12921291 */
1293- protected function appendAttachments (&$ body , $ boundary , $ multipart = null )
1292+ protected function appendAttachments (&$ body , $ boundary , $ multipart = null ): void
12941293 {
12951294 foreach ($ this ->attachments as $ attachment ) {
12961295 if (isset ($ multipart ) && $ attachment ['multipart ' ] !== $ multipart ) {
@@ -1605,10 +1604,8 @@ public function send($autoClear = true)
16051604
16061605 /**
16071606 * Batch Bcc Send. Sends groups of BCCs in batches
1608- *
1609- * @return void
16101607 */
1611- public function batchBCCSend ()
1608+ public function batchBCCSend (): void
16121609 {
16131610 $ float = $ this ->BCCBatchSize - 1 ;
16141611 $ set = '' ;
@@ -1651,10 +1648,8 @@ public function batchBCCSend()
16511648
16521649 /**
16531650 * Unwrap special elements
1654- *
1655- * @return void
16561651 */
1657- protected function unwrapSpecials ()
1652+ protected function unwrapSpecials (): void
16581653 {
16591654 $ this ->finalBody = preg_replace_callback (
16601655 '/\{unwrap\}(.*?)\{\/unwrap\}/si ' ,
@@ -1867,10 +1862,8 @@ protected function sendWithSmtp()
18671862
18681863 /**
18691864 * Shortcut to send RSET or QUIT depending on keep-alive
1870- *
1871- * @return void
18721865 */
1873- protected function SMTPEnd ()
1866+ protected function SMTPEnd (): void
18741867 {
18751868 $ this ->sendCommand ($ this ->SMTPKeepAlive ? 'reset ' : 'quit ' );
18761869 }
@@ -1920,9 +1913,9 @@ protected function SMTPConnect()
19201913 $ this ->SMTPConnect ,
19211914 true ,
19221915 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,
1916+ | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
1917+ | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
1918+ | STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT,
19261919 );
19271920
19281921 if ($ crypto !== true ) {
@@ -2019,45 +2012,73 @@ protected function SMTPAuthenticate()
20192012 return true ;
20202013 }
20212014
2022- if ($ this ->SMTPUser === '' && $ this ->SMTPPass === '' ) {
2015+ // If no username or password is set
2016+ if ($ this ->SMTPUser === '' || $ this ->SMTPPass === '' ) {
20232017 $ this ->setErrorMessage (lang ('Email.noSMTPAuth ' ));
20242018
20252019 return false ;
20262020 }
20272021
2028- $ this ->sendData ('AUTH LOGIN ' );
2029- $ reply = $ this ->getSMTPData ();
2022+ switch ($ this ->SMTPAuthMethod ) {
2023+ case 'LOGIN ' :
2024+ $ this ->sendData ('AUTH LOGIN ' );
2025+ $ reply = $ this ->getSMTPData ();
20302026
2031- if (str_starts_with ($ reply , '503 ' )) { // Already authenticated
2032- return true ;
2033- }
2027+ if (str_starts_with ($ reply , '503 ' )) { // Already authenticated
2028+ return true ;
2029+ }
20342030
2035- if (! str_starts_with ($ reply , '334 ' )) {
2036- $ this ->setErrorMessage (lang ('Email.failedSMTPLogin ' , [$ reply ]));
2031+ if (! str_starts_with ($ reply , '334 ' )) {
2032+ $ this ->setErrorMessage (lang ('Email.failedSMTPLogin ' , [$ reply ]));
20372033
2038- return false ;
2039- }
2034+ return false ;
2035+ }
20402036
2041- $ this ->sendData (base64_encode ($ this ->SMTPUser ));
2042- $ reply = $ this ->getSMTPData ();
2037+ $ this ->sendData (base64_encode ($ this ->SMTPUser ));
2038+ $ reply = $ this ->getSMTPData ();
20432039
2044- if (! str_starts_with ($ reply , '334 ' )) {
2045- $ this ->setErrorMessage (lang ('Email.SMTPAuthUsername ' , [$ reply ]));
2040+ if (! str_starts_with ($ reply , '334 ' )) {
2041+ $ this ->setErrorMessage (lang ('Email.SMTPAuthUsername ' , [$ reply ]));
20462042
2047- return false ;
2048- }
2043+ return false ;
2044+ }
20492045
2050- $ this ->sendData (base64_encode ($ this ->SMTPPass ));
2051- $ reply = $ this ->getSMTPData ();
2046+ $ this ->sendData (base64_encode ($ this ->SMTPPass ));
2047+ $ reply = $ this ->getSMTPData ();
20522048
2053- if (! str_starts_with ($ reply , '235 ' )) {
2054- $ this ->setErrorMessage (lang ('Email.SMTPAuthPassword ' , [$ reply ]));
2049+ if (! str_starts_with ($ reply , '235 ' )) {
2050+ $ this ->setErrorMessage (lang ('Email.SMTPAuthPassword ' , [$ reply ]));
20552051
2056- return false ;
2052+ return false ;
2053+ }
2054+ break ;
2055+
2056+ case 'PLAIN ' :
2057+ // Generate single command for PLAIN authentication
2058+ $ authString = "\0" . $ this ->SMTPUser . "\0" . $ this ->SMTPPass ;
2059+
2060+ $ this ->sendData ('AUTH PLAIN ' . base64_encode ($ authString ));
2061+
2062+ if (str_starts_with ($ this ->getSMTPData (), '503 ' )) { // Already authenticated
2063+ return true ;
2064+ }
2065+
2066+ if (! str_starts_with ($ this ->getSMTPData (), '235 ' )) {
2067+ $ this ->setErrorMessage (lang ('Email.failedSMTPLogin ' , [$ this ->getSMTPData ()]));
2068+
2069+ return false ;
2070+ }
2071+
2072+ break ;
2073+
2074+ default :
2075+ $ this ->setErrorMessage (lang ('Email.noSMTPAuthMethod ' ));
2076+
2077+ return false ;
20572078 }
20582079
20592080 if ($ this ->SMTPKeepAlive ) {
2060- $ this ->SMTPAuth = false ;
2081+ $ this ->SMTPAuth = false ; // Prevent re-authentication for keep-alive sessions
20612082 }
20622083
20632084 return true ;
@@ -2192,10 +2213,8 @@ private function printDebuggerRaw(): string
21922213
21932214 /**
21942215 * @param string $msg
2195- *
2196- * @return void
21972216 */
2198- protected function setErrorMessage ($ msg )
2217+ protected function setErrorMessage ($ msg ): void
21992218 {
22002219 $ this ->debugMessage [] = $ msg . '<br> ' ;
22012220 $ this ->debugMessageRaw [] = $ msg ;
0 commit comments