Export (0) Print
Expand All
2 out of 2 rated this helpful - Rate this topic

How to: Get attachments of an Outlook item from an Exchange server

apps for Office

Learn how a mail app can use a web service to get the attachments of an Outlook item that the user is currently viewing.

Last modified: April 01, 2014

Applies to: Exchange Online | Exchange Server 2013 | Exchange Server 2013 SP1 | Outlook 2013 SP1 | Outlook Web App | OWA for Devices

   Office.js: v1.0, v1.1

   Apps for Office manifests schema: v1.0, v1.1

A mail app cannot pass the attachments of a selected item directly to the remote service that runs on your server. Instead, the mail app can use the attachments API to send information about the attachments to the remote service. The service can then contact the Exchange Server directly to retrieve the attachments.

To send attachment information to the remote service, you use the following properties and function:

  • Office.context.mailbox.ewsUrl property — Provides the URL of Exchange Web Services (EWS) on the Exchange Server that hosts the mailbox. Your service uses this URL to call the GetAttachment EWS operation.

  • Office.context.mailbox.item.attachments property — Gets an array of AttachmentDetails objects, one for each attachment to the item.

  • Office.context.mailbox.getCallbackTokenAsync function — Makes an asynchronous call to the Exchange Server that hosts the mailbox to get an attachment token from the Exchange server.

To use the attachments API to get attachments from an Exchange Server mailbox, perform the following steps. Each of these steps is covered in detail in following sections using code from the Mail apps for Office: Get attachments from an Exchange server sample.

  1. Show the mail app when a message or appointment contains an attachment.

  2. Get the attachment callback token from the Exchange server.

  3. Send the attachment information to the remote service.

  4. Get the attachments from the Exchange Server by using the EWS GetAttachment operation.

Note Note

The code in these examples has been shortened to emphasize the attachment information. The sample contains additional code for authenticating the mail app with the remote server and managing the state of the request.

Show the mail app

You can use an ItemHasAttachment rule in the mail app manifest file to show your mail app when the selected item has attachments, as shown in the following example.

<Rule xsi:type="ItemHasAttachment" />

Get an attachment callback token

The Office.context.mailbox object provides the getCallbackTokenAsync function to get a token that the remote server uses to authenticate with the Exchange server. The following code shows a function that starts the asynchronous request to get the callback token, and the callback function that gets the response. The attachment callback token is stored in the service request object that is defined in the next section.

function getAttachmentToken() {
    if (serviceRequest.attachmentToken == "" {
        Office.context.mailbox.getCallbackTokenAsync(attachmentTokenCallback);
    }
};
function attachmentTokenCallback(asyncResult, userContext) {
    if (asyncResult.status === "success") {
        // Cache the result from the server.
        serviceRequest.attachmentToken = asyncResult.value;
        serviceRequest.state = 3;
        testAttachments();
    } else {
        showToast("Error", "Could not get callback token: " + asyncResult.error.message);
    }
};



Send attachment information to the remote service

The remote service that your mail app calls defines the specifics of how you should send the attachment information to the service. In this example, the remote service is a WCF service application created by using Visual Studio 2012. The remote service expects the attachment information in a JSON object. The following code initializes an object that contains the attachment information.

// Initialize a context object for the app.
//   Set the fields that are used on the request
//   object to default values.
serviceRequest = new Object();
serviceRequest.attachmentToken = "";
serviceRequest.ewsUrl = Office.context.mailbox.ewsUrl;
serviceRequest.attachments = new Array();

The Office.context.mailbox.item.attachments property contains a collection of AttachmentDetails objects, one for each attachment to the item. In most cases, the mail app can pass just the attachment ID property of an AttachmentDetails object to the remote service. If the remote service needs more details about the attachment, you can pass all or part of the AttachmentDetails object. The following code defines a method that puts the entire AttachmentDetails array in the serviceRequest object and sends a request to the remote service.

function makeServiceRequest() {
    xhr = new XMLHttpRequest();

    // Update the URL to point to your service location.
    xhr.open("POST", "https://localhost:44304/AttachmentService.svc/ProcessAttachments", true);

    xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    xhr.onreadystatechange = requestReadyStateChange;

    // Translate the attachment details into a form that matches the WCF service.
    for ( i = 0; i < Office.context.mailbox.item.attachments.length; i++) {
        serviceRequest.attachments[i] = JSON.parse(JSON.stringify(Office.context.mailbox.item.attachments[i].$0_0)); 
    }
    // Send the request. The response is handled in the requestReadyStateChange function.
    xhr.send(JSON.stringify(service.request));
};

Get the attachments from the Exchange server

Your remote service uses the EWS GetAttachment operation to retrieve attachments from the server. The WCF service application needs two objects to deserialize the JSON string into .NET Framework objects that can be used on the server. The following code shows the definitions of the deserialization objects.

using System.Runtime.Serialization;

namespace AttachmentsSample
{
    [DataContract]
    public class AttachmentServiceRequest
    {
        [DataMember(Name = "attachmentToken", IsRequired = true)]
        public string AttachmentToken { get; set; }

        [DataMember(Name = "emailAddress", IsRequired = false)]
        public string EmailAddress { get; set; }

        [DataMember(Name = "identityToken", IsRequired = true)]
        public string IdentityToken { get; set; }

        [DataMember(Name = "password", IsRequired = false)]
        public string Password { get; set; }

        [DataMember(Name = "state", IsRequired = true)]
        public int State { get; set; }

        [DataMember(Name = "ewsUrl", IsRequired = true)]
        public string EwsUrl { get; set; }

        [DataMember(Name = "attachments", IsRequired = true)]
        public AttachmentDetails[] Attachments { get; set; }

    }

    [DataContract]
    public class AttachmentDetails
    {
        [DataMember(Name = "attachmentType")]
        public string AttachmentType { get; set; }

        [DataMember(Name = "contentType")]
        public string ContentType { get; set; }

        [DataMember(Name="id")]
        public string Id { get; set; }

        [DataMember(Name = "isInline")]
        public bool IsInline { get; set; }

        [DataMember(Name = "name")]
        public string Name { get; set; }

        [DataMember(Name = "size")]
        public int Size { get; set; }
    }
}

You need to construct a GetAttachment SOAP request to get the attachments from the Exchange Server. The following code returns a string that provides the SOAP request. The remote service uses the String.Format method to insert the attachment ID for an attachment into the string.

        private const string GetAttachmentSoapRequest =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:t=""http://schemas.microsoft.com/exchange/services/2006/types"">
<soap:Header>
<t:RequestServerVersion Version=""Exchange2013"" />
</soap:Header>
  <soap:Body>
    <GetAttachment xmlns=""http://schemas.microsoft.com/exchange/services/2006/messages""
    xmlns:t=""http://schemas.microsoft.com/exchange/services/2006/types"">
      <AttachmentShape/>
      <AttachmentIds>
        <!-- Insert attachment ID with String.Format(GetAttachmentSoapRequest,<attachmentId>); -->
        <t:AttachmentId Id=""{0}""/>
      </AttachmentIds>
    </GetAttachment>
  </soap:Body>
</soap:Envelope>";

Finally, the following method does the work of using an EWS GetAttachment request to get the attachments from the Exchange Server. This implementation makes an individual request for each attachment, and returns the count of attachments processed.

    private int GetAttachmentsFromExchangeServer(AttachmentServiceRequest serviceRequest)
    {
    int processedCount = 0;

    foreach (AttachmentDetails attachment in serviceRequest.Attachments)
    {
        // Prepare a web request object.
        HttpWebRequest webRequest = WebRequest.CreateHttp(serviceRequest.EwsUrl);
        webRequest.Headers.Add("Authorization", string.Format("Bearer {0}", serviceRequest.AttachmentToken));
        webRequest.PreAuthenticate = true;
        webRequest.AllowAutoRedirect = false;
        webRequest.Method = "POST";
        webRequest.ContentType = "text/xml; charset=utf-8";

        // Construct the SOAP message for the GetAttchment operation.
        byte[] bodyBytes = Encoding.UTF8.GetBytes(string.Format(GetAttachmentSoapRequest, attachment.Id));
        webRequest.ContentLength = bodyBytes.Length;

        Stream requestStream = webRequest.GetRequestStream();
        requestStream.Write(bodyBytes, 0, bodyBytes.Length);
        requestStream.Close();

        // Make the request to the Exchange server and get the response.
        HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();

        // If the response is okay, create an XML document from the
        // response and process the request.
        if (webResponse.StatusCode == HttpStatusCode.OK)
        {
            Stream responseStream = webResponse.GetResponseStream();

            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(responseStream);

            // This method simply writes the XML document to the
            // trace output. Your service would perform its
            // processing here.
            Trace.Write(xmlDocument.InnerXml);

            // Close the response stream.
            responseStream.Close();
            webResponse.Close();

            processedCount++;
        }
    }

    return processedCount;
}

Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback

Community Additions

ADD
Show:
© 2014 Microsoft. All rights reserved.