diff --git a/src/Service/AbstractMailService.php b/src/Service/AbstractMailService.php index f57f4a9..471efa7 100644 --- a/src/Service/AbstractMailService.php +++ b/src/Service/AbstractMailService.php @@ -45,8 +45,10 @@ use Laminas\Mail\Message; use Laminas\Mime\Message as MimeMessage; use Laminas\Mime\Mime; +use Laminas\Mime\Part; use function in_array; +use function strpos; /** * Class AbstractMailService @@ -90,8 +92,8 @@ protected function extractText(Message $message): ?string private function extractTextFromMimeMessage(MimeMessage $message): ?string { foreach ($message->getParts() as $part) { - if ($part->type === 'text/plain' && $part->disposition !== Mime::DISPOSITION_ATTACHMENT) { - return $part->getContent(); + if ($this->isType($part, Mime::TYPE_TEXT)) { + return $part->getRawContent(); } } foreach ($message->getParts() as $part) { @@ -126,8 +128,8 @@ protected function extractHtml(Message $message): ?string private function extractHtmlFromMimeMessage(MimeMessage $message): ?string { foreach ($message->getParts() as $part) { - if ($part->type === 'text/html' && $part->disposition !== Mime::DISPOSITION_ATTACHMENT) { - return $part->getContent(); + if ($this->isType($part, Mime::TYPE_HTML)) { + return $part->getRawContent(); } } foreach ($message->getParts() as $part) { @@ -141,6 +143,11 @@ private function extractHtmlFromMimeMessage(MimeMessage $message): ?string return null; } + private function isType(Part $part, string $mimeType): bool + { + return strpos($part->type, $mimeType) === 0 && $part->disposition !== Mime::DISPOSITION_ATTACHMENT; + } + /** * Extract all attachments from a message * @@ -160,10 +167,9 @@ protected function extractAttachments(Message $message): array return []; } - $filter = ['text/plain', 'text/html']; $attachments = []; foreach ($body->getParts() as $part) { - if (!in_array($part->type, $filter) || $part->disposition === Mime::DISPOSITION_ATTACHMENT) { + if ($this->isAttachment($part)) { $attachments[] = $part; } } @@ -171,6 +177,17 @@ protected function extractAttachments(Message $message): array return $attachments; } + private function isAttachment(Part $part): bool + { + if (in_array($part->type, self::MULTIPART_TYPES)) { + return false; + } + if ($part->disposition === Mime::DISPOSITION_ATTACHMENT) { + return true; + } + return strpos($part->type, 'text/') !== 0; + } + /** * Get HTTP client * diff --git a/tests/SlmMailTest/Service/AbstractMailServiceTest.php b/tests/SlmMailTest/Service/AbstractMailServiceTest.php index b511272..0ee77b1 100644 --- a/tests/SlmMailTest/Service/AbstractMailServiceTest.php +++ b/tests/SlmMailTest/Service/AbstractMailServiceTest.php @@ -11,6 +11,10 @@ use SlmMail\Service\AbstractMailService; use PHPUnit\Framework\TestCase; +use function current; +use function str_repeat; +use function trim; + /** * @covers \SlmMail\Service\AbstractMailService */ @@ -56,13 +60,14 @@ public function testExtractTextFromEmptyBodyReturnsNull(): void public function testExtractTextFromTwoPartMessageReturnsString(): void { - $expected = 'Foo'; + $expected = trim(str_repeat('Foo ', 100)); $message = new Message(); $body = new MimeMessage(); $body->addPart(new Part('')); $body->addPart( (new Part($expected)) ->setType(Mime::TYPE_TEXT) + ->setEncoding(Mime::ENCODING_QUOTEDPRINTABLE) ); $message->setBody($body); @@ -87,7 +92,7 @@ public function testExtractTextFromTextAttachmentReturnsNull(): void public function testExtractTextFromMultipartMessageReturnsString(): void { - $expected = 'Foo'; + $expected = trim(str_repeat('Foo ', 100)); $message = new Message(); $body = new MimeMessage(); $contentPart = new MimeMessage(); @@ -95,6 +100,7 @@ public function testExtractTextFromMultipartMessageReturnsString(): void $contentPart->addPart( (new Part($expected)) ->setType(Mime::TYPE_TEXT) + ->setEncoding(Mime::ENCODING_QUOTEDPRINTABLE) ); $body->addPart( (new Part($contentPart->generateMessage())) @@ -126,13 +132,14 @@ public function testExtractHtmlFromEmptyBodyReturnsNull(): void public function testExtractHtmlFromTwoPartMessageReturnsString(): void { - $expected = 'Foo'; + $expected = trim(str_repeat('Foo ', 100)); $message = new Message(); $body = new MimeMessage(); $body->addPart(new Part('')); $body->addPart( (new Part($expected)) ->setType(Mime::TYPE_HTML) + ->setEncoding(Mime::ENCODING_QUOTEDPRINTABLE) ); $message->setBody($body); @@ -157,7 +164,7 @@ public function testExtractHtmlFromHtmlAttachmentReturnsNull(): void public function testExtractHtmlFromMultipartMessageReturnsString(): void { - $expected = 'Foo'; + $expected = trim(str_repeat('Foo ', 100)); $message = new Message(); $body = new MimeMessage(); $contentPart = new MimeMessage(); @@ -165,6 +172,7 @@ public function testExtractHtmlFromMultipartMessageReturnsString(): void $contentPart->addPart( (new Part($expected)) ->setType(Mime::TYPE_HTML) + ->setEncoding(Mime::ENCODING_QUOTEDPRINTABLE) ); $body->addPart( (new Part($contentPart->generateMessage())) @@ -176,4 +184,38 @@ public function testExtractHtmlFromMultipartMessageReturnsString(): void $this->service->send($message); self::assertSame($expected, trim($this->service->html)); } + + /** + * @dataProvider extractAttachmentProvider + */ + public function testExtractAttachment(string $mimeType, string $disposition, bool $expected): void + { + $message = new Message(); + $body = new MimeMessage(); + $attachment = (new Part('Foo')) + ->setType($mimeType) + ->setDisposition($disposition); + $body->addPart($attachment); + $message->setBody($body); + + $this->service->send($message); + if ($expected) { + $actual = current($this->service->attachments); + self::assertSame($attachment, $actual); + } else { + self::assertEmpty($this->service->attachments); + } + } + + public static function extractAttachmentProvider(): array + { + return [ + 'html' => [Mime::TYPE_HTML, '', false], + 'text' => [Mime::TYPE_TEXT, '', false], + 'xml' => [Mime::TYPE_XML, '', false], + 'multipart/alternative' => [Mime::MULTIPART_ALTERNATIVE, '', false], + 'xml attachment' => [Mime::TYPE_XML, Mime::DISPOSITION_ATTACHMENT, true], + 'pdf' => ['application/pdf', '', true], + ]; + } }