Back to feature list...

Message operations

The sample code on this page assumes you have already connected and authenticated to Microsoft 365 (Exchange Online) server.

Getting list of messages 

To get a list of messages, use GetMessageList() method. The following code shows how to get the top page of messages in the Inbox folder.

// create Graph client instance, connect, log in
// ...

// get top page of messages from 'Inbox'
GraphMessageCollection messages = client.GetMessageList(GraphFolderId.Inbox);

// show info about them
foreach (GraphMessageInfo info in messages)
{
    Console.WriteLine("From: {0}", info.From);
    Console.WriteLine("To: {0}", info.To);
    Console.WriteLine("Subject: {0}", info.Subject);
}
Tip: You can make things faster by choosing which message fields to return. By default, server-specific set of properties is returned.

Getting list of messages with paging 

A folder can contain thousands of items. Retrieving all of them might consume a lot of bandwidth and take a very long time. Additionally, it's usually not even possible because Exchange server limits the maximum number of items it can return in response to a single API call.

For many applications, working with several hundreds of latest items is entirely sufficient. When it isn't, use GraphPageView.

The following code shows how to retrieve a list of all messages in the 'Inbox' folder by calling GetMessageList() multiple times using the paging functionality:

// create Graph client instance, connect, log in
// ...

// list all messages in 'Inbox' using paging functionality
int offset = 0;
int pageSize = 1000;
while (true)
{
    // get next page
    GraphMessageCollection messages = client.GetMessageList(
        GraphFolderId.Inbox,
        new GraphPageView(offset, pageSize));

    // show info about messages
    foreach (GraphMessageInfo m in messages)
    {
        Console.WriteLine("[{0}] ({1}) {2}", m.ReceivedDate, m.From, m.Subject);
    }

    // break if there are no more messages
    if (messages.Count == 0)
        break;

    // set next offset
    offset += messages.Count;
}

// final offset corresponds to total number of messages listed
Console.WriteLine("Total messages: {0}", offset);

Getting message info 

To get information about a message, use GetMessageInfo() method.

By default, information specified by GraphMessageFields.Default is retrieved, which includes the default set of properties as returned by Microsoft 365 (Exchange Online) server.

// create Graph client instance, connect, log in
// ...

// construct message ID
GraphMessageId id = new GraphMessageId(messageIdString);

// retrieve envelope of the message
GraphMessageInfo message = client.GetMessageInfo(id, GraphMessageFields.Envelope);

// show some info about the message
Console.WriteLine("Subject: {0}", message.Subject);
Console.WriteLine("From: {0}", message.From);
Console.WriteLine("To: {0}", message.To);

Tip: Limiting the fields to those you need to retrieve might improve the performance of your application.

Downloading messages 

To download and parse a whole mail message into a MailMessage object, use GetMailMessage() method:

// create Graph client instance, connect, log in
// ...

// get a message
MailMessage message = client.GetMailMessage(messageId);

// show some info about the message
Console.WriteLine("Subject: {0}", message.Subject);
Console.WriteLine("From: {0}", message.From);
Console.WriteLine("To: {0}", message.To);
foreach (Attachment item in message.Attachments)
{
    Console.WriteLine(" * {0} <{1}>", item.DisplayName, item.ContentType);
}

This retrieves an instance of high-level MailMessage object. If you prefer the low-level API (MimeMessage object), call GetMimeMessage() method instead.

Alternatively, you can download a message into a file using GetMessage() method:

// create Graph client instance, connect, log in
// ...

// download a message to a file in MIME format
client.GetMessage(messageId, @"C:\data\message.eml");

To download a message into a Stream, use another GetMessage() overload:

// create Graph client instance, connect, log in
// ...

using (Stream writer = File.Create(@"C:\data\message.eml"))
{
    // download a message to a stream in MIME format
    client.GetMessage(messageId, writer);
}

Tip: When downloaded, messages are marked as Read by default. To keep messages unread, set client.Settings.MarkDownloadedMessageAsRead to false.

Uploading messages 

You can also upload messages to a folder at the server without sending them. The StoreMessage() method accepts MailMessage or MimeMessage object. To upload a mail message from a file or stream, load it to MailMessage or MimeMessage object first:

// create Graph client instance, connect, log in
// ...

// load a mail message
MailMessage mail = new MailMessage();
mail.Load(@"C:\data\message.eml");

// upload the mail to 'Drafts' folder
GraphMessageInfo message = client.StoreMessage(GraphFolderId.Drafts, mail);

// keep its ID for later use if needed
var messageId = message.Id;

Updating messages 

The UpdateMessage() method can update a message on the server without downloading and re-uploading it. Intended changes are specified using an instance of the GraphMessageData class and then applied to a message on the server.

// create Graph client instance, connect, log in
// ...

// prepare updates of a message
var updateSet = new GraphMessageData();
updateSet.Flag = GraphFlag.CreateFlagged(
    startDateTime: DateTime.Today,
    dueDateTime: DateTime.Today.AddDays(1));
updateSet.Categories = new GraphCategoryCollection("Project A", "Project B");
updateSet.Subject = "Updated subject";
updateSet.SetBodyHtml("Updated <b>body</b>.");
updateSet.Importance = GraphImportance.High;
updateSet.IsRead = false;

// apply updates
client.UpdateMessage(messageId, updateSet);

Moving messages 

To move a message to another folder, use MoveMessage() method.

// create Graph client instance, connect, log in
// ...

DateTime yesterday = DateTime.Today.AddDays(-1);

// find top page of messages that arrived to 'Inbox' yesterday
var items = client.Search(GraphFolderId.Inbox,
                          GraphMessageSearchParameter.Arrived(yesterday));

// move all of them to 'Archive' folder
foreach (GraphMessageInfo item in items)
{
    client.MoveMessage(item.Id, GraphFolderId.Archive);
}

Tip: The MoveMessage() method returns info about the new item, including its new ID.

Deleting messages 

To delete a message, use DeleteMessage() method. By default, messages are soft-deleted, which means they are moved to the Deletions subfolder of Recoverable Items folder. They can still be accessed using GraphFolderId.Deletions for a while. To enforce hard-delete, set the permanent argument of the DeleteMessage() method to true.

// create Graph client instance, connect, log in
// ...

// hard-delete desired message (do not move it to 'Deletions' folder)
client.DeleteMessage(messageId, permanent: true);

Searching for messages 

Use Search() method to search for messages matching the specified criteria. Check out Searching section for more information.

Working with attachments 

Rebex Graph makes it possible to list, add and download attachments of existing messages.

To add an attachment to a message, use AddAttachment() method:

// create Graph client instance, connect, log in
// ...

// prepare attachment metadata
var meta = new GraphAddAttachmentOptions()
{
    Name = "image.jpg",
    ContentType = MediaTypeNames.Image.Jpeg
};

// add an attachment to the existing message
var attInfo = client.AddAttachment(messageId, @"C:\data\image.jpg", meta);

// show some info about the attachment
Console.WriteLine("Added attachment {0} ({1}B).", attInfo.Name, attInfo.Size);

To list attachments of a message, use GetMessageInfo() method and specify GraphMessageFields.AttachmentInfo. To download an attachment, use GetAttachment() method:

// get info about message attachments
var info = client.GetMessageInfo(messageId, GraphMessageFields.AttachmentInfo);

// iterate through all message attachments
foreach (var att in info.Attachments)
{
    // filter image attachments
    if (att.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
    {
        // download it
        var attachment = client.GetAttachment(att.Id);

        // save it
        attachment.Save(@"C:\data\images\" + attachment.FileName);
    }
}

Graph IDs and MIME IDs 

Graph API provides various types of objects IDs. In Rebex Graph, these are represented by different classes:

  • Folder: GraphFolderId - represents mailbox folders and subfolders (such as 'Inbox', 'Sent Items' or 'Drafts').
  • Message: GraphMessageId - represents e-mail messages.
  • Attachment: GraphAttachmentId - represents attachments of e-mail messages.

These IDs are available as Id property of GraphFolderInfo, GraphMessageInfo and GraphAttachmentInfo classes. There are also several pre-defined folder IDs that can be used to access well-known folders.

Note: GraphMessageInfo and MailMessage classes also feature the MessageId property. This represents the Message-ID MIME header that is not related to Graph IDs.

To convert a Graph message ID to a MIME Message-ID, retrieve the message envelope info:

// get Envelope info of a message with desired Exchange ID (graphMessageId)
var message = client.GetMessageInfo(graphMessageId, GraphMessageFields.Envelope);

// read Message-ID (MIME header) from the message info
var mimeMessageId = message.MessageId;

To convert a MIME Message-ID to a Graph message ID, use the Search() method:

// search for messages with desired Message-ID MIME header
// the header is represented by 'internetMessageId' in Microsoft Graph API
// specify null folder to search anywhere in the mailbox
var messages = client.Search(folderId: null, new GraphMessageSearchQuery()
{
    Fields = GraphMessageFields.Id,
    RawFilter = $"internetMessageId eq '{mimeMessageId}'"
});

Console.WriteLine("Messages with Message-ID '{0}':", mimeMessageId);
foreach (GraphMessageInfo info in messages)
{
    Console.WriteLine(info.Id);
}

Note: Graph API IDs are case-sensitive strings, which makes them unsuitable to be used as a file name on case-insensitive file systems.

Message body type 

A body of a mail message can use HTML, plain text, or both. The GraphMessageInfo class has properties for both formats: BodyText and BodyHtml. However, due to a limitation of Graph API (which only exposes a single body object with one content type), only one of these properties is set at any given time.

Additionally, a BodyPreview property is available, which contains the beginning of the message body (at most 255 characters) and is always in plain text (no HTML tags).

To specify which type of message body to retrieve from the server into GraphMessageInfo, set the PreferredBodyType option:

// create Graph client instance, connect, log in
// ...

// prepare options
GraphMessageInfoOptions options = new GraphMessageInfoOptions
{
    // request basic info and body
    Fields = GraphMessageFields.Envelope | GraphMessageFields.Body,

    // request HTML body
    PreferredBodyType = GraphBodyContentType.Html
};

// get the message info from the server
GraphMessageInfo messageInfo = client.GetMessageInfo(messageId, options);

// show preview of the message body (it has a value regardless PreferredBodyType)
Console.WriteLine("Body preview: {0}", messageInfo.BodyPreview);

// you can rely on BodyHtml having a value
Console.WriteLine("HTML body: {0}", messageInfo.BodyHtml);

// BodyText will be null in this case
//Console.WriteLine("Text body: {0}", messageInfo.BodyText);

Tip: Retrieving both HTML and plain text message bodies requires two separate API calls. Alternatively, download the whole mail message instead of getting message info.

If the message stored on the server does not include the specified body format (HTML or plain text), the server generates it by converting the available body content to the requested format.

If PreferredBodyType is set to Default, the server returns the message body in its preferred format (BodyHtml).

Note: Microsoft Graph generates the plain text body from the HTML body, even when the message contains a separate plain text body. To retrieve the original plain text body of the message, download the whole MIME message.

Message fields 

Many GraphClient methods make it possible to specify which message information to retrieve. These methods include GetMessageInfo(), GetMessageList(), Search(). It's recommended to only request the information you need - this can save a lot of time, bandwidth and processing power.

Use the GraphMessageFields argument to specify which information to retrieve:

Parameter value Description
GraphMessageFields.Default Default set of fields defined by Exchange Online (Microsoft 365) server. This is the default for methods with optional fields argument.
GraphMessageFields.Id Only retrieves the Exchange message ID.
GraphMessageFields.Subject Retrieves message subject.
GraphMessageFields.Body Retrieves message body (HTML if available, plain text otherwise).
GraphMessageFields.AttachmentInfo Retrieves information about attachments.
GraphMessageFields.Envelope Retrieves message ID and envelope info. This includes the most important fields such as Date, From, To, Subject, and Message-ID.
GraphMessageFields.Info Retrieves message ID, envelope info, attachment info and additional fields such as Importance, Flag, Categories, IsRead, and LastModifiedDate.

Note: These fields are bit flags, which means that combinations such as Envelope | Body are possible - use bitwise OR operator (| in C#, Or in VB.NET).

The following code shows how to combine multiple GraphMessageFields to get desired results:

// create Graph client instance, connect, log in
// ...

// get message envelope and attachment info
GraphMessageInfo message = client.GetMessageInfo(messageId,
    GraphMessageFields.Envelope | GraphMessageFields.AttachmentInfo);

// show some info about the message
Console.WriteLine("Subject: {0}", message.Subject);
Console.WriteLine("From: {0}", message.From);
Console.WriteLine("To: {0}", message.To);
if (message.HasAttachments)
{
    Console.WriteLine("Message has attachment(s).");
}

Back to feature list...