Abrufen von Anlagen eines Outlook-Elements vom Server

Sie können die Anlagen eines Outlook-Elements auf verschiedene Arten abrufen, aber welche Option Sie verwenden, hängt von Ihrem Szenario ab.

  1. Senden Sie die Anlageninformationen an Ihren Remotedienst.

    Ihr Add-In kann die Anlagen-API verwenden, um Informationen zu den Anlagen an den Remotedienst zu senden. Der Dienst kann daraufhin direkt den Exchange-Server kontaktieren, um die Anlagen abzurufen.

  2. Verwenden Sie die getAttachmentContentAsync-API , die ab Anforderungssatz 1.8 verfügbar ist. Unterstützte Formate: AttachmentContentFormat.

    Diese API kann nützlich sein, wenn Microsoft Graph oder EWS nicht verfügbar ist (z. B. aufgrund der Administratorkonfiguration Ihres Exchange-Servers), oder Wenn Ihr Add-In den Base64-Inhalt direkt in HTML oder JavaScript verwenden möchte. Außerdem ist die getAttachmentContentAsync API in Erstellungsszenarien verfügbar, in denen die Anlage möglicherweise noch nicht mit Exchange synchronisiert wurde. Weitere Informationen finden Sie unter Verwalten der Anlagen eines Elements in einem Verfassenformular in Outlook .

In diesem Artikel wird die erste Option erläutert. Verwenden Sie die folgenden Eigenschaften und Methoden, um Anlageninformationen an den Remotedienst zu senden.

Verwenden der Anlagen-API

Führen Sie die folgenden Schritte aus, um die Anlagen-API zum Abrufen von Anlagen aus einem Exchange-Postfach zu verwenden.

  1. Zeigen Sie das Outlook-Add-In an, wenn eine Nachricht oder ein Termin eine Anlage enthält.

  2. Rufen Sie das Rückruftoken vom Exchange-Server ab.

  3. Senden Sie Rückruftoken und Anlageninformationen an den Remotedienst.

  4. Rufen Sie die Anlagen mithilfe der ExchangeService.GetAttachments-Methode oder des GetAttachment-Vorgangs vom Exchange-Server ab.

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.

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.

Abrufen eines Rückruftokens

Das Office.context.mailbox-Objekt stellt die getCallbackTokenAsync -Methode zum Abrufen eines Tokens bereit, das der Remoteserver für die Authentifizierung beim Exchange-Server verwenden kann. 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. Das Rückruftoken wird im Dienstanforderungsobjekt gespeichert, das im nächsten Abschnitt definiert wird.

function getAttachmentToken() {
    if (serviceRequest.attachmentToken == "") {
        Office.context.mailbox.getCallbackTokenAsync(attachmentTokenCallback);
    }
}

function attachmentTokenCallback(asyncResult) {
    if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
        // Cache the result from the server.
        serviceRequest.attachmentToken = asyncResult.value;
        serviceRequest.state = 3;
        testAttachments();
    } else {
        showToast("Error", "Couldn't get callback token: " + asyncResult.error.message);
    }
}

Senden von Anlageninformationen an den Remotedienst

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 ist der Remotedienst eine Web-API-Anwendung, die mit Visual Studio erstellt wurde. Die Anlageninformationen werden vom Remotedienst in einem JSON-Objekt erwartet. Der folgende Code dient zum Initialisieren eines Objekts mit den Anlageninformationen:

// Initialize a context object for the add-in.
//   Set the fields that are used on the request
//   object to default values.
 const 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. In den meisten Fällen kann das Add-In die Anlagen-ID-Eigenschaft eines AttachmentDetails-Objekts an den Remotedienst übergeben. Wenn der Remotedienst weitere Details zu der Anlage benötigt, können Sie das gesamte AttachmentDetails-Objekt oder einen Teil davon übergeben. Der folgende Code definiert eine Methode, die das gesamte AttachmentDetails-Array im serviceRequest-Objekt platziert und eine Anforderung an den Remotedienst sendet.

function makeServiceRequest() {
  // Format the attachment details for sending.
  for (let i = 0; i < mailbox.item.attachments.length; i++) {
    serviceRequest.attachments[i] = JSON.parse(JSON.stringify(mailbox.item.attachments[i]));
  }

  $.ajax({
    url: '../../api/Default',
    type: 'POST',
    data: JSON.stringify(serviceRequest),
    contentType: 'application/json;charset=utf-8'
  }).done(function (response) {
    if (!response.isError) {
      const names = "<h2>Attachments processed using " +
                    serviceRequest.service +
                    ": " +
                    response.attachmentsProcessed +
                    "</h2>";
      for (let 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-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:

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 Anlagen

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.

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 Anlagen

Wenn Sie EWS in Ihrem Remotedienst verwenden, müssen Sie eine GetAttachment-SOAP-Anforderung erstellen, um Anlagen vom Exchange-Server abzurufen. Der folgende Code gibt eine Zeichenfolge zurück, die die SOAP-Anforderung enthält. Der Remotedienst verwendet die String.Format-Methode, um die Anlage-ID für eine Anlage in die Zeichenfolge einzufügen.

private const string GetAttachmentSoapRequest =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""https://www.w3.org/2001/XMLSchema-instance""
xmlns:xsd=""https://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=""Exchange2016"" />
</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. Diese Implementierung führt eine separate Anforderung für jede Anlage aus und gibt die Anzahl verarbeiteter Anlagen zurück. Jede Antwort wird in einer separaten ProcessXmlResponse-Methode verarbeitet, die als Nächstes definiert wird.

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 response
    // 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. Diese Methode überprüft die Antwort auf Fehler. Wenn keine Fehler gefunden werden, werden die Dateianlagen und Elementanhänge verarbeitet. Die ProcessXmlResponse-Methode führt den größten Teil der Arbeit zum Verarbeiten der Anlage aus.

// 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 auch