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

Bug: Can't Send Email Using SMTP #9448

Open
yllumi opened this issue Feb 12, 2025 · 13 comments
Open

Bug: Can't Send Email Using SMTP #9448

yllumi opened this issue Feb 12, 2025 · 13 comments

Comments

@yllumi
Copy link

yllumi commented Feb 12, 2025

PHP Version

8.3

CodeIgniter4 Version

4.6.0

CodeIgniter4 Installation Method

Composer (using codeigniter4/appstarter)

Which operating systems have you tested for this bug?

Linux

Which server did you use?

fpm-fcgi

Database

No response

What happened?

I've tried to setup email sender using CodeIgniter Email class. I use SMTP configuration with SMTPCrypto=tls, SMTPPort=587 and other auth configuration. Then it shows this debug message:

hello: 
The following SMTP error was encountered:
starttls: 
The following SMTP error was encountered:
Unable to send email using SMTP. Your server might not be configured to send mail using this method.
Date: Wed, 12 Feb 2025 17:35:25 +0700
To: [email protected]
Subject: =?UTF-8?Q?SMTP=20Email=20Testing?=
From: "Masagi" <[email protected]>
Return-Path: <[email protected]>
Reply-To: <[email protected]>
User-Agent: Tarbiyya
X-Sender: [email protected]
X-Mailer: Tarbiyya
X-Priority: 3 (Normal)
Message-ID: <[email protected]>
Mime-Version: 1.0


Content-Type: multipart/alternative; boundary="B_ALT_67ac796d34a404.14803652"

This is a multi-part message in MIME format.
Your email application may not support this format.

--B_ALT_67ac796d34a404.14803652
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This is sample body of email testing using SMTP.


--B_ALT_67ac796d34a404.14803652
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

This is sample body of email testing using SMTP.

--B_ALT_67ac796d34a404.14803652--

For comparison, I try to use PHPMailer package with same configuration I've set in Config\Email class and it sent the message successfully. I use SMTP account from Hostinger.

Steps to Reproduce

This is my sample code:

// CodeIgniter Email
$email = service("email");
$email->setTo("[email protected]");
$email->setSubject("SMTP Email Testing");
$email->setMessage("This is sample body of email testing using SMTP.");
$email->send(false);
echo $email->printDebugger();

// PHPMailer
$mail = new PHPMailer(true);
$EmailConfig = new \Config\Email;
try {
    $mail->SMTPDebug = SMTP::DEBUG_SERVER;
    $mail->isSMTP();
    $mail->Host       = $EmailConfig->SMTPHost;
    $mail->SMTPAuth   = true;
    $mail->Username   = $EmailConfig->SMTPUser;
    $mail->Password   = $EmailConfig->SMTPPass;
    $mail->SMTPSecure = $EmailConfig->SMTPCrypto; // 'tls'
    $mail->Port       = $EmailConfig->SMTPPort; // 587

    $mail->setFrom($EmailConfig->fromEmail, $EmailConfig->fromName);
    $mail->addAddress('[email protected]');
    $mail->isHTML(true);

    $mail->Subject = 'SMTP Email Testing';
    $mail->Body    = 'This is sample body of email testing using SMTP.';

    $mail->send();
    echo 'Message has been sent';
} catch (Exception $e) {
    echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}

Expected Output

I don't know if I missed something in my configuration or if there is an error in the Email class.

Anything else?

No response

@yllumi yllumi added the bug Verified issues on the current code behavior or pull requests that will fix them label Feb 12, 2025
@michalsn
Copy link
Member

I can't reproduce the problem using an email from Hostinger.

These are the only things changed in the email config.

email.fromEmail = 'hello@<private>'
email.fromName = 'This is me'
email.protocol = 'smtp'
email.SMTPHost = 'smtp.hostinger.com'
email.SMTPUser = 'hello@<private>'
email.SMTPPass = '<private>'
email.SMTPCrypto = 'tls'
email.SMTPPort = '587'
email.mailType = 'html'

The log:

220 ESMTP smtp.hostinger.com

hello: 250-smtp.hostinger.com
250-PIPELINING
250-SIZE 48811212
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 CHUNKING

starttls: 220 2.0.0 Ready to start TLS

hello: 250-smtp.hostinger.com
250-PIPELINING
250-SIZE 48811212
250-ETRN
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 CHUNKING

from: 250 2.1.0 Ok

to: 250 2.1.5 Ok

data: 354 End data with .

250 2.0.0 Ok: queued as 4YtnkF3L5YzF8gN4

quit: 221 2.0.0 Bye

Your message has been successfully sent using the following protocol: smtp

<here goes the message>

@michalsn
Copy link
Member

@yllumi Can you add something to help us reproduce the error? Without that, I'm afraid I'll have to close this issue.

@warcooft
Copy link
Contributor

i get the same problem, is there any special settings if the application running on a linux server?

@michalsn
Copy link
Member

@warcooft

i get the same problem, is there any special settings if the application running on a linux server?

I don't think so. Do you get the same error with this email provider or a different one? Can you provide any more details?

@ip-qi
Copy link

ip-qi commented Feb 21, 2025

@warcooft
....

I don't know if I missed something in my configuration or if there is an error in the Email class.

Anything else?

No response

Check if your mail server is using PLAIN or LOGIN SMTP Authentication method, this error could occur because if your mail server is using AUTH PLAIN (most likely) because CI4 by default is using AUTH LOGIN (a bit older authentication method) and as per my knowledge it is not possible to change the AUTH method simply and difference is:
AUTH LOGIN sends first username then password
AUTH PLAIN sends both username and password within single command

Because of that Email.php class needs adjustment within SMTPAuthenticate() function to handle LOGIN/PLAIN mechanism

Can you just replace within System\Email.php SMTPAuthenticate() function with this one and report back if email is sent now?

protected function SMTPAuthenticate() {
    if (!$this->SMTPAuth) {
        return true;
    }

    if ($this->SMTPUser === '' || $this->SMTPPass === '') {
        $this->setErrorMessage(lang('Email.noSMTPAuth'));
        return false;
    }

    // AUTH PLAIN format: base64_encode("\0username\0password")
    $authString = "\0" . $this->SMTPUser . "\0" . $this->SMTPPass;
    $authBase64 = base64_encode($authString);

    // send AUTH PLAIN command
    $this->sendData('AUTH PLAIN ' . $authBase64);
    $reply = $this->getSMTPData();

    // dbg output
    log_message('debug', 'SMTP AUTH response: ' . $reply);

    if (strpos($reply, '235') === 0) {
        if ($this->SMTPKeepAlive) {
            $this->SMTPAuth = false; // prevent re-authentication for keep-alive sessions
        }
        return true;
    }

    if (strpos($reply, '503') === 0) {
        return true; // already authenticated
    }

    // authentication fails
    $this->setErrorMessage('SMTP authentication failed: ' . $reply);
    return false;
}

@michalsn michalsn added the waiting for info Issues or pull requests that need further clarification from the author label Feb 21, 2025
@yllumi
Copy link
Author

yllumi commented Feb 22, 2025

@yllumi Can you add something to help us reproduce the error? Without that, I'm afraid I'll have to close this issue.

@michalsn this is my code

$email = service("email");
$email->setTo("[email protected]");
$email->setSubject("SMTP Email Testing");
$email->setMessage("This is sample body of email testing using SMTP.");
$email->send(false);
echo $email->printDebugger();

and this is my only configuration:

email.SMTPHost = 'smtp.hostinger.com'
email.protocol = 'smtp'
email.SMTPCrypto = 'tls'
email.SMTPPort = '587'
email.SMTPUser = '[email protected]'
email.SMTPPass = '<private>'
email.fromEmail  = '[email protected]'
email.fromName   = 'Masagi'
email.mailType = 'html'

I also tried in fresh install of CodeIgniter 4.6.0 and it is still showing same error.

@yllumi
Copy link
Author

yllumi commented Feb 22, 2025

Can you just replace within System\Email.php SMTPAuthenticate() function with this one and report back if email is sent now?

@ip-qi I've tried to change the content of SMTPAuthenticate() as you recommend and nothing happen, still shown same error. I've tried to debug and I thought the problem occured since calling SMTPConnect().

@ip-qi
Copy link

ip-qi commented Feb 22, 2025

Can you just replace within System\Email.php SMTPAuthenticate() function with this one and report back if email is sent now?

@ip-qi I've tried to change the content of SMTPAuthenticate() as you recommend and nothing happen, still shown same error. I've tried to debug and I thought the problem occured since calling SMTPConnect().

@yllumi I dont think your issue is related to my example code. I asked @warcooft to try it because i didnt know his email provider and his actual use case but this same issue i personally had due to the AUTH PLAIN method not being implemented in CI and code i provided is my personal current "fix" which let me send emails using SMTP PLAIN method. (didnt reported is as no one seems to use AUTH PLAIN method but i thought @warcooft might be having that kind of issue so i gave a "wild guess").

Since you are using Hostinger and Hostinger is using same AUTH LOGIN method as CodeIgniter too and since @michalsn tried and sent successfully email the issue is likely somewhere else in your case.

Have you tried using email client like Mozilla Thunderbird to receive and send emails? If you can add your email account and send/receive mails there is likely issue somewhere within your CI4 code. If Email client cant receive/send email it could be some misconfiguration on your email server side.. (not an expert in the field but just giving you few extra steps to try and find the cause)

@michalsn
Copy link
Member

michalsn commented Feb 22, 2025

@ip-qi OP was able to successfully send emails using PHPMailer.

@yllumi It looks like the SMTP timeout might be causing the issue. By default, SMTPTimeout is set to 5 seconds, which might not be enough, especially if the mail server takes longer to respond due to network latency or processing delays. Since you're operating from Indonesia, this could be a factor. Let's increase the timeout to 15 seconds and see how it goes.

// edit
I just checked and PHPMailer sets it to even more - 30 seconds.

@yllumi
Copy link
Author

yllumi commented Feb 23, 2025

@yllumi It looks like the SMTP timeout might be causing the issue. By default, SMTPTimeout is set to 5 seconds, which might not be enough, especially if the mail server takes longer to respond due to network latency or processing delays. Since you're operating from Indonesia, this could be a factor. Let's increase the timeout to 15 seconds and see how it goes.

// edit I just checked and PHPMailer sets it to even more - 30 seconds.

Aah, your guess was right @michalsn ! I set SMTP timeout to 30 seconds and finally CodeIgniter successfully sends SMTP email.
I think the default timeout value in Config/Email should be increased, and or message debug should be improved, such as recommending to increase the timeout value. I checked PHPMailer even has a default timeout value of 300 seconds or 5 minutes.

Interestingly, I tried changing the timeout in phpmailer to 5 seconds hardcoded and it still managed to send SMTP message. Whether this is because PHPMailer prioritizes the use of stream_socket_client before fsockopen to connect to an SMTP server, I don't know.

@michalsn
Copy link
Member

@yllumi I'm glad it worked for you.

I think the default timeout value in Config/Email should be increased, and or message debug should be improved, such as recommending to increase the timeout value.

IMO, the default timeout is okay, but we could benefit from improved timeout handling and debug messages for it. If you feel "the inner call" feel free to send improvements.

I checked PHPMailer even has a default timeout value of 300 seconds or 5 minutes.

Yes, you're right. I only looked at the method while SMTP class has a dedicated parameter for timeout.

Interestingly, I tried changing the timeout in phpmailer to 5 seconds hardcoded and it still managed to send SMTP message. Whether this is because PHPMailer prioritizes the use of stream_socket_client before fsockopen to connect to an SMTP server, I don't know.

From what I see, this is because PHPMailer sets stream_set_timeout every time before reading the response from the server. So, every SMTP command gets a fresh timeout when waiting for its corresponding response, while in CI we have to fit in with all commands in the given timeout.

@michalsn
Copy link
Member

@ip-qi If you prepare a PR with AUTH PLAIN, I think we will accept it without problems - however, you need to prepare a config option for it.

@michalsn michalsn removed bug Verified issues on the current code behavior or pull requests that will fix them waiting for info Issues or pull requests that need further clarification from the author labels Feb 23, 2025
@ip-qi
Copy link

ip-qi commented Feb 23, 2025

@ip-qi If you prepare a PR with AUTH PLAIN, I think we will accept it without problems - however, you need to prepare a config option for it.

Sure, i added
/**
* Which SMTP AUTH method to use ('LOGIN', 'PLAIN')
*
* @var string
*/
protected $SMTPAuthMethod = 'LOGIN'; <- which should not break anything as majority uses this method

And also i added in email.rst appropriate changes to reflect additional config parameter

Also PR is on the way

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

4 participants