Abrufen von Anlagen eines Outlook-Elements vom ServerGet attachments of an Outlook item from the server

Von einem Outlook-Add-In können die Anlagen eines Elements nicht direkt an den auf Ihrem Server ausgeführten Remotedienst übergeben werden. Stattdessen kann von dem Outlook-Add-In die Anlagen-API verwendet werden, um Informationen zu den Anlagen an den Remotedienst zu senden. Der Dienst kann daraufhin direkt den Exchange-Server kontaktieren, um die Anlagen abzurufen.An Outlook add-in cannot pass the attachments of a selected item directly to the remote service that runs on your server. Instead, the add-in 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.

Zum Senden von Anlageninformationen an den Remotedienst werden folgende Eigenschaften und die folgende Funktion verwendet:To send attachment information to the remote service, you use the following properties and function:

Verwenden der Anlagen-APIUsing the attachments API

Wenn Sie die Anlagen-API zum Abrufen von Anlagen aus einem Exchange-Postfach verwenden möchten, gehen Sie wie folgt vor:To use the attachments API to get attachments from an Exchange mailbox, perform the following steps:

  1. Zeigen Sie das Outlook-Add-In an, wenn eine Nachricht oder ein Termin eine Anlage enthält.Show the add-in when the user is viewing a message or appointment that contains an attachment.

  2. Rufen Sie das Rückruftoken vom Exchange-Server ab.Get the callback token from the Exchange server.

  3. Senden Sie Rückruftoken und Anlageninformationen an den Remotedienst.Send the callback token and attachment information to the remote service.

  4. Rufen Sie die Anlagen mithilfe der ExchangeService.GetAttachments-Methode oder des GetAttachment-Vorgangs vom Exchange-Server ab.Get the attachments from the Exchange server by using the ExchangeService.GetAttachments method or the GetAttachment operation.

Die einzelnen Schritte werden in den folgenden Abschnitten ausführlich und unter Verwendung von Code aus dem Beispiel Outlook-Add-in-JavaScript-GetAttachments erläutert.Each of these steps is covered in detail in the following sections using code from the Outlook-Add-in-JavaScript-GetAttachments sample.

Hinweis

Der Code in diesen Beispielen wurde gekürzt, um die Anlageninformationen hervorzuheben. Das Beispiel enthält zusätzlichen Code zum Authentifizieren des Outlook-Add-Ins beim Remoteserver sowie zum Verwalten des Anforderungszustands.The code in these examples has been shortened to emphasize the attachment information. The sample contains additional code for authenticating the add-in with the remote server and managing the state of the request.

Abrufen eines RückruftokensGet a callback token

Das Office.context.mailbox-Objekt stellt die getCallbackTokenAsync-Funktion bereit, um ein Token abzurufen, das der Remoteserver zum Authentifizieren beim Exchange-Server verwenden kann.The Office.context.mailbox object provides the getCallbackTokenAsync function to get a token that the remote server can use to authenticate with the Exchange server. Der folgende Code zeigt eine Funktion in einem Add-In, das die asynchrone Anforderung zum Abrufen des Rückruftokens startet, sowie die Rückruffunktion, die die Antwort abruft.The following code shows a function in an add-in that starts the asynchronous request to get the callback token, and the callback function that gets the response. Das Rückruftoken wird im Dienstanforderungsobjekt gespeichert, das im nächsten Abschnitt definiert wird.The 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 === "succeeded") {
        // 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);
    }
}

Senden von Anlageninformationen an den RemotedienstSend attachment information to the remote service

Die genaue Vorgehensweise zum Senden von Informationen an den Remotedienst ist abhängig davon, welcher Dienst von Ihrem Outlook-Add-In aufgerufen wird. In diesem Beispiel handelt es sich bei dem Remotedienst um eine mithilfe von Visual Studio 2013 erstellte Web-API-Anwendung. Die Anlageninformationen werden vom Remotedienst in einem JSON-Objekt erwartet. Der folgende Code dient zum Initialisieren eines Objekts mit den Anlageninformationen:The remote service that your add-in calls defines the specifics of how you should send the attachment information to the service. In this example, the remote service is a Web API application created by using Visual Studio 2013. 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 add-in.
//   Set the fields that are used on the request
//   object to default values.
 var serviceRequest = {
    attachmentToken: '',
    ewsUrl         : Office.context.mailbox.ewsUrl,
    attachments    : []
 };

Die Office.context.mailbox.item.attachments-Eigenschaft enthält eine Sammlung von AttachmentDetails-Objekten, und zwar eines für jede Anlage für das Element.The Office.context.mailbox.item.attachments property contains a collection of AttachmentDetails objects, one for each attachment to the item. In den meisten Fällen kann das Add-In die Anlagen-ID-Eigenschaft eines AttachmentDetails-Objekts an den Remotedienst übergeben.In most cases, the add-in can pass just the attachment ID property of an AttachmentDetails object to the remote service. Wenn der Remotedienst weitere Details zu der Anlage benötigt, können Sie das gesamte AttachmentDetails-Objekt oder einen Teil davon übergeben.If the remote service needs more details about the attachment, you can pass all or part of the AttachmentDetails object. Der folgende Code definiert eine Methode, die das gesamte AttachmentDetails-Array im serviceRequest-Objekt platziert und eine Anforderung an den Remotedienst sendet.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() {
  // Format the attachment details for sending.
  for (var i = 0; i < mailbox.item.attachments.length; i++) {
    serviceRequest.attachments[i] = JSON.parse(JSON.stringify(mailbox.item.attachments[i].$0_0));
  }

  $.ajax({
    url: '../../api/Default',
    type: 'POST',
    data: JSON.stringify(serviceRequest),
    contentType: 'application/json;charset=utf-8'
  }).done(function (response) {
    if (!response.isError) {
      var names = "<h2>Attachments processed using " +
                    serviceRequest.service +
                    ": " +
                    response.attachmentsProcessed +
                    "</h2>";
      for (i = 0; i < response.attachmentNames.length; i++) {
        names += response.attachmentNames[i] + "<br />";
      }
      document.getElementById("names").innerHTML = names;
    } else {
      app.showNotification("Runtime error", response.message);
    }
  }).fail(function (status) {

  }).always(function () {
    $('.disable-while-sending').prop('disabled', false);
  })
}

Abrufen der Anlagen vom Exchange-ServerGet the attachments from the Exchange server

Ihr Remotedienst kann entweder die verwaltete EWS API-Methode GetAttachments oder den EWS-Vorgang GetAttachment verwenden, um Anlagen vom Server abzurufen. Die Dienstanwendung benötigt zwei Objekte um die JSON-Zeichenfolge in .NET Framework-Objekte zu deserialisieren, die auf dem Server verwendet werden können. Der folgende Code zeigt die Definitionen der Deserialisierungsobjekte:Your remote service can use either the GetAttachments EWS Managed API method or the GetAttachment EWS operation to retrieve attachments from the server. The 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.

namespace AttachmentsSample
{
  public class AttachmentSampleServiceRequest
  {
    public string attachmentToken { get; set; }
    public string ewsUrl { get; set; }
    public string service { get; set; }
    public AttachmentDetails [] attachments { get; set; }
  }

  public class AttachmentDetails
  {
    public string attachmentType { get; set; }
    public string contentType { get; set; }
    public string id { get; set; }
    public bool isInline { get; set; }
    public string name { get; set; }
    public int size { get; set; }
  }
}

Verwenden der verwalteten EWS-API zum Abrufen der AnlagenUse the EWS Managed API to get the attachments

Wenn Sie die verwaltete EWS-API im Remotedienst einsetzen, können Sie die GetAttachments-Methode verwenden, die eine EWS-SOAP-Anforderung erstellt, sendet und empfängt, um die Anlagen abzurufen. Microsoft empfiehlt die verwaltete EWS-API, da sie weniger Codezeilen erfordert und eine intuitivere Benutzeroberfläche für EWS-Anrufe bereitstellt. Der folgende Code sendet eine Anforderung, um alle Anlagen abzurufen, und gibt die Anzahl und die Namen der verarbeiteten Anlagen zurück.If you use the EWS Managed API in your remote service, you can use the GetAttachments method, which will construct, send, and receive an EWS SOAP request to get the attachments. We recommend that you use the EWS Managed API because it requires fewer lines of code and provides a more intuitive interface for making calls to EWS. The following code makes one request to retrieve all the attachments, and returns the count and names of the attachments processed.

private AttachmentSampleServiceResponse GetAtttachmentsFromExchangeServerUsingEWSManagedApi(AttachmentSampleServiceRequest request)
{
  var attachmentsProcessedCount = 0;
  var attachmentNames = new List<string>();

  // Create an ExchangeService object, set the credentials and the EWS URL.
  ExchangeService service = new ExchangeService();
  service.Credentials = new OAuthCredentials(request.attachmentToken);
  service.Url = new Uri(request.ewsUrl);

  var attachmentIds = new List<string>();

  foreach (AttachmentDetails attachment in request.attachments)
  {
    attachmentIds.Add(attachment.id);
  }

  // Call the GetAttachments method to retrieve the attachments on the message.
  // This method results in a GetAttachments EWS SOAP request and response
  // from the Exchange server.
  var getAttachmentsResponse =
    service.GetAttachments(attachmentIds.ToArray(),
                            null,
                            new PropertySet(BasePropertySet.FirstClassProperties,
                                            ItemSchema.MimeContent));

  if (getAttachmentsResponse.OverallResult == ServiceResult.Success)
  {
    foreach (var attachmentResponse in getAttachmentsResponse)
    {
      attachmentNames.Add(attachmentResponse.Attachment.Name);

      // Write the content of each attachment to a stream.
      if (attachmentResponse.Attachment is FileAttachment)
      {
        FileAttachment fileAttachment = attachmentResponse.Attachment as FileAttachment;
        Stream s = new MemoryStream(fileAttachment.Content);
        // Process the contents of the attachment here.
      }

      if (attachmentResponse.Attachment is ItemAttachment)
      {
        ItemAttachment itemAttachment = attachmentResponse.Attachment as ItemAttachment;
        Stream s = new MemoryStream(itemAttachment.Item.MimeContent.Content);
        // Process the contents of the attachment here.
      }

      attachmentsProcessedCount++;
    }
  }

  // Return the names and number of attachments processed for display
  // in the add-in UI.
  var response = new AttachmentSampleServiceResponse();
  response.attachmentNames = attachmentNames.ToArray();
  response.attachmentsProcessed = attachmentsProcessedCount;

  return response;
}

Verwenden von EWS zum Abrufen von AnlagenUse EWS to get the attachments

Wenn Sie EWS in Ihrem Remotedienst verwenden, müssen Sie eine GetAttachment-SOAP-Anforderung erstellen, um Anlagen vom Exchange-Server abzurufen.If you use EWS in your remote service, you need to construct a GetAttachment SOAP request to get the attachments from the Exchange server. Der folgende Code gibt eine Zeichenfolge zurück, die die SOAP-Anforderung enthält.The following code returns a string that provides the SOAP request. Der Remotedienst verwendet die String.Format-Methode, um die Anlage-ID für eine Anlage in die Zeichenfolge einzufügen.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>
        <t:AttachmentId Id=""{0}""/>
      </AttachmentIds>
    </GetAttachment>
  </soap:Body>
</soap:Envelope>";

Schließlich verwendet die folgende Methode eine EWS-GetAttachment-Anforderung, um die Anlagen vom Exchange-Server abzurufen.Finally, the following method does the work of using an EWS GetAttachment request to get the attachments from the Exchange server. Diese Implementierung führt eine separate Anforderung für jede Anlage aus und gibt die Anzahl verarbeiteter Anlagen zurück.This implementation makes an individual request for each attachment, and returns the count of attachments processed. Jede Antwort wird in einer separaten ProcessXmlResponse-Methode verarbeitet, die als Nächstes definiert wird.Each response is processed in a separate ProcessXmlResponse method, defined next.

private AttachmentSampleServiceResponse GetAttachmentsFromExchangeServerUsingEWS(AttachmentSampleServiceRequest request)
{
  var attachmentsProcessedCount = 0;
  var attachmentNames = new List<string>();

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

    // Construct the SOAP message for the GetAttachment 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 reponse
    // and process the request.
    if (webResponse.StatusCode == HttpStatusCode.OK)
    {
      var responseStream = webResponse.GetResponseStream();

      var responseEnvelope = XElement.Load(responseStream);

      // After creating a memory stream containing the contents of the
      // attachment, this method writes the XML document to the trace output.
      // Your service would perform it's processing here.
      if (responseEnvelope != null)
      {
        var processResult = ProcessXmlResponse(responseEnvelope);
        attachmentNames.Add(string.Format("{0} {1}", attachment.name, processResult));

      }

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

    }
    // If the response is not OK, return an error message for the
    // attachment.
    else
    {
      var errorString = string.Format("Attachment \"{0}\" could not be processed. " +
        "Error message: {1}.", attachment.name, webResponse.StatusDescription);
      attachmentNames.Add(errorString);
    }
    attachmentsProcessedCount++;
  }

  // Return the names and number of attachments processed for display
  // in the add-in UI.
  var response = new AttachmentSampleServiceResponse();
  response.attachmentNames = attachmentNames.ToArray();
  response.attachmentsProcessed = attachmentsProcessedCount;

  return response;
}

Jede Antwort vom GetAttachment-Vorgang wird an die ProcessXmlResponse-Methode gesendet.Each response from the GetAttachment operation is sent to the ProcessXmlResponse method. Diese Methode überprüft die Antwort auf Fehler.This method checks the response for errors. Wenn keine Fehler gefunden werden, werden die Dateianlagen und Elementanhänge verarbeitet.If it doesn't find any errors, it processes file attachments and item attachments. Die ProcessXmlResponse-Methode führt den größten Teil der Arbeit zum Verarbeiten der Anlage aus.The ProcessXmlResponse method performs the bulk of the work to process the attachment.

// This method processes the response from the Exchange server.
// In your application the bulk of the processing occurs here.
private string ProcessXmlResponse(XElement responseEnvelope)
{
  // First, check the response for web service errors.
  var errorCodes = from errorCode in responseEnvelope.Descendants
                    ("{http://schemas.microsoft.com/exchange/services/2006/messages}ResponseCode")
                    select errorCode;
  // Return the first error code found.
  foreach (var errorCode in errorCodes)
  {
    if (errorCode.Value != "NoError")
    {
      return string.Format("Could not process result. Error: {0}", errorCode.Value);
    }
  }

  // No errors found, proceed with processing the content.
  // First, get and process file attachments.
  var fileAttachments = from fileAttachment in responseEnvelope.Descendants
                    ("{http://schemas.microsoft.com/exchange/services/2006/types}FileAttachment")
                        select fileAttachment;
  foreach(var fileAttachment in fileAttachments)
  {
    var fileContent = fileAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}Content");
    var fileData = System.Convert.FromBase64String(fileContent.Value);
    var s = new MemoryStream(fileData);
    // Process the file attachment here.
  }

  // Second, get and process item attachments.
  var itemAttachments = from itemAttachment in responseEnvelope.Descendants
                        ("{http://schemas.microsoft.com/exchange/services/2006/types}ItemAttachment")
                        select itemAttachment;
  foreach(var itemAttachment in itemAttachments)
  {
    var message = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}Message");
    if (message != null)
    {
      // Process a message here.
      break;
    }
    var calendarItem = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}CalendarItem");
    if (calendarItem != null)
    {
      // Process calendar item here.
      break;
    }
    var contact = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}Contact");
    if (contact != null)
    {
      // Process contact here.
      break;
    }
    var task = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}Tontact");
    if (task != null)
    {
      // Process task here.
      break;
    }
    var meetingMessage = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}MeetingMessage");
    if (meetingMessage != null)
    {
      // Process meeting message here.
      break;
    }
    var meetingRequest = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}MeetingRequest");
    if (meetingRequest != null)
    {
      // Process meeting request here.
      break;
    }
    var meetingResponse = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}MeetingResponse");
    if (meetingResponse != null)
    {
      // Process meeting response here.
      break;
    }
    var meetingCancellation = itemAttachment.Element("{http://schemas.microsoft.com/exchange/services/2006/types}MeetingCancellation");
    if (meetingCancellation != null)
    {
      // Process meeting cancellation here.
      break;
    }
  }

  return string.Empty;
}

Siehe auchSee also