# Microsoft Graph — Mail  · replaces agent365 `mail`

Paging: add `max_items=N` to any GET (≤ 1000). Coverage + limits: see the SKILL.md guide.

| Task | Call |
|------|------|
| Recent messages | `GET /me/messages?$select=subject,from,receivedDateTime,isRead&$top=20&$orderby=receivedDateTime desc` |
| Inbox only | `GET /me/mailFolders/inbox/messages?$top=20` |
| One message | `GET /me/messages/{id}` |
| Keyword search | `GET /me/messages?$search="subject:budget"` |
| Unread only | `GET /me/messages?$filter=isRead eq false` |
| With attachments | `GET /me/messages?$filter=hasAttachments eq true` |
| List attachments | `GET /me/messages/{id}/attachments` |
| Mail folders | `GET /me/mailFolders` |
| Send | `POST /me/sendMail` |
| Reply | `POST /me/messages/{id}/reply` → `{"comment":"…"}` |
| Reply all | `POST /me/messages/{id}/replyAll` → `{"comment":"…"}` |
| Forward | `POST /me/messages/{id}/forward` → `{"comment":"…","toRecipients":[{"emailAddress":{"address":"lee@x.com"}}]}` |
| Create a draft | `POST /me/messages` → `{"subject":"…","body":{…},"toRecipients":[…]}` |
| Mark read | `PATCH /me/messages/{id}` → `{"isRead": true}` |
| Move to a folder | `POST /me/messages/{id}/move` → `{"destinationId": "deleteditems"}` |
| Delete | `DELETE /me/messages/{id}` |

`$search` cannot be combined with `$filter`/`$orderby`; run two queries instead.
Well-known folder names work in place of a folder id: `inbox` · `drafts` ·
`sentitems` · `deleteditems` · `archive` · `junkemail`.
Send body:

```json
{
  "message": {
    "subject": "Status",
    "body": { "contentType": "Text", "content": "All green." },
    "toRecipients": [{ "emailAddress": { "address": "lee@contoso.com" } }]
  },
  "saveToSentItems": true
}
```

Incremental sync (changes only): `GET /me/mailFolders/inbox/messages/delta` →
save the `@odata.deltaLink`, pass it back next run (delta pattern: SKILL.md).
