0

I'm trying to save Outlook email attachments to OneDrive using msgraph-sdk-php. I can pull in the emails and get attachment information but I don't know how to save the attachments.

I tried implementing this solution but I get this error:

Client error: `PUT https:\/\/08fxt-my.sharepoint.com\/personal\/myemail_onmicrosoft_com\/_api\/v2.0\/drive\/items\/01LRAM......` resulted in a `400 Bad Request` response:\n{\"error\":{\"code\":\"invalidRequest\",\"message\":\"The Content-Range header length does not match the provided number of bytes.\"}}\n

This is my code:

$outlook_emails = $this->getEmails();

foreach ($outlook_emails as $outlook_email) {
    $email_object = $outlook_email->jsonSerialize();


    if ($email_object['hasAttachments'] == true) {
        $email_attachments = (new Graph())->setAccessToken($accessToken)
            ->createCollectionRequest("GET", '/users/' . $userId . '/messages/' . $outlook_email->getId() . '/attachments')
            ->setReturnType(\Microsoft\Graph\Model\FileAttachment::class)
            ->execute();

        foreach ($email_attachments as $attachment) {

            $attachment_object  = $attachment->jsonSerialize();
            $filename           = $attachment->getName();

            
            $uploadsession = $graph->createRequest("POST",
                "/users/" . $userId . "/drive/root:/test/" . $filename . ":/createUploadSession")
                ->attachBody([
                    "@microsoft.graph.conflictBehavior" => "rename | fail | replace",
                    "description"                       => "description",
                    "fileSystemInfo"                    => ["@odata.type" => "microsoft.graph.fileSystemInfo"],
                    "name"                              => $filename,
                ])
                ->setReturnType(\Microsoft\Graph\Model\UploadSession::class)
                ->execute();



            $fragSize = 320 * 1024;// 1024 * 1024 * 4;

            $graph_url    = $uploadsession->getUploadUrl();
            $fileSize     = $attachment->getSize();
            $numFragments = ceil($fileSize / $fragSize);


            $bytesRemaining = $fileSize;
            $i              = 0;
            while ($i < $numFragments) {
                $chunkSize = $numBytes = $fragSize;
                $start     = $i * $fragSize;
                $end       = $i * $fragSize + $chunkSize - 1;
                $offset    = $i * $fragSize;
                if ($bytesRemaining < $chunkSize) {
                    $chunkSize = $numBytes = $bytesRemaining;
                    $end       = $fileSize - 1;
                }

                $content_range = "bytes " . $start . "-" . $end . "/" . $fileSize;


                $headers = [
                    "Content-Length" => $numBytes,
                    "Content-Range"  => $content_range,
                ];

                $uploadByte     = $graph->createRequest("PUT", $graph_url)
                    ->addHeaders($headers)
                    ->attachBody($attachment_object['contentBytes'])
                    ->setReturnType(Model\UploadSession::class)
                    ->setTimeout("1000")
                    ->execute();
                $bytesRemaining = $bytesRemaining - $chunkSize;
                $i++;
            }
        }
    }
    
}            

This is a sample output of $attachment in the inner foreach

{
  "@odata.type": "#microsoft.graph.fileAttachment",
  "@odata.mediaContentType": "application/pdf",
  "id": "AAMkAGQXXXXXXXX7Op2M8=",
  "lastModifiedDateTime": "2023-07-27T19:32:55Z",
  "name": "dummy.pdf",
  "contentType": "application/pdf",
  "size": 13454,
  "isInline": false,
  "contentId": "f_lkljxgt10",
  "contentLocation": null,
  "contentBytes": "JVBERi0xLXXXXXXXXXXXXXX="
}

This is what $headers is set to:

{"Content-Length":13454,"Content-Range":"bytes 0-13453/13454"}
Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
MalcolmInTheCenter
  • 1,376
  • 6
  • 27
  • 47

0 Answers0