smtpd
smtpd copied to clipboard
Example code not working
How to reproduce:
php version
PHP 7.2.9-1+ubuntu16.04.1+deb.sury.org+1 (cli) (built: Aug 19 2018 07:16:12) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.2.9-1+ubuntu16.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies
packages
composer require phpmailer/phpmailer
composer require thefox/smtpd
composer require monolog/monolog
server.php
<?php
// Import PHPMailer classes into the global namespace
// These must be at the top of your script, not inside a function
use TheFox\Smtp\Server;
use TheFox\Smtp\Event;
use Zend\Mail\Message;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
//Load Composer's autoloader
require 'vendor/autoload.php';
// Generate certificate
$privkey = openssl_pkey_new();
$cert = openssl_csr_new([
'countryName' => 'UK',
'stateOrProvinceName' => 'Isle Of Wight',
'localityName' => 'Cowes',
'organizationName' => 'Open Sauce Systems',
'organizationalUnitName' => 'Dev',
'commonName' => '127.0.0.1',
'emailAddress' => '[email protected]',
], $privkey);
$cert = openssl_csr_sign($cert, null, $privkey, 365);
// Generate PEM file
$pem = [];
openssl_x509_export($cert, $pem[0]);
openssl_pkey_export($privkey, $pem[1]);
$pem = implode($pem);
// Save PEM file
$pemfile = 'server.pem';
file_put_contents($pemfile, $pem);
$listenOptions = [
'ssl' => [
'verify_peer' => false,
'local_cert' => $pemfile,
'allow_self_signed' => true,
],
];
// Create a Logger with Monolog.
$logger = new Logger('smtp_example');
$logger->pushHandler(new StreamHandler('php://stdout', Logger::DEBUG));
$server = new Server([
'ip' => '127.0.0.1',
'port' => 587,
'logger' => $logger,
]);
if(!$server->listen($listenOptions)) {
print 'Server could not listen.' . "\n";
exit(1);
}
$server->addEvent(new Event(Event::TRIGGER_NEW_MAIL, null, function(Event $event, string $from, array $rcpts, Message $mail) {
// Do Stuff
}));
$server->addEvent(new Event(Event::TRIGGER_AUTH_ATTEMPT, null, function($event, $type, $credentials): bool {
return true;
}));
$server->loop();
email.php
<?php
// Import PHPMailer classes into the global namespace
// These must be at the top of your script, not inside a function
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
//Load Composer's autoloader
require 'vendor/autoload.php';
$mail = new PHPMailer(true); // Passing `true` enables exceptions
try {
//Server settings
$mail->SMTPDebug = 2; // Enable verbose debug output
$mail->isSMTP(); // Set mailer to use SMTP
$mail->Host = 'localhost'; // Specify main and backup SMTP servers
$mail->SMTPAuth = false; // Enable SMTP authentication
// $mail->Username = '[email protected]'; // SMTP username
// $mail->Password = 'secret'; // SMTP password
$mail->SMTPSecure = 'tls'; // Enable TLS encryption, `ssl` also accepted
$mail->Port = 587; // TCP port to connect to
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);
//Recipients
$mail->setFrom('[email protected]', 'Mailer');
$mail->addAddress('[email protected]', 'Joe User'); // Add a recipient
$mail->addAddress('[email protected]'); // Name is optional
$mail->addReplyTo('[email protected]', 'Information');
$mail->addCC('[email protected]');
$mail->addBCC('[email protected]');
//Attachments
// $mail->addAttachment('/var/tmp/file.tar.gz'); // Add attachments
// $mail->addAttachment('/tmp/image.jpg', 'new.jpg'); // Optional name
//Content
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = 'Here is the subject';
$mail->Body = 'This is the HTML message body <b>in bold!</b>';
$mail->AltBody = 'This is the body in plain text for non-HTML mail clients';
$mail->send();
echo 'Message has been sent';
} catch (Exception $e) {
echo 'Message could not be sent. Mailer Error: ', $mail->ErrorInfo;
}
run server & send email:
sudo php server.php
php email.php
server.php output:
[2018-10-23 19:22:54] smtp_example.INFO: start [] []
[2018-10-23 19:22:54] smtp_example.INFO: ip = "127.0.0.1" [] []
[2018-10-23 19:22:54] smtp_example.INFO: port = "587" [] []
[2018-10-23 19:22:54] smtp_example.INFO: hostname = "localhost.localdomain" [] []
[2018-10-23 19:22:54] smtp_example.NOTICE: listen ok [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1 data send: "220 localhost.localdomain SMTP Service Ready" [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1 data send: "250-localhost.localdomain\n250-AUTH PLAIN LOGIN\n250-STARTTLS\n250 HELP" [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1 data send: "220 Ready to start TLS" [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
[2018-10-23 19:23:06] smtp_example.DEBUG: client 1: collect data [] []
... (repeats forever) ...
email.php output:
2018-10-24 00:23:06 SERVER -> CLIENT: 220 localhost.localdomain SMTP Service Ready
2018-10-24 00:23:06 CLIENT -> SERVER: EHLO tim-workstation
2018-10-24 00:23:06 SERVER -> CLIENT: 250-localhost.localdomain
250-AUTH PLAIN LOGIN
250-STARTTLS
250 HELP
2018-10-24 00:23:06 CLIENT -> SERVER: STARTTLS
2018-10-24 00:23:06 SERVER -> CLIENT: 220 Ready to start TLS
2018-10-24 00:23:06 CLIENT -> SERVER: EHLO tim-workstation
2018-10-24 00:23:08 SERVER -> CLIENT:
2018-10-24 00:23:08 SMTP ERROR: EHLO command failed:
2018-10-24 00:23:08 SMTP NOTICE: EOF caught while checking if connected
The server does not appear to be receiving the "EHLO tim-workstation" command that is being sent by PHPMailer and so it just continually spins with no received data. Are you able to reproduce this? Do you know why this might be happening? Your library appears to be using a custom networking library and I'm not familiar enough with the low-level networking functions to debug effectively. If you could point me in the right direction I could probably write up a fix.
Having the same problem, and I've narrowed it down a bit. If I turn off TLS on the sending side, the server works as expected. Not sure where to go from here to debug further, though...
Hi, I'm sorry for this. I have to debug the code line-by-line. Maybe rewriting the example from scratch with a better approach.
Creating the certificate in the example code is not a good idea. This script should not focus on creating an SSL certificate, rather on handling the SMTP server.
Nothing to be sorry for! Bugs are part of the process (assuming it even is a bug). If it helps, the stream_socket_enable_crypto call at StreamSocket.php:170 does not return an error or warning, but once it has been called the stream_socket_recvfrom call at line 135 starts returning FALSE. Of course this should be returning a string, but even worse is that the dataRecv method of the Client class does not know what to do with a FALSE response, so it keeps looping and looping.
More info, in case it may help: I removed the self-signed certificate and purchased a real one. The problem still exists, so I don't believe the self-signing is the issue (but of course I may have screwed up the certificate somehow). If there's anything else I can do to help track this down, please let me know.
Technically there is no different between a self-signed certificate and a purchased real one.
Indeed; I interpreted the second line of your original response to indicate you thought the certificate creation in the example code may be a problem, so I tried to verify that it is not. If I misinterpreted your comment, I apologize.
Ah, I see. This was a miscommunication.
I meant that the example script and this project should not focus on creating certificates at all. Only take the path to an existing certificate. I'll remove the example in the next version and create an extra examples directory with different example files.
Gotcha. Note, though, that this issue definitely seems to be irrespective of the example code. Any attempt I've made to use the SMTP server with TLS is failing in the manner described above.
Testing with OpenSSL command line doesn't give me any hints, but perhaps you will understand the attached log better.
Progress, maybe. At least some information, if not a fix. Replace stream_socket_recvfrom and stream_socket_sendto with fread and fwrite, respectively, and it works.
@jonevance @zookatron Are you on master, or a specific version?
0.3
That's really old. We are already at 0.7.
Sorry about that. Your README.md instructs to install via:
composer.phar require "thefox/smtpd=~0.3"
I've upgraded to 0.7 and the problem persists, and is still "fixable" by swapping the recv and send with fread and fwrite.
Hi all,
@TheFox I've tried several different versions of the library and they all appear to have the same bug for me, including version 0.7.
@jonevance Your "replace stream_socket_recvfrom and stream_socket_sendto with fread and fwrite" fix is working perfectly for me, thanks, that is a huge help! @TheFox Any chance we could get this fix merged into master? Would it help to create a PR?
Prefer to have the stream functions work, of course, but I've tried everything; the problem really seems to be in the underlying system.
@TheFox Same happens here with the current master.
[2019-04-10 15:22:33] smtp_example.DEBUG: client 1: collect data [] []
[2019-04-10 15:22:33] smtp_example.DEBUG: client 1: collect data [] []
[2019-04-10 15:22:33] smtp_example.DEBUG: client 1: collect data [] []
[2019-04-10 15:22:33] smtp_example.DEBUG: client 1: collect data [] []
$ php -v
PHP 7.2.14 (cli) (built: Jan 31 2019 00:51:06) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
I ran into the same issue and can confirm that https://github.com/TheFox/network/pull/1 from @aaronschmied fixes it