Building custom solutions that extend, automate, and integrate Microsoft 365 apps.
Hello Swapnil,
Looking directly at the JSON response payload you attached (153759 (1).txt), here is the exact reason why attachments are not being returned and the recommended steps to troubleshoot and verify this behavior.
1. Root Cause Analysis from Your Attached Payload
In your returned message JSON object:
-
"hasAttachments": false -
"attachments": null
Because the underlying Exchange mailbox item has hasAttachments set to false, Microsoft Graph does not expand or retrieve any attachment collection. The $expand=attachments query parameter only works when Exchange recognizes attachments on the item.
2. Why Attachments Are Missing for This Message
- Inline HTML Warnings vs Actual MIME Attachments: The email body contains an external disclaimer table/banner (
** EXTERNAL EMAIL - Please verify the sender... **) and links (https://aka.ms/LearnAboutSenderIdentification), but there is no actual file or MIME attachment part embedded in the message sent from Gmail (******@gmail.com). - Attachment Stripping by Security / Transport Rules: If the sender did attempt to attach a file, it may have been quarantined or stripped by Exchange Online Protection (EOP), Microsoft Defender for Office 365 (Safe Attachments), or an organization transport rule before reaching the inbox. When an attachment is removed by a policy, the message body is delivered but
hasAttachmentsremainsfalse. - Signed or Encrypted (S/MIME) Envelopes: If the message contains a signature or encryption layer (
smime.p7m), attachments inside the encrypted MIME tree cannot be expanded directly via the standard$expand=attachmentsendpoint.
3. Recommended Steps to Verify and Troubleshoot
Step 1: Query the Dedicated Attachments Endpoint Directly
Instead of expanding from the parent message, call the attachments collection endpoint directly:
GET https://graph.microsoft.com/v1.0/me/messages/AAMkADM1MTY5ZmQxLTZiYTMtNGYyYy04NWNmLTZhOWJmMWQxNjMyYQBGAAAAAACRGw69NWd7Ta6NLWqCEP5sBwBag65GIzOvT5oib6RULtNnAAAApIApAAATxg0baD1ESa3cjwincxQmAAeA5bw_AAA=/attachments
- Result: If this returns
{"@odata.context": "...","value": []}with an empty array (HTTP 200), Exchange confirms there are no attachments stored for this message item.
Step 2: Inspect the Raw MIME Stream ($value)
To see the exact raw RFC 822 email payload delivered to the mailbox:
GET https://graph.microsoft.com/v1.0/me/messages/AAMkADM1MTY5ZmQxLTZiYTMtNGYyYy04NWNmLTZhOWJmMWQxNjMyYQBGAAAAAACRGw69NWd7Ta6NLWqCEP5sBwBag65GIzOvT5oib6RULtNnAAAApIApAAATxg0baD1ESa3cjwincxQmAAeA5bw_AAA=/$value
- Save the response stream as a
.emlfile and open it in a text editor to check theContent-Type: multipart/...boundaries to verify whether a MIME body part withContent-Disposition: attachmentexists.
4. Best Practice Guidelines for Graph API Attachments
- Limitations of
$expand=attachments:-
$expand=attachmentsonly returns up to 10 attachments. - Large attachments (or item attachments) may not return full payload content inline.
-
- Production Recommendation:
- First inspect the
hasAttachmentsboolean property on the message. - If
hasAttachments: true, invokeGET /messages/{id}/attachmentsto reliably retrieve all attachments with proper pagination.
- First inspect the
Hope this helps resolve your issue! Please let us know if you have any further questions.