Skip to content

Commit

Permalink
Added ability to extract text and html from multipart messages
Browse files Browse the repository at this point in the history
  • Loading branch information
matt committed Nov 16, 2023
1 parent bbeb128 commit 2df9632
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 2 deletions.
38 changes: 36 additions & 2 deletions src/Service/AbstractMailService.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,21 @@
use Laminas\Mime\Message as MimeMessage;
use Laminas\Mime\Mime;

use function in_array;

/**
* Class AbstractMailService
*/
abstract class AbstractMailService implements MailServiceInterface
{
private const MULTIPART_TYPES = [
Mime::MULTIPART_ALTERNATIVE,
Mime::MULTIPART_MIXED,
Mime::MULTIPART_RELATED,
Mime::MULTIPART_RELATIVE,
Mime::MULTIPART_REPORT,
];

/**
* @var HttpClient
*/
Expand All @@ -74,11 +84,23 @@ protected function extractText(Message $message): ?string
return null;
}

foreach ($body->getParts() as $part) {
return $this->extractTextFromMimeMessage($body);
}

private function extractTextFromMimeMessage(MimeMessage $message): ?string
{
foreach ($message->getParts() as $part) {
if ($part->type === 'text/plain' && $part->disposition !== Mime::DISPOSITION_ATTACHMENT) {
return $part->getContent();
}
}
foreach ($message->getParts() as $part) {
if (in_array($part->type, self::MULTIPART_TYPES)) {
return $this->extractTextFromMimeMessage(
MimeMessage::createFromMessage($part->getContent(), $part->boundary)
);
}
}

return null;
}
Expand All @@ -98,11 +120,23 @@ protected function extractHtml(Message $message): ?string
return null;
}

foreach ($body->getParts() as $part) {
return $this->extractHtmlFromMimeMessage($body);
}

private function extractHtmlFromMimeMessage(MimeMessage $message): ?string
{
foreach ($message->getParts() as $part) {
if ($part->type === 'text/html' && $part->disposition !== Mime::DISPOSITION_ATTACHMENT) {
return $part->getContent();
}
}
foreach ($message->getParts() as $part) {
if (in_array($part->type, self::MULTIPART_TYPES)) {
return $this->extractHtmlFromMimeMessage(
MimeMessage::createFromMessage($part->getContent(), $part->boundary)
);
}
}

return null;
}
Expand Down
179 changes: 179 additions & 0 deletions tests/SlmMailTest/Service/AbstractMailServiceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<?php

declare(strict_types=1);

namespace SlmMailTest\Service;

use Laminas\Mail\Message;
use Laminas\Mime\Message as MimeMessage;
use Laminas\Mime\Mime;
use Laminas\Mime\Part;
use SlmMail\Service\AbstractMailService;
use PHPUnit\Framework\TestCase;

/**
* @covers \SlmMail\Service\AbstractMailService
*/
final class AbstractMailServiceTest extends TestCase
{
private AbstractMailService $service;

protected function setUp(): void
{
parent::setUp();

$this->service = new class () extends AbstractMailService {
public ?string $text = null;
public ?string $html = null;
public array $attachments = [];

public function send(Message $message)
{
$this->text = $this->extractText($message);
$this->html = $this->extractHtml($message);
$this->attachments = $this->extractAttachments($message);
}
};
}

public function testExtractTextFromStringBodyReturnsString(): void
{
$expected = 'Foo';
$message = new Message();
$message->setBody($expected);

$this->service->send($message);
self::assertSame($expected, $this->service->text);
}

public function testExtractTextFromEmptyBodyReturnsNull(): void
{
$message = new Message();

$this->service->send($message);
self::assertNull($this->service->text);
}

public function testExtractTextFromTwoPartMessageReturnsString(): void
{
$expected = 'Foo';
$message = new Message();
$body = new MimeMessage();
$body->addPart(new Part(''));
$body->addPart(
(new Part($expected))
->setType(Mime::TYPE_TEXT)
);
$message->setBody($body);

$this->service->send($message);
self::assertSame($expected, $this->service->text);
}

public function testExtractTextFromTextAttachmentReturnsNull(): void
{
$message = new Message();
$body = new MimeMessage();
$body->addPart(
(new Part('Foo'))
->setType(Mime::TYPE_TEXT)
->setDisposition(Mime::DISPOSITION_ATTACHMENT)
);
$message->setBody($body);

$this->service->send($message);
self::assertNull($this->service->text);
}

public function testExtractTextFromMultipartMessageReturnsString(): void
{
$expected = 'Foo';
$message = new Message();
$body = new MimeMessage();
$contentPart = new MimeMessage();
$contentPart->addPart(new Part());
$contentPart->addPart(
(new Part($expected))
->setType(Mime::TYPE_TEXT)
);
$body->addPart(
(new Part($contentPart->generateMessage()))
->setType(Mime::MULTIPART_ALTERNATIVE)
->setBoundary($contentPart->getMime()->boundary())
);
$message->setBody($body);

$this->service->send($message);
self::assertSame($expected, trim($this->service->text));
}

public function testExtractHtmlFromStringBodyReturnsNull(): void
{
$message = new Message();
$message->setBody('Foo');

$this->service->send($message);
self::assertNull($this->service->html);
}

public function testExtractHtmlFromEmptyBodyReturnsNull(): void
{
$message = new Message();

$this->service->send($message);
self::assertNull($this->service->html);
}

public function testExtractHtmlFromTwoPartMessageReturnsString(): void
{
$expected = 'Foo';
$message = new Message();
$body = new MimeMessage();
$body->addPart(new Part(''));
$body->addPart(
(new Part($expected))
->setType(Mime::TYPE_HTML)
);
$message->setBody($body);

$this->service->send($message);
self::assertSame($expected, $this->service->html);
}

public function testExtractHtmlFromHtmlAttachmentReturnsNull(): void
{
$message = new Message();
$body = new MimeMessage();
$body->addPart(
(new Part('Foo'))
->setType(Mime::TYPE_HTML)
->setDisposition(Mime::DISPOSITION_ATTACHMENT)
);
$message->setBody($body);

$this->service->send($message);
self::assertNull($this->service->html);
}

public function testExtractHtmlFromMultipartMessageReturnsString(): void
{
$expected = 'Foo';
$message = new Message();
$body = new MimeMessage();
$contentPart = new MimeMessage();
$contentPart->addPart(new Part());
$contentPart->addPart(
(new Part($expected))
->setType(Mime::TYPE_HTML)
);
$body->addPart(
(new Part($contentPart->generateMessage()))
->setType(Mime::MULTIPART_ALTERNATIVE)
->setBoundary($contentPart->getMime()->boundary())
);
$message->setBody($body);

$this->service->send($message);
self::assertSame($expected, trim($this->service->html));
}
}

0 comments on commit 2df9632

Please sign in to comment.