Skip to content

Commit

Permalink
improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
arukompas committed Aug 25, 2023
1 parent 1d58467 commit 85bb0db
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 3 deletions.
44 changes: 42 additions & 2 deletions src/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,20 @@ public function getHeaders(): array

public function getHeader(string $header, $default = null): ?string
{
return $this->headers[$header] ?? $default;
$header = strtolower($header);

foreach ($this->headers as $key => $value) {
if (strtolower($key) === $header) {
return $value;
}
}

return $default;
}

public function getContentType(): string
{
return $this->getHeader('Content-Type', '');
}

public function getId(): string
Expand Down Expand Up @@ -169,7 +182,6 @@ protected function parse()

if (isset($this->boundary) && $line === '--'.$this->boundary.'--') {
// We've reached the end of the message
$this->addPart($currentBody, $currentBodyHeaders);
break;
}

Expand Down Expand Up @@ -208,6 +220,21 @@ protected function parse()
}

if (preg_match('/^(?<key>[A-Za-z\-0-9]+): (?<value>.*)$/', $line, $matches)) {
if (strtolower($matches['key']) === 'content-type' && !isset($this->boundary)) {
// this might be a single-part message. Let's start collecting the body.
$collectingBody = true;
$currentBody = '';
$currentBodyHeaders = [
$matches['key'] => $matches['value'],
];

if (str_ends_with($currentBodyHeaders[$matches['key']], ';')) {
$currentBodyHeaderInProgress = $matches['key'];
}

continue;
}

$this->headers[$matches['key']] = $matches['value'];

// if the last character is a semicolon, then the header is continued on the next line
Expand All @@ -221,6 +248,19 @@ protected function parse()
// The line is not part of the email message. Let's remove it altogether.
$this->message = ltrim(substr($this->message, strlen($line)));
}

if (!empty($currentBody) || !empty($currentBodyHeaders)) {
$this->addPart($currentBody, $currentBodyHeaders);
}

if (! $this->getContentType() && ($part = $this->getParts()[0] ?? null)) {
foreach ($part->getHeaders() as $key => $value) {
if (strtolower($key) === 'content-type') {
$this->headers[$key] = $value;
break;
}
}
}
}

protected function addPart(string $currentBody, array $currentBodyHeaders): void
Expand Down
60 changes: 59 additions & 1 deletion tests/Unit/MessageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,64 @@
use Opcodes\MailParser\Message;

it('can parse a simple mail message', function () {
$messageString = <<<EOF
From: Sender <[email protected]>
To: Receiver <[email protected]>
Subject: Test Subject
Message-ID: <[email protected]>
MIME-Version: 1.0
Date: Fri, 25 Aug 2023 15:36:13 +0200
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Email content goes here.
EOF;

$message = Message::fromString($messageString);

expect($message->getFrom())->toBe('Sender <[email protected]>')
->and($message->getTo())->toBe('Receiver <[email protected]>')
->and($message->getSubject())->toBe('Test Subject')
->and($message->getId())->toBe('[email protected]')
->and($message->getDate()?->format('Y-m-d H:i:s'))->toBe('2023-08-25 15:36:13')
->and($message->getContentType())->toBe('text/html; charset=utf-8')
->and($message->getHtmlPart()?->getContent())->toBe('Email content goes here.')
->and($message->getHtmlPart()?->getHeaders())->toBe([
'Content-Type' => 'text/html; charset=utf-8',
'Content-Transfer-Encoding' => 'quoted-printable',
]);
});

it('can parse lowercase headers', function () {
$messageString = <<<EOF
from: Sender <[email protected]>
to: Receiver <[email protected]>
subject: Test Subject
message-id: <[email protected]>
mime-version: 1.0
date: Fri, 25 Aug 2023 15:36:13 +0200
content-type: text/html; charset=utf-8
content-transfer-encoding: quoted-printable
Email content goes here.
EOF;

$message = Message::fromString($messageString);

expect($message->getHeaders())->toBe([
'from' => 'Sender <[email protected]>',
'to' => 'Receiver <[email protected]>',
'subject' => 'Test Subject',
'message-id' => '<[email protected]>',
'mime-version' => '1.0',
'date' => 'Fri, 25 Aug 2023 15:36:13 +0200',
'content-type' => 'text/html; charset=utf-8',
])
->and($message->getFrom())->toBe('Sender <[email protected]>')
->and($message->getHeader('Content-Type'))->toBe('text/html; charset=utf-8');
});

it('can parse a mail message with boundaries', function () {
date_default_timezone_set('UTC');
$messageString = <<<EOF
From: [email protected]
Expand Down Expand Up @@ -177,7 +235,7 @@
</body>
</html>
------=_Part_1_1234567890--
------=_Part_1_1234567890--
EOF;

$message = Message::fromString($messageString);
Expand Down

0 comments on commit 85bb0db

Please sign in to comment.