Welcome Guest, Not a member yet? Register   Sign In
SMTP Email
#1

Hi,

I am having a problem using the CI4 built in email class.

I have stepped through in the debugger and get as far as 

PHP Code:
$this->sendCommand('starttls'); 

in the SMTPConnect function.

It then throws an error 

"fwrite(): send of 10 bytes failed with errno=32 Broken pipe"

It seems that the login is successful in terms of connecting to the host and it accepting my username and password.

Speaking with the hosting provider, they confirmed that SSL or TLS should work correctly. However, I have not been able to send email with either.

My sending code is very simple:

PHP Code:
    public function email_send()
    {
        
$email = \Config\Services::email();

        
$email->setFrom('[email protected]''Tester');
        
$email->setTo('[email protected]');


        
$email->setSubject('Email Test');
        
$email->setMessage('Testing the email class.');

        
$res $email->send(false);

        if (
$res)
        {
            echo 
'Email send was successful';
        }
        else
        {
            echo 
'Failed to send the email';
            
print_r($email->printDebugger());
        }

    } 
// end of method 

Obviously the email addresses are bogus, I changed them from real addresses.

The code doesn't get as far as the failed block on the return due to the exception mentioned above.

The config file is, stripped of comment, to make it shorter:


PHP Code:
    public $fromEmail;
    public 
$fromName;
    public 
$recipients;
    public 
$userAgent 'CodeIgniter';
    public 
$protocol 'smtp';
    public 
$mailPath '/usr/sbin/mhsendmail';
    public 
$SMTPHost 'host.co.uk';
    public 
$SMTPUser '******';
    public 
$SMTPPass '******';
    public 
$SMTPPort 465;
    public 
$SMTPTimeout 5;
     public 
$SMTPKeepAlive false;
    public 
$SMTPCrypto 'tls';
    public 
$wordWrap true;
    public 
$wrapChars 76;
    public 
$mailType 'text';
    public 
$charset 'UTF-8';
    public 
$validate false;
    public 
$priority 3;
    public 
$CRLF "\r\n";
    public 
$newline "\r\n";
    public 
$BCCBatchMode false;
    public 
$BCCBatchSize 200;
    public 
$DSN false

I am looking for any help on this process.

Yes, the sendmail path is from testing with MailHog on my Mac. And that works with the 'mail' protocol. It works from the server too. But it isn't a good long term solution. I would rather have the function of smtp.

Thanks.
Reply
#2

(This post was last modified: 07-30-2020, 12:47 PM by tgix.)

Just a thought - could the server still be using SSL? The email library seems to try to enable TLS (line 1880 in system/email/Email.php).
Just try changing that to another crypto type, for example STREAM_CRYPTO_METHOD_ANY_CLIENT, see https://www.php.net/manual/en/function.s...crypto.php

Or... investigating further: STREAM_CRYPTO_METHOD_TLS_CLIENT = TLS 1.0 only since PHP 5.6.7 it seems.
If the server is modern, then TLS 1.0 is probably not supported and 1.1 or 1.2 is required.
Reply
#3

(07-30-2020, 12:39 PM)tgix Wrote: Just a thought - could the server still be using SSL? The email library seems to try to enable TLS (line 1880 in system/email/Email.php).
Just try changing that to another crypto type, for example STREAM_CRYPTO_METHOD_ANY_CLIENT, see https://www.php.net/manual/en/function.s...crypto.php

Or... investigating further: STREAM_CRYPTO_METHOD_TLS_CLIENT = TLS 1.0 only since PHP 5.6.7 it seems.
If the server is modern, then TLS 1.0 is probably not supported and 1.1 or 1.2 is required.

I just queried the server with the SSL Labs tool. You might be on to something there, the server supports:
  • TLS 1.3
  • TLS 1.2
and no other versions of TLS.

It also supports the following:

# TLS 1.3 (server has no preference)
TLS_AES_128_GCM_SHA256 (0x1301)  ECDH x25519 (eq. 3072 bits RSA)  FS 128
TLS_AES_256_GCM_SHA384 (0x1302)  ECDH x25519 (eq. 3072 bits RSA)  FS 256
TLS_CHACHA20_POLY1305_SHA256 (0x1303)  ECDH x25519 (eq. 3072 bits RSA)  FS 256

# TLS 1.2 (suites in server-preferred order)
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)  ECDH x25519 (eq. 3072 bits RSA)  FS 128
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)  ECDH x25519 (eq. 3072 bits RSA)  FS  WEAK 128
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)  ECDH x25519 (eq. 3072 bits RSA)  FS  WEAK 256


Which is sort of interesting, but probably irrelevant.

According to the PHP manual stream_socket_enable_crypto should support TSL1.2 Client, which should be OK for this.
I am running PHP 7.3, but could bump to 7.4 without any problems on the code side.
Reply
#4

(This post was last modified: 07-30-2020, 09:28 PM by tgix.)

(07-30-2020, 01:26 PM)Chroma Wrote: According to the PHP manual stream_socket_enable_crypto should support TSL1.2 Client, which should be OK for this.
I am running PHP 7.3, but could bump to 7.4 without any problems on the code side.

OK. I would say that CI4 is enabling TLS in the wrong way since it only enables TLS 1.0 with the call to stream_socket_enable_crypto() and passing STREAM_CRYPTO_METHOD_TLS_CLIENT.

If you installed CI4 using composer, I suggest you edit one of the files inside CI4, namely: <project_root>/vendor/codeigniter4/framework/system/Email/Email.php and change line 1880:

PHP Code:
$crypto stream_socket_enable_crypto($this->SMTPConnecttrueSTREAM_CRYPTO_METHOD_TLS_CLIENT); 

Into something more compatible, such as:

Code:
$crypto = stream_socket_enable_crypto($this->SMTPConnect, true, STREAM_CRYPTO_METHOD_ANY_CLIENT);

or (only enabling TLS 1.2):
Code:
$crypto = stream_socket_enable_crypto($this->SMTPConnect, true, STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT);

Changing the framework files are not recommended since an upgrade will overwrite your changes, but will at least a) get you going and b) allow a change to framework for an upcoming version.

If you are not comfortable creating a pull request (PR), let me know if the connection with your server works after modifying the line and I can submit a PR with this change.
Reply
#5

(This post was last modified: 07-30-2020, 11:44 PM by Chroma.)

Hi tiger,

Thanks for the suggestion. I will give it a try this morning and see if that helps.

Smile

I have tried the change to use


This is what I get back from the printDebugger():

hello:
The following SMTP error was encountered:
Unable to send email using PHP SMTP. Your server might not be configured to send mail using this method.
Date: Fri, 31 Jul 2020 07:32:57 +0100
From: "Tester" <[email protected]>
Return-Path: < [email protected] >
To: xxxxxx
Subject: =?UTF-8?Q?Email=20Test?=
Reply-To: < [email protected] >
User-Agent: CodeIgniter
X-Sender: [email protected]
X-Mailer: CodeIgniter
X-Priority: 3 (Normal)
Message-ID: <[email protected] >
Mime-Version: 1.0


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

Testing the email class.


The error is still the same, it is failing on the STARTTLS line, I don't think that it is getting as far as the crypto line. I think that it is failing when the call from 1879 happens and it never gets to the stream_socket_enable_crypto line, as it fails on the line above. I just don't know what would cause it to fail there, when it was clearly talking to the server. My only thought is that the socket is closing after the helo for some reason.

This is what the exception looks like, without the coloured boxes.

Code:
( ! ) Fatal error: Uncaught ErrorException: fwrite(): send of 6 bytes failed with errno=32 Broken pipe in /Users/name/Sites/menai/core-sys/Email/Email.php on line 2019
( ! ) ErrorException: fwrite(): send of 6 bytes failed with errno=32 Broken pipe in /Users/name/Sites/menai/core-sys/Email/Email.php on line 2019
Call Stack
#    Time    Memory    Function    Location
1    33.4107    751352    CodeIgniter\Email\Email->__destruct( )    .../Email.php:0
2    33.4107    751352    CodeIgniter\Email\Email->sendCommand( ???, ??? )    .../Email.php:2139
3    33.4107    751352    CodeIgniter\Email\Email->sendData( ??? )    .../Email.php:1941
4    42.0435    751384    fwrite ( ???, ??? )    .../Email.php:2019
5    42.0435    752368    CodeIgniter\Debug\Exceptions->errorHandler( ???, ???, ???, ???, ??? )    .../Email.php:2019

Any thoughts?
Reply
#6

(This post was last modified: 07-31-2020, 01:07 AM by tgix.)

Hmmm... after testing with with my two providers authsmtp.com and Amazon Web Services SES I can see a can of worms opening.

I see you are using port 465. With Amazon SES I can use port 465 with SMTPCrypto set to 'ssl', but not with 'tls'.
Using port 587 I can connect using SMTPCrypto = 'tls'.

Complicating things further, I see that RFC8314 (section 3.3) specifies that the TLS handshake should start immediately and not wait for STARTTLS. So, as I understand it - if port 465 is used, 'ssl' should be specified to connect securely from the start and thus SMTPCrypto='ssl' is required. If using port 587, connection is initially made in cleartext and then STARTTLS is used to switch to securecd connect.

If you change SMTPCrypto to 'ssl' and keep port 465 does it work for you?
Alternatively: if you switch to port 587 (provided you ISP supports it) and keep 'tls' does it work for you?

Also, I see that Amazon SES doesn't allow using STARTTLS when connected to port 465. It replies with "454 TLS not supported". AuthSMTP accepts STARTTLS even on port 465 (suggested in the RFC for backward compatibility). Changing cipher mid-connection has proven to be a bad idea so I guess Amazon is extra cautious.
Reply
#7

Hi Tgix,

OK, with what you just wrote above, I now have send a test message and it seems to have worked.

It looks like I needed to use SSL on port 465.

I don't know why this worked today when I am sure I tested this earlier on before I started this thread. But, it is now working and we are all in good shape.

I am sorry about the delay in replying, but I was away on business and now just got back and had change to test.

Thanks for all your help and suggestions, it was instrumental in this working.
Reply
#8

Yeah, the standards says secure communication is required on 465. As the CI framework is written (including version 4.0.4), the correct setting was 'ssl' in these cases as the 'tls' setting wouldn't enable a secure channel on initial connect.

Based on our discussions I created a pull request for CI, so in the next version secure communication will be the default on port 465 - https://github.com/codeigniter4/CodeIgniter4/pull/3430 ('ssl' not required). The 'tls' setting should still be used on ports requiring STARTTLS (such as 587 or 25).
Reply
#9

Good idea and I hope that this thread and your fix helps other who get similarly stuck.

I gave you +1 reputation.

Smile
Reply




Theme © iAndrew 2016 - Forum software by © MyBB