From 6a6de040615ce2310968b6b6230103ce53b58a41 Mon Sep 17 00:00:00 2001 From: Nico Hoffmann Date: Sat, 24 Aug 2024 17:34:53 +0200 Subject: [PATCH] `Email\Transport` class --- src/Email/Email.php | 21 ++----- src/Email/PHPMailer.php | 32 +++-------- src/Email/Transport.php | 104 ++++++++++++++++++++++++++++++++++ tests/Email/EmailTest.php | 24 +++++++- tests/Email/PHPMailerTest.php | 2 +- 5 files changed, 138 insertions(+), 45 deletions(-) create mode 100644 src/Email/Transport.php diff --git a/src/Email/Email.php b/src/Email/Email.php index 36f1b95849..0980966646 100644 --- a/src/Email/Email.php +++ b/src/Email/Email.php @@ -41,7 +41,7 @@ class Email protected Address|null $replyTo = null; protected string $subject; protected array $to; - protected array|null $transport; + protected Transport $transport; /** * Email constructor @@ -58,7 +58,6 @@ public function __construct(array $props = [], bool $debug = false) $props['body'] = ['text' => $props['body']]; } - $this->attachments = Attachment::factory($props['attachments'] ?? []); $this->bcc = Address::factory($props['bcc'] ?? [], multiple: true); $this->beforeSend = $props['beforeSend'] ?? null; @@ -67,7 +66,7 @@ public function __construct(array $props = [], bool $debug = false) $this->from = Address::factory([$props['from'] => $props['fromName'] ?? null]); $this->subject = $props['subject']; $this->to = Address::factory($props['to'], multiple: true); - $this->transport = $props['transport'] ?? null; + $this->transport = new Transport(...$props['transport'] ?? []); if ($replyTo = $props['replyTo'] ?? null) { $this->replyTo = Address::factory([$replyTo => $props['replyToName'] ?? null]); @@ -126,16 +125,6 @@ public function cc(): array return Address::resolve($this->cc); } - /** - * Returns default transport settings - */ - protected function defaultTransport(): array - { - return [ - 'type' => 'mail' - ]; - } - /** * Returns the "from" email address */ @@ -211,9 +200,9 @@ public function to(): array /** * Returns the email transports settings */ - public function transport(): array + public function transport(): Transport { - return $this->transport ?? $this->defaultTransport(); + return $this->transport; } /** @@ -235,7 +224,7 @@ public function toArray(): array 'replyToName' => $this->replyToName(), 'subject' => $this->subject(), 'to' => $this->to(), - 'transport' => $this->transport() + 'transport' => $this->transport()->toArray() ]; } } diff --git a/src/Email/PHPMailer.php b/src/Email/PHPMailer.php index ee84a40405..762bb03009 100644 --- a/src/Email/PHPMailer.php +++ b/src/Email/PHPMailer.php @@ -64,32 +64,14 @@ public function send(bool $debug = false): bool } // smtp transport settings - if (($this->transport()['type'] ?? 'mail') === 'smtp') { + if ($this->transport()->type() === 'smtp') { $mailer->isSMTP(); - $mailer->Host = $this->transport()['host'] ?? null; - $mailer->SMTPAuth = $this->transport()['auth'] ?? false; - $mailer->Username = $this->transport()['username'] ?? null; - $mailer->Password = $this->transport()['password'] ?? null; - $mailer->SMTPSecure = $this->transport()['security'] ?? 'ssl'; - $mailer->Port = $this->transport()['port'] ?? null; - - if ($mailer->SMTPSecure === true) { - switch ($mailer->Port) { - case null: - case 587: - $mailer->SMTPSecure = 'tls'; - $mailer->Port = 587; - break; - case 465: - $mailer->SMTPSecure = 'ssl'; - break; - default: - throw new InvalidArgumentException( - 'Could not automatically detect the "security" protocol from the ' . - '"port" option, please set it explicitly to "tls" or "ssl".' - ); - } - } + $mailer->Host = $this->transport()->host(); + $mailer->SMTPAuth = $this->transport()->auth(); + $mailer->Username = $this->transport()->username(); + $mailer->Password = $this->transport()->password(); + $mailer->SMTPSecure = $this->transport()->security(); + $mailer->Port = $this->transport()->port(); } // accessible phpMailer instance diff --git a/src/Email/Transport.php b/src/Email/Transport.php new file mode 100644 index 0000000000..679a1d8da8 --- /dev/null +++ b/src/Email/Transport.php @@ -0,0 +1,104 @@ + + * @link https://getkirby.com + * @copyright Bastian Allgeier + * @license https://opensource.org/licenses/MIT + * @since 5.0.0 + */ +class Transport +{ + public function __construct( + public string $type = 'mail', + public string|null $host = null, + public int|null $port = null, + public string|bool $security = 'ssl', + public bool $auth = false, + #[SensitiveParameter] + public string|null $username = null, + #[SensitiveParameter] + public string|null $password = null, + ) { + } + + public function auth(): bool + { + return $this->auth; + } + + public function host(): string|null + { + return $this->host; + } + + public function password(): string|null + { + return $this->password; + } + + public function port(): int|null + { + if ($this->type() === 'mail') { + return null; + } + + // fallback to match security option + return $this->port ?? match ($this->security()) { + 'tls' => 587, + 'ssl' => 465, + default => null + }; + } + + public function security(): string|null + { + if ($this->type() === 'mail') { + return null; + } + + // automatic mode: try to set based on port + if ($this->security === true) { + return match ($this->port) { + null, 587 => 'tls', + 465 => 'ssl', + default => throw new InvalidArgumentException( + 'Could not automatically detect the "security" protocol from the "port" option, please set it explicitly to "tls" or "ssl".' + ) + }; + } + + return $this->security; + } + + public function toArray(): array + { + return array_filter([ + 'type' => $this->type(), + 'host' => $this->host(), + 'port' => $this->port(), + 'security' => $this->security(), + 'auth' => $this->auth(), + 'username' => $this->username(), + 'password' => $this->password(), + ]); + } + + public function type(): string + { + return $this->type; + } + + public function username(): string|null + { + return $this->username; + } +} diff --git a/tests/Email/EmailTest.php b/tests/Email/EmailTest.php index 9019f66fca..27aeb8ea07 100644 --- a/tests/Email/EmailTest.php +++ b/tests/Email/EmailTest.php @@ -49,7 +49,7 @@ public function testProperties() $this->assertSame('', $email->body()->html()); $this->assertFalse($email->isHtml()); - $this->assertSame(['type' => 'mail'], $email->transport()); + $this->assertSame('mail', $email->transport()->type()); } public function testToArray() @@ -202,7 +202,16 @@ public function testBeforeSend() $mailer = new Mailer(); - $this->assertSame($transport, $mail->transport()); + $this->assertSame([ + 'type' => 'smtp', + 'host' => 'mail.getkirby.com', + 'port' => 465, + 'security' => 'ssl', + 'auth' => true, + 'username' => 'test@test.com', + 'password' => 'randomString', + ], $mail->transport()->toArray()); + $this->assertSame($mail->beforeSend(), $beforeSend); $this->assertInstanceOf('Closure', $mail->beforeSend()); @@ -224,7 +233,16 @@ public function testBeforeSend() $mailer = new Mailer(); - $this->assertSame($transport, $mail->transport()); + $this->assertSame([ + 'type' => 'smtp', + 'host' => 'mail.getkirby.com', + 'port' => 465, + 'security' => 'ssl', + 'auth' => true, + 'username' => 'test@test.com', + 'password' => 'randomString', + ], $mail->transport()->toArray()); + $this->assertSame($mail->beforeSend(), $beforeSend); $this->assertInstanceOf('Closure', $mail->beforeSend()); diff --git a/tests/Email/PHPMailerTest.php b/tests/Email/PHPMailerTest.php index a3bfbbb64f..3a83aa38e6 100644 --- a/tests/Email/PHPMailerTest.php +++ b/tests/Email/PHPMailerTest.php @@ -129,7 +129,7 @@ public function testSMTPTransportDefaults() $phpunit->assertNull($mailer->Username); $phpunit->assertNull($mailer->Password); $phpunit->assertSame('ssl', $mailer->SMTPSecure); - $phpunit->assertNull($mailer->Port); + $phpunit->assertSame(465, $mailer->Port); $beforeSend = true; }