zbateson / mail-mime-parser

An email parser written in PHP
https://mail-mime-parser.org/
BSD 2-Clause "Simplified" License
441 stars 56 forks source link

Decoding base64 body #202

Open denyszrazhevskiy opened 1 year ago

denyszrazhevskiy commented 1 year ago

Hi, Zaahid! Hope for your advice.

We receive non-standard emails from the same sender. mail_example.txt as example (Some data has been removed, but this does not affect the main problem). Email with headers:

Content-Type: multipart/mixed
Content-Transfer-Encoding: base64

The sender uses SAP Web Application Server 7.00, which encodes the entire body of the message in base64 encoding. According to RFC 1521 such email is not valid If a Content-Transfer-Encoding header field appears as part of a message header, it applies to the entire body of that message. If a Content-Transfer-Encoding header field appears as part of a body part's headers, it applies only to the body of that body part. If an entity is of type "multipart" or "message", the Content-Transfer-Encoding is not permitted to have any value other than a bit width (e.g., "7bit", "8bit", etc.) or "binary

As a workaround, we now use this construction

before check multipart/mixed and base64 and entire body is encoded in base64
$message = $zBatesonMimeParser->parse($nonStandardMail, false);
$message->removeHeader("Content-Transfer-Encoding");
$message->addRawHeader("Content-Transfer-Encoding", "binary");
$message->setContent(base64_decode($message->getContent()));
$message2 = $zBatesonMimeParser->parse($message->getStream(), false);

Perhaps there are better ways to do this?

Thank you for your attention.

zbateson commented 1 year ago

Hi @denyszrazhevskiy --

That's pretty close to what I'd do. I'm not a huge fan of base64_decode though since it doesn't work on streams which might be annoying for larger emails... here's what I'd do instead:

use ZBateson\MailMimeParser\Stream\HeaderStream;
use GuzzleHttp\Psr7\AppendStream;
use GuzzleHttp\Psr7;

$encoded = $zBatesonMimeParser->parse($nonStandardMail, false);
$message = $zBatesonMimeParser->parse(
    new AppendStream([ new HeaderStream($encoded), $encoded->getContentStream() ]),
    true
);

Hope that helps :)