microsoftgraph / msgraph-sdk-php

Microsoft Graph Library for PHP.
Other
575 stars 144 forks source link

How to get the Email-Content (for file_put_contents) and the Email-direction #932

Closed basementmedia2 closed 2 years ago

basementmedia2 commented 2 years ago

Hi again,

sorry for this second post at same day:

If i execute the following request

$email = $graph->createRequest("GET", "my@email.com/mailfolders/inbox/messages/myemail_id)
->setReturnType(Model\Message::class)
->execute();

I get a response-JSON Object. But this contains no information about email-direction (incoming/outgoing). With PHP-EWS response object had the member "X-MS-Exchange-Organization-MessageDirectionality" which contained e.g. "incoming". How to get this information with microsoft graph?

And another question is related to the Email-Attachments (i hope it is ok to put two questions in one post):

if ($email->getHasAttachments() > 0) {
    echo "We've got attachments!";
    $fileAttachment_arr = $graph->createRequest("GET", "my@email.com/mailfolders/inbox/messages/myemail_id/attachments/")
    ->setReturnType(Model\Attachment::class)
    ->execute();

    foreach ($fileAttachment_arr as $att_item) {
        $att_name = $att_item->getName(); // works
        $contentType = $att_item->getContentType(); // works
        $contentID = $att_item->getId(); // works
        $isInline = $att_item->getIsInline(); // works
        $att_contentBytes = $att_item->getContentBytes(); // Does NOT work
        $att_content = $att_item->getContent(); // Does NOT work
    }
}

With PHP-EWS i could do this, to generate a file:

$att_content = $att_item->getContent();
file_put_contents($somepath, $att_content);

But how can i do this with microsoft graph API.

Thank you for yout support.

Best regards Daniel

zengin commented 2 years ago

Hi @basementmedia2,

Thanks for raising these two questions:

For the 1st question, please extend the URL with a select query option and then call getInternetMessageHeaders()

$email = $graph->createRequest("GET", "my@email.com/mailfolders/inbox/messages/myemail_id?$select=internetMessageHeaders")
->setReturnType(Model\Message::class)
->execute();

$headers = $email->getInternetMessageHeaders();

// loop through headers and get the value when name is X-MS-Exchange-Organization-MessageDirectionality

For the 2nd question, please refer to the following:

https://github.com/microsoftgraph/msgraph-sdk-php/blob/c8a1436a504c66621019aea89b3239f1aeb737a8/tests/Functional/MailTest.php#L90 and let us know if that works.

getContentBytes is available in the child class FileAttachment:

https://github.com/microsoftgraph/msgraph-sdk-php/blob/c8a1436a504c66621019aea89b3239f1aeb737a8/src/Beta/Microsoft/Graph/Model/FileAttachment.php#L33

basementmedia2 commented 2 years ago

Hi,

thank you for your answers.

To answer regarding question 1:

I already tried reading out the internetMessageHeaders, but now i know why it didn't work: When i execute the following query

$email = $graph->createRequest("GET", "https://graph.microsoft.com/v1.0/me/messages/AAMkAGE4NmI2MmZkLWJjNzktNDBmMS1hZGY4LWIxMzBjNmY4MWI3OQBGAAAAAAAlT71tgzMxT4lEEyvGxik9BwDrnNWima7tSIuOg9AgCoUfAAAAAAEMAADrnNWima7tSIuOg9AgCoUfAACmb0ydAAA=?$select=internetMessageHeaders")
->setReturnType(Model\Message::class)
->execute();

I get this error

Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: `GET https://graph.microsoft.com/v1.0/me/messages/AAMkAGE4NmI2MmZkLWJjNzktNDBmMS1hZGY4LWIxMzBjNmY4MWI3OQBGAAAAAAAlT71tgzMxT4lEEyvGxik9BwDrnNWima7tSIuOg9AgCoUfAAAAAAEMAADrnNWima7tSIuOg9AgCoUfAACmb0ydAAA=?=internetMessageHeaders` resulted in a `400 Bad Request` response: {"error":{"code":"BadRequest","message":"/me request is only valid with delegated authentication flow.","innerError":{"d (truncated...) in /www/htdocs/myfolder/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113 Stack trace: #0 /www/htdocs/myfolder/vendor/guzzlehttp/guzzle/src/Middleware.php(66): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response)) #1 /www/htdocs/myfolder/vendor/guzzlehttp/promises/src/Promise.php(203): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response)) #2 /www/htdocs/myfolder/vendor/guzzlehttp/promises/src/Promise.php(156 in /www/htdocs/myfolder/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php on line 113

Means the "$select" gets lost --> means problem is related to PHP

Do you know a way to solve this so that $select is not replaced by an empty string?

To your answer related to question 2

I am not sure if I have transferred the example from your link correctly to my code (since you are working with "$this->_client" in your Public Function):

Here is my attempt which does not work yet:

$email = $graph->createRequest("GET","my.email@mydomain.de/mailfolders/inbox/messages/myemail_id)
->setReturnType(Model\Message::class)
->execute();

$subject=$email->getSubject(); // works!

$attachments = $graph->createRequest("GET", "my.email@mydomain.de/mailfolders/inbox/messages/myemail_id/attachments")
->setReturnType(Model\Attachment::class)
->execute();

$attachmentId = $attachments[0]->getId();
$attachment = $graph->createRequest("GET", "my.email@mydomain.de/mailfolders/inbox/messages/myemail_id/attachments/".$attachmentId)
->setReturnType(Model\FileAttachment::class)
->execute()

// How do i transfer the last two lines of your code example to my case:
//$this->assertInstanceOf(Model\FileAttachment::class, $attachment);
//$this->assertNotNull($attachment->getContentBytes());

// And how can i then get file_put_contents working?

Can you help me to complete the code so that I can create a file with "file_put_contents()"?

zengin commented 2 years ago

For question 1, you need to escape the $ sign as it has a special meaning in PHP, note the backslash before $, sorry I missed that in the first reply:

$email = $graph->createRequest("GET", "my@email.com/mailfolders/inbox/messages/myemail_id?\$select=internetMessageHeaders")
->setReturnType(Model\Message::class)
->execute();

$headers = $email->getInternetMessageHeaders();

// loop through headers and get the value when name is X-MS-Exchange-Organization-MessageDirectionality

For question 2, the code I linked to is in a test context, which validates the result returned. Assert functions come from the testing library. You don't need that in your code, could you run the following parts from your original question after the line that gets the $attachment?

$att_contentBytes = $attachment->getContentBytes();
file_put_contents($somepath, $att_contentBytes);
basementmedia2 commented 2 years ago

Hi,

this

$att_contentBytes = $attachment->getContentBytes();
file_put_contents($somepath, $att_contentBytes);

unfortunately results in an error:

Fatal error: Uncaught Error: Call to undefined method Microsoft\Graph\Model\Attachment::getContentBytes() in /www/htdocs/[...]/myfile.php:133 Stack trace: #0 {main} thrown in /www/htdocs/[...]/myfile.php on line 133

Here is the full code:

$attachments = $graph->createRequest("GET", "my@email.de/mailfolders/inbox/messages/{email_id}/attachments")
->setReturnType(Model\Attachment::class)
->execute();

if (!empty($attachments)) {
  // we have attachments...
  foreach ($attachments as $att_item) {
          $attID = $att_item->getId();
          $att_name = $att_item->getName();
          $contentType = $att_item->getContentType();
          $isInline = $att_item->getIsInline();
          $att_contentBytes = $att_item->getContentBytes(); // DOES NOT WORK
          $contentID = $att_item->getContentId(); // DOES ALSO NOT WORK
   }
} else {
  // We have no attachments...
}
zengin commented 2 years ago

Hi @basementmedia2,

That behavior is expected if you set the return type to be Model\Attachment::class as the parent class doesn't have contentBytes. Could you change the return type to Model\FileAttachment::class and try again?

basementmedia2 commented 2 years ago

Sorry @zengin i forgot to answer ;-( Works now, thank you for your help!

zengin commented 2 years ago

No worries, thanks for the confirmation!

basementmedia2 commented 2 years ago

Hi @zengin ,

sorry to come back with the same problem but: I did now realize that the attachment (in my example case a PDF) was saved but can not be opened. It has some more Kilobytes than the original PDF-File of the email and if you open it, the fault message "file can not be opened" is displayed.

Here again is the final PHP-code:

$attachments = $graph->createRequest("GET", "{myemail}/mailfolders/inbox/messages/{email_id}/attachments")
->setReturnType(Model\FileAttachment::class)
->execute();

if (!empty($attachments)) {

foreach ($attachments as $att_item) {
  $uniqid = uniqid();
  $attID = $att_item->getId();
  $att_name = $att_item->getName();

  $contentType = $att_item->getContentType();
  $contentID = $att_item->getContentId();
  $isInline = $att_item->getIsInline();

  $att_content = $att_item->getContentBytes();

  if ($isInline==0) {        
    $path=$_SERVER['DOCUMENT_ROOT']."email_att/".$uniqid."/".$att_name;
    if (!is_dir($_SERVER['DOCUMENT_ROOT']."email_att/".$uniqid."/")) {
      mkdir($_SERVER['DOCUMENT_ROOT']."email_att/".$uniqid."/");
    } 
    file_put_contents($path, $att_content);
  }
} 

As said, the PDF-file is created but not readable :-( Can you once again help me?

Best regards Daniel

Edit: I tried same with a txt-file attachment. the original txt has the text "Das ist ein Test" After file_put_contents the text is "RGFzIGlzdCBlaW4gVGVzdA=="

Seems that is is encrypted.

basementmedia2 commented 2 years ago

Yes!

base64_decode() solved the problem: --> file_put_contents($path, base64_decode($att_content));