通过EWS发送邮件:架构验证:无效的子元素'Body'

时间:2021-06-19 06:19:11

I'm trying to send an e-mail from within a C++ application via a Microsoft Exchange 2010 server. For this, I use the EWS protocol using the library ews-cpp.

我正在尝试通过Microsoft Exchange 2010服务器从C ++应用程序中发送电子邮件。为此,我使用库ews-cpp使用EWS协议。

The following trivial example, based on the one from https://github.com/otris/ews-cpp/blob/master/examples/send_message.cpp, is failing (mail addresses and credentials stripped from my actual code):

基于https://github.com/otris/ews-cpp/blob/master/examples/send_message.cpp中的一个示例,以下简单示例失败(邮件地址和凭据从我的实际代码中删除):

#include <iostream>
#include <ews/ews.hpp>

struct {
    std::string domain = "mailserver";
    std::string username = "...";
    std::string password = "...";
    std::string server_uri = "https://mailserver/EWS/Exchange.asmx";
} env;

int main()
{
    ews::set_up();

    try
    {
        auto service = ews::service(env.server_uri, env.domain, env.username,
                                    env.password);
        service.set_request_server_version(ews::server_version::exchange_2010_sp2);

        auto message = ews::message();

        message.set_subject("Test mail from outer space");
        std::vector<ews::mailbox> recipients;

        recipients.push_back(ews::mailbox("..."));
        message.set_to_recipients(recipients);

        auto text = ews::body("This is a test.");
        message.set_body(text);

        service.create_item(message,
                            ews::message_disposition::send_and_save_copy);
    }
    catch (ews::schema_validation_error& exc)
    {
        std::cout << exc.what() << std::endl;
        std::cout << exc.violation() << std::endl;
    }

    ews::tear_down();
    return 0;
}

The raw SOAP request is as follows (indentation added by me):

原始SOAP请求如下(我添加的缩进):

<m:CreateItem MessageDisposition="SendAndSaveCopy">
  <m:Items>
    <t:Message>
      <t:Subject>Test mail from outer space</t:Subject>
      <t:ToRecipients>
        <t:Mailbox>
          <t:EmailAddress>...</t:EmailAddress>
        </t:Mailbox>
      </t:ToRecipients>
      <t:Body BodyType="Text">This is a test.</t:Body>
    </t:Message>
  </m:Items>
</m:CreateItem>

The function create_item throws an ews::schema_validation_error which is caught in the above code, printing:

函数create_item抛出一个ews :: schema_validation_error,它在上面的代码中被捕获,打印:

The request failed schema validation
The element 'Message' in namespace ‘http://schemas.microsoft.com/exchange/services/2006/types’ has invalid child element 'Body' in namespace 'http://schemas.microsoft.com/exchange/services/2006/types'. List of possible elements expected: 'CcRecipients, BccRecipients, IsReadReceiptRequested, IsDeliveryReceiptRequested, ConversationIndex, ConversationTopic, From, InternetMessageId, IsRead, IsResponseRequested, References, ReplyTo, ReceivedBy, ReceivedRepresenting' in Namespace 'http://schemas.microsoft.com/exchange/services/2006/types'.

In other words, EWS doesn't expect <t:Body> within <t:Message>.

换句话说,EWS不期望 中的 。

So, when leaving out that element in the SOAP request (comment out message.set_body(text)), the mail is sent smoothly. However, a mail without a body doesn't make much sense, does it?

因此,当在SOAP请求中省略该元素时(注释掉message.set_body(text)),邮件将被顺利发送。但是,没有身体的邮件没有多大意义,是吗?

I thought that the problem might be the fact that ews-cpp was written for Exchange 2013 (and that the schema changed between 2010 and 2013 in this regard). So I digged into the schema, which each Exchange server serves at /ews/types.xsd, to see if the schema allows such a child element.

我认为问题可能是ews-cpp是为Exchange 2013编写的(并且在这方面,模式在2010年和2013年之间发生了变化)。因此,我深入研究了每个Exchange服务器在/ews/types.xsd上运行的模式,以查看模式是否允许这样的子元素。

In the schema definition file, I found the definition of the type MessageType (which is the type of the Message element we are talking about):

在模式定义文件中,我找到了MessageType类型的定义(它是我们正在讨论的Message元素的类型):

<xs:complexType name="MessageType">
  <xs:complexContent>
    <xs:extension base="t:ItemType">
      <xs:sequence>
        <xs:element name="Sender" minOccurs="0" type="t:SingleRecipientType"/>
        <xs:element name="ToRecipients" type="t:ArrayOfRecipientsType" minOccurs="0"/>
        <xs:element name="CcRecipients" type="t:ArrayOfRecipientsType" minOccurs="0"/>
        <xs:element name="BccRecipients" type="t:ArrayOfRecipientsType" minOccurs="0"/>
        <xs:element name="IsReadReceiptRequested" type="xs:boolean" minOccurs="0"/>
        <xs:element name="IsDeliveryReceiptRequested" type="xs:boolean" minOccurs="0"/>
        <xs:element name="ConversationIndex" type="xs:base64Binary" minOccurs="0"/>
        <xs:element name="ConversationTopic" type="xs:string" minOccurs="0"/>
        <xs:element name="From" type="t:SingleRecipientType" minOccurs="0"/>
        <xs:element name="InternetMessageId" type="xs:string" minOccurs="0"/>
        <xs:element name="IsRead" type="xs:boolean" minOccurs="0"/>
        <xs:element name="IsResponseRequested" type="xs:boolean" minOccurs="0"/>
        <xs:element name="References" type="xs:string" minOccurs="0"/>
        <xs:element name="ReplyTo" type="t:ArrayOfRecipientsType" minOccurs="0"/>
        <xs:element name="ReceivedBy" type="t:SingleRecipientType" minOccurs="0"/>
        <xs:element name="ReceivedRepresenting" type="t:SingleRecipientType" minOccurs="0"/>
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>

As you can see, there is no Body child element, but MessageType is based on ItemType, which is defined as follows (excerpt):

如您所见,没有Body子元素,但MessageType基于ItemType,其定义如下(摘录):

<xs:complexType name="ItemType">
<xs:sequence>
    <xs:element name="MimeContent" type="t:MimeContentType" minOccurs="0"/>
    <xs:element name="ItemId" type="t:ItemIdType" minOccurs="0"/>
    <xs:element name="ParentFolderId" type="t:FolderIdType" minOccurs="0"/>
    <xs:element name="ItemClass" type="t:ItemClassType" minOccurs="0"/>
    <xs:element name="Subject" type="xs:string" minOccurs="0"/>
    <xs:element name="Sensitivity" type="t:SensitivityChoicesType" minOccurs="0"/>
    <xs:element name="Body" type="t:BodyType" minOccurs="0"/>
    <xs:element name="Attachments" type="t:NonEmptyArrayOfAttachmentsType" minOccurs="0"/>
    [...]
  </xs:sequence>
</xs:complexType>

As you can see, it accepts the Body element as a child.

如您所见,它接受Body元素作为子元素。

Note that the Subject element is also defined in the ItemType and not in MessageType, and that is accepted by EWS in the above code snippet.

请注意,Subject元素也在ItemType中定义,而不是在MessageType中定义,并且EWS在上面的代码片段中接受了它。

What might be the cause of this strange validation failure?

这种奇怪的验证失败可能是什么原因?

1 个解决方案

#1


0  

Found the solution myself:

自己找到解决方案:

For the element Message, which is based on Item according to the schema definition, EWS first expects all child elements for Item, followed by the Message-specific child elements.

对于根据模式定义基于Item的元素Message,EWS首先要求Item的所有子元素,然后是Message特定的子元素。

This sounds very insane (to me), but swapping <t:ToRecipients> and <t:Body> in the <t:Message> element indeed solved the problem.

这对我来说听起来非常疯狂,但是在 元素中交换 和 确实解决了这个问题。

I did this by swapping the two corresponding setters in my code:

我通过在代码中交换两个相应的setter来做到这一点:

    auto message = ews::message();


    // First, set properties of the general "item":

    message.set_subject("Test mail from outer space");

    auto text = ews::body("This is a test.");
    message.set_body(text);


    // Then, set properties of the concrete "message":

    std::vector<ews::mailbox> recipients;
    recipients.push_back(ews::mailbox("..."));
    message.set_to_recipients(recipients);

I'm not sure if this is a bug in ews-cpp, in EWS / Exchange server, or in the EWS schema definition.

我不确定这是ews-cpp,EWS / Exchange服务器或EWS架构定义中的错误。

#1


0  

Found the solution myself:

自己找到解决方案:

For the element Message, which is based on Item according to the schema definition, EWS first expects all child elements for Item, followed by the Message-specific child elements.

对于根据模式定义基于Item的元素Message,EWS首先要求Item的所有子元素,然后是Message特定的子元素。

This sounds very insane (to me), but swapping <t:ToRecipients> and <t:Body> in the <t:Message> element indeed solved the problem.

这对我来说听起来非常疯狂,但是在 元素中交换 和 确实解决了这个问题。

I did this by swapping the two corresponding setters in my code:

我通过在代码中交换两个相应的setter来做到这一点:

    auto message = ews::message();


    // First, set properties of the general "item":

    message.set_subject("Test mail from outer space");

    auto text = ews::body("This is a test.");
    message.set_body(text);


    // Then, set properties of the concrete "message":

    std::vector<ews::mailbox> recipients;
    recipients.push_back(ews::mailbox("..."));
    message.set_to_recipients(recipients);

I'm not sure if this is a bug in ews-cpp, in EWS / Exchange server, or in the EWS schema definition.

我不确定这是ews-cpp,EWS / Exchange服务器或EWS架构定义中的错误。