Work with email by using the Mail REST API

Find out how to get, create, update, delete, and send email by using the Mail REST API in Exchange Online.

Last modified: June 18, 2014

Applies to: Exchange Online | Office 365

Prerelease content Prerelease content

The features and APIs documented in this article are in preview and are subject to change. Do not use them in production.

Your feedback about these features and APIs is important. Let us know what you think. Have questions? Connect with us on StackOverflow. Tag your questions with [ms-office].

In this article
Get email
Create email
Update email
Delete email
Move and copy email
Send email
Additional resources

The Mail REST API provides full access to email messages in a user's mailbox on Exchange Online and Exchange Online as part of Office 365. From reading to sending email, the Mail REST API has it covered. This article provides all the information you need to know to work with email in your application.

Required Scope: Mail.Read or Mail.Write

You can use the Mail REST API to get email in two different ways. You can request a set of emails from a folder, optionally filtered or sorted, or you can request a specific email by its Id property.

Get a set of emails

Let's start simple, by getting an unfiltered, unsorted set of emails in the user's Inbox. The Inbox is accessible as a Folder entity, so it has a Messages property. The Messages property is a collection of Message entities, which represent email. We can get a basic set of emails in the Inbox by sending a GET request to the Messages property on the Inbox, as shown in the following example.

GET https://outlook.office365.com/ews/odata/Me/Inbox/Messages HTTP/1.1
Accept: application/json;odata.metadata=full

The server responds with a JSON representation of the messages in the Inbox.

NoteNote

The identifiers in the examples in this article are shortened for readability.

{
  "@odata.context": "https://outlook.office365.com/EWS/OData/$metadata#Me/Inbox/Messages",
  "value": [
    {
      "@odata.id": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI3...')",
      "@odata.editLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI3...')",
      "Id": "AAMkAGI3...",
      "ChangeKey": "CQAAABYAAABH0JWDyeM4R4EU8sjWq9C6AAAEcqJs",
      "ClassName": "IPM.Note",
      "Subject": "Sent with REST",
      "BodyPreview": "This message was created and sent with the Mail REST API!",
      "Body": {
        "ContentType": "HTML",
        "Content": "This message was created and sent with the Mail REST API!"
      },
      "Importance": "Low",
      "Categories": [],
      "HasAttachments": false,
      "ParentFolderId": "AQMkAGIP...",
      "From": {
        "Name": "Sadie Daniels",
        "Address": "sadie@contoso.com"
      },
      "Sender": {
        "Name": "Sadie Daniels",
        "Address": "sadie@contoso.com"
      },
      "ToRecipients": [
        {
          "Name": "Sadie Daniels",
          "Address": "sadie@contoso.com"
        }
      ],
      "CcRecipients": [],
      "BccRecipients": [],
      "ReplyTo": [],
      "ConversationId": "AAQkAGI3...",
      "DateTimeReceived": "2014-02-10T16:29:27Z",
      "DateTimeSent": "2014-02-10T16:29:24Z",
      "IsDeliveryReceiptRequested": false,
      "IsReadReceiptRequested": false,
      "IsDraft": false,
      "IsRead": true,
      "EventId": null,
      "MeetingMessageType": "None",
      "DateTimeCreated": "2014-02-10T16:29:27Z",
      "LastModifiedTime": "2014-02-10T16:29:27Z",
      "Attachments@odata.navigationLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI3...')/Attachments"
    },
    {
      "@odata.id": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI4...')",
      "@odata.editLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI4...')",
      "Id": "AAMkAGI4...",
      "ChangeKey": "CQAAABYAAABH0JWDyeM4R4EU8sjWq9C6AAAEcqJq",
      "ClassName": "IPM.Note",
      "Subject": "Test Subject",
      "BodyPreview": "Test Email",
      "Body": {
        "ContentType": "HTML",
        "Content": "Test Email"
      },
      "Importance": "Low",
      "Categories": [],
      "HasAttachments": false,
      "ParentFolderId": "AAMkAGIP...",
      "From": {
        "Name": "Sadie Daniels",
        "Address": "sadie@contoso.com"
      },
      "Sender": {
        "Name": "Sadie Daniels",
        "Address": "sadie@contoso.com"
      },
      "ToRecipients": [
        {
          "Name": "Sadie Daniels",
          "Address": "sadie@contoso.com"
        }
      ],
      "CcRecipients": [],
      "BccRecipients": [],
      "ReplyTo": [],
      "ConversationId": "AAQkAGI4...",
      "DateTimeReceived": "2014-02-10T16:12:19Z",
      "DateTimeSent": "2014-02-10T16:12:16Z",
      "IsDeliveryReceiptRequested": false,
      "IsReadReceiptRequested": false,
      "IsDraft": false,
      "IsRead": true,
      "EventId": null,
      "MeetingMessageType": "None",
      "DateTimeCreated": "2014-02-10T16:12:19Z",
      "LastModifiedTime": "2014-02-10T16:12:19Z",
      "Attachments@odata.navigationLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI4...')/Attachments"
    }
  ]
}

Refining results with paging, filtering, and property selection

That simple example works great if you're not concerned with sorting or filtering, and if there are less than 50 messages in the user's Inbox. If any of those conditions aren't true, you probably want to refine the results that you get back from the GET request.

Table 1.  Ways to refine the results

If you want to refine...

Use...

Explanation

The size of the result set

The $top and $skip query parameters defined by OData Version 4.0 Part 2: URL Conventions

By default, the number of results is limited to 50. You can change the number of results by using the $top parameter, up to a maximum of 500.

The $skip parameter is used to implement a paging mechanism. For example, if you request 10 items in your first GET request, you can then repeat the same GET request with "$skip=10" to get the next 10 results.

The sort order of the result set

The $orderby query parameter defined by OData Version 4.0

You can use the $orderby parameter with any Message entity property to control the sorting of the results.

The filtering of the result set

The $filter query parameter defined by OData Version 4.0

You can use the $filter parameter to define simple or complex filters to control which items are returned.

The specific properties returned in the result set

The $select query parameter defined by OData Version 4.0

By default, all properties defined by the $metadata document for a Message entity are returned in the result set. You can reduce the number of properties that are returned by using the $select parameter. However, the odata.id, odata.editLink, Id, and Attachments@odata.navigationLink properties are always returned in the results set.

Let's refine our original query. The following example sorts the results by the DateTimeReceived property (in ascending order), only includes items with the Importance property set to "Low", requests only the Subject, Importance, and DateTimeReceived properties, and limits the results to at most five items.

GET https://outlook.office365.com/ews/odata/Me/Inbox/Messages?$orderby=DateTimeReceived&$filter=Importance eq Microsoft.Exchange.Services.OData.Model.Importance'Low'&$select=Subject,Importance,DateTimeReceived&$top=5 HTTP/1.1
Accept: application/json;odata.metadata=full

This time, the response looks a bit different than the response in the previous example.

{
  "@odata.context": "https://outlook.office365.com/EWS/OData/$metadata#Me/Inbox/Messages",
  "value": [
    {
      "@odata.id": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI4...')",
      "@odata.editLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI4...')",
      "Id": "AAMkAGI4...",
      "Subject": "Test Subject",
      "Importance": "Low",
      "DateTimeReceived": "2014-02-10T16:12:19Z",
      "Attachments@odata.navigationLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI4...')/Attachments"
    },
    {
      "@odata.id": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI3...')",
      "@odata.editLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI3...')",
      "Id": "AAMkAGI3...",
      "Subject": "Sent with REST",
      "Importance": "Low",
      "DateTimeReceived": "2014-02-10T16:29:27Z",
      "Attachments@odata.navigationLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI3...')/Attachments"
    }
  ]
}

OData provides a lot of different query options to refine results. The following are just a few examples.

This example requests all messages in the Inbox that have "project plan" in the subject.

GET https://outlook.office365.com/ews/odata/Me/Inbox/Messages?$filter=contains(Subject,'project plan') HTTP/1.1
Accept: application/json;odata.metadata=full

This example requests all messages in the Inbox that are part of the same conversation. It uses the value of the ConversationId property from a Message entity within that conversation.

GET https://outlook.office365.com/ews/odata/Me/Inbox/Messages?$filter=ConversationId eq 'AAQkAGI3...' HTTP/1.1
Accept: application/json;odata.metadata=full

This example requests all messages in the Inbox received on or after February 18, 2014.

GET https://outlook.office365.com/ews/odata/Me/Inbox/Messages?$filter=DateTimeReceived ge 2014-02-18 HTTP/1.1
Accept: application/json;odata.metadata=full

Get a specific email

To get a specific email, you need its identifier. The value of a Message entity's Id property is used as an entity key to select that Message from a collection. The top-level Message entity collection, exposed by the Messages property on a User entity, is the best way to request a specific email. You can also use the value of the @odata.id property to obtain a ready-made URL for the email.

The following example requests a specific email by its identifier.

GET https://outlook.office365.com/EWS/OData/Me/Messages('AAMkAGI3...') HTTP/1.1
Accept: application/json;odata.metadata=full

Required Scope: Mail.Write

Now that you're familiar with how to get existing email, let's look at adding new items. You can create an email in any mail folder in the mailbox. One common scenario is saving a work in progress to the user's Drafts folder.

The first thing you need to do is create a JSON representation of the email you want to create. Within that JSON representation, you include the property values that you want to set. Then you send that JSON representation in the payload of a POST request to the URL of the Message entity collection that you want to create the new message in.

Note Note

By default, attempting to create an email in the Messages property on the User object will result in the message being sent instead of saved, assuming your application has the Mail.Send scope. You can change this behavior by using the MessageDisposition parameter. If you set the parameter to "SaveOnly", the message will be saved in the Draft folder. If you set it to "SendAndSaveCopy", the message will be sent and a copy will be saved in the Sent Items folder.

The following example creates a new email in the user's Drafts folder.

POST https://outlook.office365.com/ews/odata/Me/Drafts/Messages HTTP/1.1
Accept: application/json;odata.metadata=full
Content-Type: application/json;odata.metadata=full
Expect: 100-continue

{
  "@odata.type": "#Microsoft.Exchange.Services.OData.Model.Message",
  "Subject": "Have you seen this new Mail REST API?",
  "Importance": "High",
  "Body": {
    "ContentType": "HTML",
    "Content": "It looks awesome!"
  },
  "ToRecipients": [
    {
      "Name": "Hope Gross",
      "Address": "hope@contoso.com"
    }
  ]
}

The server responds with a JSON representation of the new email.

{
  "@odata.context": "https://outlook.office365.com/EWS/OData/$metadata#Me/Drafts/Messages/$entity",
  "@odata.id": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI5...')",
  "@odata.editLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI5...')",
  "Id": "AAMkAGI5...",
  "ChangeKey": "CQAAABYAAABH0JWDyeM4R4EU8sjWq9C6AAAEcrvy",
  "ClassName": "IPM.Note",
  "Subject": "Have you seen this new Mail REST API?",
  "BodyPreview": "It looks awesome!",
  "Body": {
    "ContentType": "HTML",
    "Content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n</head>\r\n<body>\r\nIt looks awesome!\r\n</body>\r\n</html>\r\n"
  },
  "Importance": "High",
  "Categories": [],
  "HasAttachments": false,
  "ParentFolderId": "AQMkAGIP...",
  "From": null,
  "Sender": null,
  "ToRecipients": [
    {
      "Name": "Hope Gross",
      "Address": "hope@contoso.com"
    }
  ],
  "CcRecipients": [],
  "BccRecipients": [],
  "ReplyTo": [],
  "ConversationId": "AAMkAGI5...",
  "DateTimeReceived": "2014-02-14T21:24:32Z",
  "DateTimeSent": "2014-02-14T21:24:32Z",
  "IsDeliveryReceiptRequested": false,
  "IsReadReceiptRequested": false,
  "IsDraft": true,
  "IsRead": true,
  "EventId": null,
  "MeetingMessageType": "None",
  "DateTimeCreated": "2014-02-14T21:24:32Z",
  "LastModifiedTime": "2014-02-14T21:24:32Z",
  "Attachments@odata.navigationLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI5...')/Attachments"
}

Required Scope: Mail.Write

Now that you’ve created a draft email in the Drafts folder, the next task is to finish composing that email. To update an existing item, send a PATCH request to the URL for that item. The payload of the PATCH request is a JSON representation of the properties that you want to update. Only the properties that you include in the payload are changed.

The following example updates the Body property of the email.

PATCH https://outlook.office365.com/ews/odata/Me/Messages('AAMkAGI5...') HTTP/1.1
Accept: application/json;odata.metadata=full
Content-Type: application/json;odata.metadata=full
Expect: 100-continue

{
  "Body": {
    "ContentType": "HTML",
    "Content": "It looks awesome! I think it will suit our needs nicely."
  }
}

The server responds with a JSON representation of the updated email.

{
  "@odata.context": "https://outlook.office365.com/EWS/OData/$metadata#Me/Drafts/Messages/$entity",
  "@odata.id": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI5...')",
  "@odata.editLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI5...')",
  "Id": "AAMkAGI5...",
  "ChangeKey": "CQAAABYAAABH0JWDyeM4R4EU8sjWq9C6AAAEcrv0",
  "ClassName": "IPM.Note",
  "Subject": "Have you seen this new Mail REST API?",
  "BodyPreview": "It looks awesome! I think it will suit our needs nicely.",
  "Body": {
    "ContentType": "HTML",
    "Content": "<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n</head>\r\n<body>\r\nIt looks awesome! I think it will suit our needs nicely.\r\n</body>\r\n</html>\r\n"
  },
  "Importance": "High",
  "Categories": [],
  "HasAttachments": false,
  "ParentFolderId": "AAMkAGIP...",
  "ToRecipients": [
    {
      "Name": "Hope Gross",
      "Address": "hope@contoso.com"
    }
  ],
  "CcRecipients": [],
  "BccRecipients": [],
  "ReplyTo": [],
  "ConversationId": "AAMkAGI5...",
  "DateTimeReceived": "2014-02-14T21:24:32Z",
  "DateTimeSent": "2014-02-14T21:24:32Z",
  "IsDeliveryReceiptRequested": false,
  "IsReadReceiptRequested": false,
  "IsDraft": true,
  "IsRead": true,
  "EventId": null,
  "MeetingMessageType": "None",
  "DateTimeCreated": "2014-02-14T21:24:32Z",
  "LastModifiedTime": "2014-02-14T21:38:59Z",
  "Attachments@odata.navigationLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI5...')/Attachments"
}

Required Scope: Mail.Write

You can delete email by simply sending a DELETE request to the URL of the Message entity. The following example deletes an email from the Inbox.

Note Note

When you delete items by using the Mail REST API, you bypass the Deleted Items folder, and instead perform a soft delete. If you want to move items to the Deleted Items folder instead, see Move and copy email later in this article.

DELETE https://outlook.office365.com/ews/odata/Me/Messages('AAMkAGI3...') HTTP/1.1

The server responds with an HTTP status 200 "OK" to indicate success.

Required Scope: Mail.Write

To move or copy an email, use the Move or Copy action on the Message entity, respectively. To invoke these actions, send a POST request to the URL of the Message entity, with a '/' and the name of the action appended to the end. For example, to move an email, you would append "/Move" to the URL of the Message. The payload of the POST request for a Copy or a Move action is a JSON object with a single property, DestinationId. This property contains the identifier of the Folder entity to copy or move the item to.

The following example moves an email from the Inbox to the Deleted Items folder.

POST https://outlook.office365.com/ews/odata/Me/Messages('AAMkAGI3...')/Move HTTP/1.1
Accept: application/json;odata.metadata=full
Content-Type: application/json;odata.metadata=full
Expect: 100-continue

{
  "DestinationId": "DeletedItems"
}

The server responds with a JSON representation of the email in the Deleted Items folder.

Required Scope: Mail.Send

You can use the Mail REST API to send email in two different ways. The first is to invoke the Send action on an existing email that has the IsDraft property set to true. For example, your user might save a message to the Drafts folder, and then later decide to send it. The Send action automatically saves a copy to the Sent Items folder for you.

The following example sends the message that was created and updated in the previous examples.

POST https://outlook.office365.com/ews/odata/Me/Messages('AAMkAGI5...')/Send HTTP/1.1

The server responds with an HTTP status 200 "OK" to indicate success.

This approach works great, but requires at least two roundtrips to the server: one to create the message, and one to invoke the Send action. What if your application just wants to send an email right away? That's where the second way to send an email comes in. With the Mail REST API, you can send an email immediately by using the MessageDisposition query parameter in the URL when you send the POST request to create the email.

The MessageDisposition parameter has three possible values: "SaveOnly", "SendOnly", and "SendAndSaveCopy". In the previous example that creates an email, the MessageDisposition parameter was omitted. In most cases, if you do not include this parameter, the default value is "SaveOnly". The exception to this rule is if you are sending a POST to the Messages property on the User entity, such as /Me/Messages. In that case, if you omit the MessageDisposition parameter, the default value is "SendOnly". If you include the parameter with a value of "SendOnly", the email is sent and no copy is saved in the user's mailbox. If you include the parameter with a value of "SendAndSaveCopy", the email is sent and a copy is saved in the folder where you create it.

The following example creates a message in the Sent Items folder and sends it.

POST https://outlook.office365.com/ews/odata/Me/SentItems/Messages?MessageDisposition=SendAndSaveCopy HTTP/1.1
Accept: application/json;odata.metadata=full
Expect: 100-continue

{
  "@odata.type": "#Microsoft.Exchange.Services.OData.Model.Message",
  "Subject": "Sent in a single POST",
  "Importance": "Normal",
  "Body": {
    "ContentType": "HTML",
    "Content": "This message was created and sent in a single post."
  },
  "ToRecipients": [
    {
      "Name": "Hope Gross",
      "Address": "hope@contoso.com"
    }
  ]
}

The server responds with a JSON representation of the email after it has been sent.

{
  "@odata.context": "https://outlook.office365.com/EWS/OData/$metadata#Me/SentItems/Messages/$entity",
  "@odata.id": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI6...')",
  "@odata.editLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI6...')",
  "Id": "AAMkAGI6...",
  "ChangeKey": "CQAAABYAAABH0JWDyeM4R4EU8sjWq9C6AAAEcr/A",
  "ClassName": "IPM.Note",
  "Subject": "Sent in a single POST",
  "BodyPreview": "This message was created and sent in a single post.",
  "Body": {
    "ContentType": "HTML",
    "Content": "This message was created and sent in a single post."
  },
  "Importance": "Normal",
  "Categories": [],
  "HasAttachments": false,
  "ParentFolderId": "AQMkAGIS...",
  "From": {
    "Name": "Sadie Daniels",
    "Address": "sadie@contoso.com"
  },
  "Sender": {
    "Name": "Sadie Daniels",
    "Address": "sadie@contoso.com"
  },
  "ToRecipients": [
    {
      "Name": "Hope Gross",
      "Address": "hope@contoso.com"
    }
  ],
  "CcRecipients": [],
  "BccRecipients": [],
  "ReplyTo": [],
  "ConversationId": "AAMkAGI6...",
  "DateTimeReceived": "2014-02-17T15:17:19Z",
  "DateTimeSent": "2014-02-17T15:17:19Z",
  "IsDeliveryReceiptRequested": false,
  "IsReadReceiptRequested": false,
  "IsDraft": false,
  "IsRead": true,
  "EventId": null,
  "MeetingMessageType": "None",
  "DateTimeCreated": "2014-02-17T15:17:19Z",
  "LastModifiedTime": "2014-02-17T15:17:19Z",
  "Attachments@odata.navigationLink": "https://outlook.office365.com/EWS/OData/Users('sadie@contoso.com')/Messages('AAMkAGI6...')/Attachments"
}
Show:
© 2014 Microsoft