generated from Nodarx/template
refactor: smtp client
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
@@ -644,7 +644,7 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
}
|
||||
|
||||
$this->initialize();
|
||||
$smtp = $this->remoteService->submitClient();
|
||||
$smtp = $this->remoteService->smtpClient();
|
||||
try {
|
||||
$queueId = $smtp->send(trim($sender->getAddress()), $recipients, $raw);
|
||||
} finally {
|
||||
|
||||
+23
-23
@@ -10,9 +10,9 @@ declare(strict_types=1);
|
||||
namespace KTXM\ProviderImap\Smtp;
|
||||
|
||||
use KTXM\ProviderImap\Smtp\Auth\AuthMechanism;
|
||||
use KTXM\ProviderImap\Smtp\Protocol\CommandWriter;
|
||||
use KTXM\ProviderImap\Smtp\Protocol\Reply;
|
||||
use KTXM\ProviderImap\Smtp\Protocol\ReplyReader;
|
||||
use KTXM\ProviderImap\Smtp\Protocol\ProtocolWriter;
|
||||
use KTXM\ProviderImap\Smtp\Protocol\Response\Response;
|
||||
use KTXM\ProviderImap\Smtp\Protocol\ProtocolReader;
|
||||
use KTXM\ProviderImap\Smtp\Transport\ConnectionFactoryInterface;
|
||||
use KTXM\ProviderImap\Smtp\Transport\ConnectionInterface;
|
||||
use KTXM\ProviderImap\Smtp\Transport\SocketConnectionFactory;
|
||||
@@ -30,8 +30,8 @@ use Psr\Log\LoggerInterface;
|
||||
final class Client
|
||||
{
|
||||
private ?ConnectionInterface $connection = null;
|
||||
private ?ReplyReader $reader = null;
|
||||
private ?CommandWriter $writer = null;
|
||||
private ?ProtocolReader $reader = null;
|
||||
private ?ProtocolWriter $writer = null;
|
||||
private ?ConnectionConfig $config = null;
|
||||
private ?SmtpCapabilities $capabilities = null;
|
||||
|
||||
@@ -47,8 +47,8 @@ final class Client
|
||||
|
||||
$this->connection = $connection;
|
||||
$this->config = $config;
|
||||
$this->reader = new ReplyReader($connection, $this->logger);
|
||||
$this->writer = new CommandWriter($connection, $this->logger);
|
||||
$this->reader = new ProtocolReader($connection, $this->logger);
|
||||
$this->writer = new ProtocolWriter($connection, $this->logger);
|
||||
|
||||
// Server greeting.
|
||||
$greeting = $this->reader()->read();
|
||||
@@ -101,17 +101,17 @@ final class Client
|
||||
}
|
||||
$mailFrom .= ' SIZE=' . $size;
|
||||
}
|
||||
$this->command($mailFrom, static fn (Reply $r): bool => $r->isPositiveCompletion(), 'MAIL FROM');
|
||||
$this->command($mailFrom, static fn (Response $r): bool => $r->isPositiveCompletion(), 'MAIL FROM');
|
||||
|
||||
foreach ($recipients as $recipient) {
|
||||
$this->command(
|
||||
sprintf('RCPT TO:<%s>', $recipient),
|
||||
static fn (Reply $r): bool => $r->isPositiveCompletion(),
|
||||
static fn (Response $r): bool => $r->isPositiveCompletion(),
|
||||
'RCPT TO',
|
||||
);
|
||||
}
|
||||
|
||||
$this->command('DATA', static fn (Reply $r): bool => $r->isPositiveIntermediate(), 'DATA');
|
||||
$this->command('DATA', static fn (Response $r): bool => $r->isPositiveIntermediate(), 'DATA');
|
||||
|
||||
$this->writer()->writeRaw($this->dotStuff($rawMessage) . "\r\n.\r\n");
|
||||
$reply = $this->reader()->read();
|
||||
@@ -161,7 +161,7 @@ final class Client
|
||||
throw new SmtpException('SMTP server does not advertise STARTTLS.');
|
||||
}
|
||||
|
||||
$this->command('STARTTLS', static fn (Reply $r): bool => $r->isPositiveCompletion(), 'STARTTLS');
|
||||
$this->command('STARTTLS', static fn (Response $r): bool => $r->isPositiveCompletion(), 'STARTTLS');
|
||||
$this->connection()->upgradeToTls();
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ final class Client
|
||||
{
|
||||
$this->command(
|
||||
'AUTH PLAIN ' . AuthMechanism::plainToken($username, $password),
|
||||
static fn (Reply $r): bool => $r->isPositiveCompletion(),
|
||||
static fn (Response $r): bool => $r->isPositiveCompletion(),
|
||||
'AUTH PLAIN',
|
||||
true,
|
||||
);
|
||||
@@ -193,27 +193,27 @@ final class Client
|
||||
|
||||
private function authLogin(string $username, string $password): void
|
||||
{
|
||||
$this->command('AUTH LOGIN', static fn (Reply $r): bool => $r->isPositiveIntermediate(), 'AUTH LOGIN');
|
||||
$this->command('AUTH LOGIN', static fn (Response $r): bool => $r->isPositiveIntermediate(), 'AUTH LOGIN');
|
||||
|
||||
$this->writer()->writeLine(base64_encode($username), true);
|
||||
$userReply = $this->reader()->read();
|
||||
if (!$userReply->isPositiveIntermediate()) {
|
||||
throw new SmtpException('SMTP AUTH LOGIN username rejected: ' . $userReply->text());
|
||||
$userResponse = $this->reader()->read();
|
||||
if (!$userResponse->isPositiveIntermediate()) {
|
||||
throw new SmtpException('SMTP AUTH LOGIN username rejected: ' . $userResponse->text());
|
||||
}
|
||||
|
||||
$this->writer()->writeLine(base64_encode($password), true);
|
||||
$passReply = $this->reader()->read();
|
||||
if (!$passReply->isPositiveCompletion()) {
|
||||
throw new SmtpException('SMTP authentication failed: ' . $passReply->text());
|
||||
$passResponse = $this->reader()->read();
|
||||
if (!$passResponse->isPositiveCompletion()) {
|
||||
throw new SmtpException('SMTP authentication failed: ' . $passResponse->text());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue a command line and assert the reply satisfies $accept.
|
||||
*
|
||||
* @param callable(Reply):bool $accept
|
||||
* @param callable(Response):bool $accept
|
||||
*/
|
||||
private function command(string $line, callable $accept, string $label, bool $sensitive = false): Reply
|
||||
private function command(string $line, callable $accept, string $label, bool $sensitive = false): Response
|
||||
{
|
||||
$this->writer()->writeLine($line, $sensitive);
|
||||
$reply = $this->reader()->read();
|
||||
@@ -242,12 +242,12 @@ final class Client
|
||||
return $this->connection ?? throw new SmtpException('SMTP client is not connected.');
|
||||
}
|
||||
|
||||
private function reader(): ReplyReader
|
||||
private function reader(): ProtocolReader
|
||||
{
|
||||
return $this->reader ?? throw new SmtpException('SMTP client is not connected.');
|
||||
}
|
||||
|
||||
private function writer(): CommandWriter
|
||||
private function writer(): ProtocolWriter
|
||||
{
|
||||
return $this->writer ?? throw new SmtpException('SMTP client is not connected.');
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace KTXM\ProviderImap\Smtp\Protocol;
|
||||
|
||||
use KTXM\ProviderImap\Smtp\Protocol\Response\Response;
|
||||
use KTXM\ProviderImap\Smtp\SmtpException;
|
||||
use KTXM\ProviderImap\Smtp\Transport\ConnectionInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
@@ -20,14 +21,14 @@ use Psr\Log\LoggerInterface;
|
||||
* ("250-text") to indicate continuation and a space ("250 text") on the final
|
||||
* line. See RFC 5321 §4.2.
|
||||
*/
|
||||
final class ReplyReader
|
||||
final class ProtocolReader
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ConnectionInterface $connection,
|
||||
private readonly ?LoggerInterface $logger = null,
|
||||
) {}
|
||||
|
||||
public function read(): Reply
|
||||
public function read(): Response
|
||||
{
|
||||
$lines = [];
|
||||
$raw = '';
|
||||
@@ -63,6 +64,6 @@ final class ReplyReader
|
||||
'raw' => rtrim($raw, "\r\n"),
|
||||
]);
|
||||
|
||||
return new Reply($code ?? 0, $lines, rtrim($raw, "\r\n"));
|
||||
return new Response($code ?? 0, $lines, rtrim($raw, "\r\n"));
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace KTXM\ProviderImap\Smtp\Protocol;
|
||||
use KTXM\ProviderImap\Smtp\Transport\ConnectionInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
final class CommandWriter
|
||||
final class ProtocolWriter
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ConnectionInterface $connection,
|
||||
@@ -7,12 +7,12 @@ declare(strict_types=1);
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace KTXM\ProviderImap\Smtp\Protocol;
|
||||
namespace KTXM\ProviderImap\Smtp\Protocol\Response;
|
||||
|
||||
/**
|
||||
* A parsed SMTP reply: a 3-digit status code plus one or more text lines.
|
||||
*/
|
||||
final class Reply
|
||||
final class Response
|
||||
{
|
||||
/**
|
||||
* @param int $code 3-digit SMTP status code
|
||||
@@ -9,7 +9,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace KTXM\ProviderImap\Smtp;
|
||||
|
||||
use KTXM\ProviderImap\Smtp\Protocol\Reply;
|
||||
use KTXM\ProviderImap\Smtp\Protocol\Response\Response;
|
||||
|
||||
/**
|
||||
* Parsed EHLO capabilities.
|
||||
@@ -27,7 +27,7 @@ final class SmtpCapabilities
|
||||
private readonly array $keywords,
|
||||
) {}
|
||||
|
||||
public static function fromEhlo(Reply $reply): self
|
||||
public static function fromEhlo(Response $reply): self
|
||||
{
|
||||
$keywords = [];
|
||||
$lines = $reply->lines();
|
||||
|
||||
Reference in New Issue
Block a user