Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attachments from apple mail broken #84

Closed
iget-esoares opened this issue Jan 18, 2019 · 9 comments
Closed

Attachments from apple mail broken #84

iget-esoares opened this issue Jan 18, 2019 · 9 comments

Comments

@iget-esoares
Copy link

Trying to parse an email from apple mail with attachments fails. I can't understand why, but the .pdf file doesn't come as attachment, but instead it's an inline.

-Apple-Mail-CD6ECD97-0DAC-4631-A32C-944058EC07DB
Content-Type: application/pdf;
    name=\"Sem Ti_tulo 3.pdf\";
    x-apple-part-url=181BFA41-8F11-4043-A3F2-DAE0BBEB9876
Content-Disposition: inline;
    filename*=utf-8''Sem%20Ti%CC%81tulo%203.pdf
Content-Transfer-Encoding: base64

For some reason, trying to save these attachments from apple mail always create an corrupted file.

I'm using the following code to get attachments:

foreach ($rawMessage->getAllAttachmentParts() as $attachment) {
$contentType = $attachment->getHeader('content-type');

        $originalFilename = null;

        foreach ($contentType->getParts() as $part) {
            if ($part instanceof ParameterPart && $part->getName() == 'name') {
                $originalFilename = $part->getValue();
            }
        }

        $stream = $attachment->getContentStream();
        $destinationStream = \GuzzleHttp\Psr7\stream_for(
            fopen('php://memory', 'r+')
        );
        \GuzzleHttp\Psr7\copy_to_stream($stream, $destinationStream);

        $resourceFile = $fileService->saveStream(
            $destinationStream,
            $originalFilename
        );
    }
@iget-esoares
Copy link
Author

iget-esoares commented Jan 18, 2019

As additional, comparing the original and the saved file:

-rw-rw-r--  1 user user    811008 jan 18 11:05 broken.pdf
-rw-rw-r--  1 user user    814016 jan 18 10:48 good.pdf

Note that the broken have a few less bytes then the good one. This pattern repeats.

Also comparing the binary of two files, they are identical, except that the broken one stops first.

@iget-esoares
Copy link
Author

Investigating, found this interesting:

        $stream = $attachment->getContentStream();
        $destinationStream = \GuzzleHttp\Psr7\stream_for(
            fopen('php://memory', 'r+')
        );
        \GuzzleHttp\Psr7\copy_to_stream($stream, $destinationStream);

        $contentSize = strlen(bin2hex($destinationStream->__toString()));
        dd($contentSize/2); // Outputs 811008 - The exact broken file size

but:

        $contentSize = strlen(bin2hex($attachment->getContentStream()->__toString()));
        dd($contentSize/2); // Outputs 814016, the correct filesize.
        $stream = $attachment->getContentStream();
        $destinationStream = \GuzzleHttp\Psr7\stream_for(
            fopen('php://memory', 'r+')
        );
        \GuzzleHttp\Psr7\copy_to_stream($stream, $destinationStream);

This indicates that the problem is somewhere in Psr7 code. I'm using the fopen with memory because I need the stream, not a file, and passing the stream directly causes zero-lenght output on my file driver.

@zbateson
Copy link
Owner

Interesting, thanks for reporting and investigating.

Does this happen with any PDF attachment in apple mail consistently? It could also be a bug in base64 decoding, or some funny/unexpected pattern or character or something happening in the encoded attachment that I'm not handling correctly in zbateson/stream-decorators -- have you tried with a really small test PDF as well? Or it might be something about the size that apple mail generates... anything look strange/different at the 1081344th ((811008 / 3) * 4) character in the base64-encoded email (divide by number of characters in one line of apple-mail generated base64 to find the correct line number)?

@iget-esoares
Copy link
Author

Some points to add:

  • It happens with any PDF sent by apple mail (don't know why apple mail uses content-disposition: inline )
  • It happens with different PDF files and sizes. The "break" byte is not the same position (so it's not some memory limitation or something like that)
  • I didn't tested with different file types
  • Something important: my mime message comes inside a JSON (from mailgun api response), so some ugly conversion/escaping might cause this issue?!

Also, I workarounded the problem by changing my fileservice to support the response type of $attachment->getContentStream(). So this is no more a production issue for me, but still is annoying

@zbateson
Copy link
Owner

Aah, so this is strictly related to the Psr7\copy_to_stream call? Maybe something wrong in my stream decorator implementation causing that though, or something about the base64 stream (a character, etc...) itself that's causing something weird to happen.

zbateson added a commit to zbateson/stream-decorators that referenced this issue Mar 21, 2019
zbateson added a commit to zbateson/stream-decorators that referenced this issue Mar 21, 2019
PregReplaceFilterStream didn't implement eof(), which caused an
issue using stream_get_contents on a guzzle resource created out
of the stream

zbateson/mail-mime-parser#84
zbateson/mail-mime-parser#87
@iget-master
Copy link

Thanks for it!

@zbateson
Copy link
Owner

No problem.

For reference if anyone stumbles here, fix was released in 1.1.4

@vinceve
Copy link

vinceve commented Oct 6, 2019

@zbateson How did you fix it? I am currently experiencing the same problem but in another context. When I send a pdf from the Gmail webclient it works perfectly, but when I send a pdf from my phone (apple mail client) it does not. I am puzzled!

@zbateson
Copy link
Owner

zbateson commented Oct 6, 2019

Hi @vinceve --

This issue was specific to the base64 decoding component in my library, it was only happening to larger attachments. It wasn't related specifically to apple mail in the end.

All the best!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants