Extrair uma entidade de uma mensagem de email usando o EWS no Exchange

Saiba como extrair informações do corpo de uma mensagem de email usando a API Gerenciada do EWS ou o EWS no Exchange.

Você pode usar a API Gerenciada do EWS ou o EWS para acessar os endereços, contatos, endereços de email, sugestões de reunião, números de telefone, tarefas e URLs que um servidor do Exchange extrai de mensagens de email. Em seguida, você pode usar essas informações para novos aplicativos ou sugerir ações de acompanhamento em aplicativos existentes. Por exemplo, se uma entidade de contato, sugestão de reunião ou sugestão de tarefa for identificada em um email, seu aplicativo poderá sugerir que um novo item com informações prepovoadas seja criado. Usando entidades extraídas, você pode capitalizar a intenção por trás dos dados e ajudar os usuários a integrar perfeitamente o conteúdo da mensagem de email em resultados acionáveis.

A extração de entidade para endereços, contatos, endereços de email, sugestões de reunião, números de telefone, tarefas e URLs já está integrada a todos os itens do repositório exchange. Se você estiver usando a API Gerenciada do EWS, a propriedade Item.EntityExtractionResult recuperará as entidades para você em uma chamada de método Item.Bind . Se você estiver usando o EWS, o elemento EntityExtractionResult receberá todas as entidades extraídas para você em uma chamada de operação GetItem . Depois de recuperar os resultados das entidades extraídas, você poderá percorrer cada coleção de entidades para coletar informações pertinentes. Por exemplo, se uma sugestão de reunião foi extraída, você poderá recuperar o assunto da reunião sugerido, a lista de participantes, a hora de início e a hora de término.

Tabela 1. Propriedades da API Gerenciada do EWS e elementos EWS que contêm entidades extraídas

Entidade extraída Propriedade API Gerenciada do EWS Elemento EWS
Endereços
EntityExtractionResult.Addresses
Endereços
Contatos
EntityExtractionResult.Contacts
Contatos
Emails
EntityExtractionResult.EmailAddresses
Emailaddresses
Sugestões de reunião
EntityExtractionResult.MeetingSuggestions
MeetingSuggestions
Telefones
EntityExtractionResult.PhoneNumbers
PhoneNumbers
Sugestões de tarefa
EntityExtractionResult.TaskSuggestions
TaskSuggestions
URLs
EntityExtractionResult.Urls
URLs

Como a extração de entidade depende do reconhecimento de linguagem natural, o reconhecimento de entidades pode ser não determinístico e o sucesso às vezes depende do contexto. Para demonstrar como o reconhecimento de linguagem natural funciona, os exemplos neste artigo usam o email a seguir como entrada.

From: Ronnie Sturgis

To: Sadie Daniels

Subject: Dinner party

Hi Sadie

Are you free this Friday at 7 to join us for a dinner party at our house?

We're at 789 International Blvd, St Paul MN 55104.

Our number is 612-555-0158 if you have trouble finding it.

Please RSVP to either myself or Mara (mara@contoso.com) before Friday morning. Best for you organics (http://www.bestforyouorganics.com) will be catering so we can fully enjoy ourselves!

Also, can you forward this to Magdalena? I don't have her contact information.

See you then!

Ronnie

Extrair todas as entidades de um email usando a API Gerenciada do EWS

O exemplo de código a seguir mostra como exibir todas as entidades extraídas pelo servidor, usando o método Item.Bind e enumerando por meio de cada uma das entidades extraídas e suas propriedades.

Este exemplo pressupõe que o serviço seja um objeto ExchangeService válido e que ItemId é a Id da mensagem de email para mover ou copiar.

public static void ExtractEntities(ExchangeService service, ItemId ItemId)
{
    // Create a property set that limits the properties returned 
    // by the Bind method to only those that are required.
    PropertySet propSet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.EntityExtractionResult);
    // Get the item from the server.
    // This method call results in an GetItem call to EWS.
    Item item = Item.Bind(service, ItemId, propSet);
    Console.WriteLine("The following entities have been extracted from the message:");
    Console.WriteLine(" ");
    // If address entities are extracted from the message, print the results.
    if (item.EntityExtractionResult != null)
    {
        if (item.EntityExtractionResult.Addresses != null)
        {
            Console.WriteLine("--------------------Addresses---------------------------");
            foreach (AddressEntity address in item.EntityExtractionResult.Addresses)
            {
                Console.WriteLine("Address: {0}", address.Address);
            }
            Console.WriteLine(" ");
        }
        // If contact entities are extracted from the message, print the results.
        if (item.EntityExtractionResult.Contacts != null)
        {
            Console.WriteLine("--------------------Contacts----------------------------");
            foreach (ContactEntity contact in item.EntityExtractionResult.Contacts)
            {
                Console.WriteLine("Addresses:       {0}", contact.Addresses);
                Console.WriteLine("Business name:   {0}", contact.BusinessName);
                Console.WriteLine("Contact string:  {0}", contact.ContactString);
                Console.WriteLine("Email addresses: {0}", contact.EmailAddresses);
                Console.WriteLine("Person name:     {0}", contact.PersonName);
                Console.WriteLine("Phone numbers:   {0}", contact.PhoneNumbers);
                Console.WriteLine("URLs:            {0}", contact.Urls);
            }
            Console.WriteLine(" ");
        }
        // If email address entities are extracted from the message, print the results.
        if (item.EntityExtractionResult.EmailAddresses != null)
        {
            Console.WriteLine("--------------------Email addresses---------------------");
            foreach (EmailAddressEntity email in item.EntityExtractionResult.EmailAddresses)
            {
                Console.WriteLine("Email addresses: {0}", email.EmailAddress);
            }
            Console.WriteLine(" ");
        }
        // If meeting suggestion entities are extracted from the message, print the results.
        if (item.EntityExtractionResult.MeetingSuggestions != null)
        {
            Console.WriteLine("--------------------Meeting suggestions-----------------");
            foreach (MeetingSuggestion meetingSuggestion in item.EntityExtractionResult.MeetingSuggestions)
            {
                Console.WriteLine("Meeting subject:  {0}", meetingSuggestion.Subject);
                Console.WriteLine("Meeting string:   {0}", meetingSuggestion.MeetingString);
                foreach (EmailUserEntity attendee in meetingSuggestion.Attendees)
                {
                    Console.WriteLine("Attendee name:    {0}", attendee.Name);
                    Console.WriteLine("Attendee user ID: {0}", attendee.UserId);
                }
                Console.WriteLine("Start time:       {0}", meetingSuggestion.StartTime);
                Console.WriteLine("End time:         {0}", meetingSuggestion.EndTime);
                Console.WriteLine("Location:         {0}", meetingSuggestion.Location);
            }
            Console.WriteLine(" ");
        }
        // If phone number entities are extracted from the message, print the results.
        if (item.EntityExtractionResult.PhoneNumbers != null)
        {
            Console.WriteLine("--------------------Phone numbers-----------------------");
            foreach (PhoneEntity phone in item.EntityExtractionResult.PhoneNumbers)
            {
                Console.WriteLine("Original phone string:  {0}", phone.OriginalPhoneString);
                Console.WriteLine("Phone string:           {0}", phone.PhoneString);
                Console.WriteLine("Type:                   {0}", phone.Type);
            }
            Console.WriteLine(" ");
        }
        // If task suggestion entities are extracted from the message, print the results.
        if (item.EntityExtractionResult.TaskSuggestions != null)
        {
            Console.WriteLine("--------------------Task suggestions--------------------");
            foreach (TaskSuggestion task in item.EntityExtractionResult.TaskSuggestions)
            {
                foreach (EmailUserEntity assignee in task.Assignees)
                {
                    Console.WriteLine("Assignee name:    {0}", assignee.Name);
                    Console.WriteLine("Assignee user ID: {0}", assignee.UserId);
                }
                Console.WriteLine("Task string:      {0}", task.TaskString);
            }
            Console.WriteLine(" ");
        }
        // If URL entities are extracted from the message, print the results.
        if (item.EntityExtractionResult.Urls != null)
        {
            Console.WriteLine("--------------------URLs--------------------------------");
            foreach (UrlEntity url in item.EntityExtractionResult.Urls)
            {
                Console.WriteLine("URL: {0}", url.Url);
            }
            Console.WriteLine(" ");
        }
    }
    // If no entities are extracted from the message, print the result.
    else if (item.EntityExtractionResult == null)
    {
        Console.WriteLine("No entities extracted");
    }
}

A saída a seguir é exibida no console.

The following entities have been extracted from the message:
 
--------------------Addresses---------------------------
Address: 789 International Blvd, St Paul MN 55104
 
--------------------Contacts----------------------------
Addresses:       
Business name:   
Contact string:  Mara (mara@contoso.com)
Email addresses: mara@contoso.com
Person name:     Mara
Phone numbers:   
URLs:            
 
--------------------Email addresses---------------------
Email addresses: mara@contoso.com
 
--------------------Meeting suggestions-----------------
Meeting subject:  dinner party
Meeting string:   Are you free this Friday at 7 to join us for a dinner party at our house?
Attendee name:    Ronnie Sturgis
Attendee user ID: ronnie@contoso.com
Attendee name:    Sadie Daniels
Attendee user ID: sadie@cntoso.com
Start time:       10/1/0104 2:00:00 PM
End time:         10/1/0104 2:30:00 PM
Location:         
 
--------------------Phone numbers-----------------------
Original phone string:  612-555-0158
Phone string:           6125550158
Type:                   Unspecified
 
--------------------Task suggestions--------------------
Assignee name:    Sadie Daniels
Assignee user ID: sadie@contoso.com
Task string:      Also, can you forward this to Magdalena?
 
--------------------URLs--------------------------------
URL: http://www.bestforyouorganics.com

Observe que todos os endereços, contatos, endereços de email, números de telefone, tarefas e URLs foram extraídos conforme o esperado. A sugestão da reunião, no entanto, é um pouco mais complexa. Observe que a hora de início e o horário de término da sugestão da reunião não são o que você pode esperar. A hora de início no email é "nesta sexta-feira às 7", mas o valor extraído para a hora de início é 10/1/0104 14:00:00 PM. Isso ocorre porque a hora de início e o tempo de término extraídos pelo servidor são datas codificadas. Para obter mais informações sobre como interpretar valores dateTime em sugestões de reunião, consulte [MS-OXCEXT]: Protocolo de Objeto de Mensagem de Extensão do Cliente.

Extrair todas as entidades de um email usando o EWS

O exemplo de código a seguir mostra como usar a operação GetItem e o elemento EntityExtractionResult para recuperar as entidades extraídas de um item.

Essa também é a solicitação XML enviada pela API Gerenciada do EWS quando você usa o método Bind para extrair todas as entidades de um email usando a API Gerenciada do EWS.

O valor do elemento ItemId é abreviado para legibilidade.

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages"
               xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types"
               xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013" />
  </soap:Header>
  <soap:Body>
    <m:GetItem>
      <m:ItemShape>
        <t:BaseShape>IdOnly</t:BaseShape>
        <t:AdditionalProperties>
          <t:FieldURI FieldURI="item:EntityExtractionResult" />
        </t:AdditionalProperties>
      </m:ItemShape>
      <m:ItemIds>
        <t:ItemId Id="sVC5AAA=" />
      </m:ItemIds>
    </m:GetItem>
  </soap:Body>
</soap:Envelope>

O servidor responde à solicitação GetItem com uma mensagem GetItemResponse que inclui um valor ResponseCode de NoError, o que indica que a mensagem de email foi recuperada com êxito. A resposta também inclui o EntityExtractionResult para cada entidade extraída.

O valor do elemento ItemId é abreviado para legibilidade.

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:ServerVersionInfo MajorVersion="15"
                         MinorVersion="0"
                         MajorBuildNumber="883"
                         MinorBuildNumber="10"
                         Version="V2_10"
                         xmlns:h="https://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns="https://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" />
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <m:GetItemResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages"
                       xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:GetItemResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:Items>
            <t:Message>
              <t:ItemId Id="sVC5AAA="
                        ChangeKey="CQAAABYAAAD32nSTjepyT63rYH17n9THAAAOOqJN" />
              <t:EntityExtractionResult>
                <t:Addresses>
                  <t:AddressEntity>
                    <t:Position>LatestReply</t:Position>
                    <t:Address>789 International Blvd, St Paul MN 55104</t:Address>
                  </t:AddressEntity>
                </t:Addresses>
                <t:MeetingSuggestions>
                  <t:MeetingSuggestion>
                    <t:Position>LatestReply</t:Position>
                    <t:Attendees>
                      <t:EmailUser>
                        <t:Name>Ronnie Sturgis</t:Name>
                        <t:UserId>ronnie@contoso.com</t:UserId>
                      </t:EmailUser>
                      <t:EmailUser>
                        <t:Name>Sadie Daniels</t:Name>
                        <t:UserId>sadie@contoso.com</t:UserId>
                      </t:EmailUser>
                    </t:Attendees>
                    <t:Subject>dinner party</t:Subject>
                    <t:MeetingString>Are you free this Friday at 7 to join us for a dinner party at our house?</t:MeetingString>
                    <t:StartTime>0104-10-01T19:00:00Z</t:StartTime>
                    <t:EndTime>0104-10-01T19:30:00Z</t:EndTime>
                  </t:MeetingSuggestion>
                </t:MeetingSuggestions>
                <t:TaskSuggestions>
                  <t:TaskSuggestion>
                    <t:Position>LatestReply</t:Position>
                    <t:TaskString>Also, can you forward this to Magdalena?</t:TaskString>
                    <t:Assignees>
                      <t:EmailUser>
                        <t:Name>Sadie Daniels</t:Name>
                        <t:UserId>sadie@contoso.com</t:UserId>
                      </t:EmailUser>
                    </t:Assignees>
                  </t:TaskSuggestion>
                </t:TaskSuggestions>
                <t:EmailAddresses>
                  <t:EmailAddressEntity>
                    <t:Position>LatestReply</t:Position>
                    <t:EmailAddress>mara@contoso.com</t:EmailAddress>
                  </t:EmailAddressEntity>
                </t:EmailAddresses>
                <t:Contacts>
                  <t:Contact>
                    <t:Position>LatestReply</t:Position>
                    <t:PersonName>Mara</t:PersonName>
                    <t:EmailAddresses>
                      <t:EmailAddress>mara@contoso.com</t:EmailAddress>
                    </t:EmailAddresses>
                    <t:ContactString>Mara (mara@contoso.com</t:ContactString>
                  </t:Contact>
                </t:Contacts>
                <t:Urls>
                  <t:UrlEntity>
                    <t:Position>LatestReply</t:Position>
                    <t:Url>http://www.bestforyouorganics.com</t:Url>
                  </t:UrlEntity>
                </t:Urls>
                <t:PhoneNumbers>
                  <t:Phone>
                    <t:Position>LatestReply</t:Position>
                    <t:OriginalPhoneString>612-555-0158</t:OriginalPhoneString>
                    <t:PhoneString>6125550158</t:PhoneString>
                    <t:Type>Unspecified</t:Type>
                  </t:Phone>
                </t:PhoneNumbers>
              </t:EntityExtractionResult>
            </t:Message>
          </m:Items>
        </m:GetItemResponseMessage>
      </m:ResponseMessages>
    </m:GetItemResponse>
  </s:Body>
</s:Envelope>

Observe que todos os endereços, contatos, endereços de email, números de telefone, tarefas e URLs foram extraídos conforme o esperado. A sugestão da reunião, no entanto, é um pouco mais complexa. Observe que a hora de início e o horário de término da sugestão da reunião não são o que você pode esperar. A hora de início no email era "nesta sexta-feira às 7", mas o valor extraído para a hora de início é 10/1/0104 14:00:00 pm. Isso ocorre porque a hora de início e o tempo de término extraídos pelo servidor são datas codificadas. Para obter mais informações sobre como interpretar valores dateTime em sugestões de reunião, consulte [MS-OXCEXT]: Protocolo de Objeto de Mensagem de Extensão do Cliente.

Confira também