Search code examples
c#emailexchange-servermailkitexchange-server-2013

Prevent Exchange 2013 from converting message body text/plain to HTML


I'm using MailKit v2.8 to parse data out of emails in using IMAP to connect to a Microsoft Exchange 2013 account. The body of messages being sent to my Exchange inbox will be "text/plain" 100% of the time. This process works completely fine for new emails (and has been in production use for a couple months), however replies/forwards to those emails are being converted to HTML presumably by Exchange when fetching. The header of the reply email on the server still specifies that the message body is "text/plain." Outlook also displays the response in plain text, but for some reason when I try to fetch the TextPart of the message summary using MailKit, it is returning null.

MailKit email fetching code:

using var imap = new ImapClient {
    ServerCertificateValidationCallback = (mySender, cert, chain, sslPolicyErrors) => { return true; },
    CheckCertificateRevocation = false
};

try {
    await imap.ConnectAsync(_config.ImapServer, _config.ImapPort, SecureSocketOptions.SslOnConnect);
    imap.AuthenticationMechanisms.Remove("XOAUTH2");
    await imap.AuthenticateAsync(_config.ImapUsername, _config.ImapPassword);
    var inbox = imap.Inbox;

    if (!string.IsNullOrWhiteSpace(_config.Inbox)) { // set inbox to subfolder for devenv
        inbox = await imap.Inbox.GetSubfolderAsync(_config.Inbox);
    }
    await inbox.OpenAsync(FolderAccess.ReadWrite);
    var uIds = await inbox.SearchAsync(SearchQuery.All);
    var msgs = await inbox.FetchAsync(uIds, MessageSummaryItems.UniqueId | MessageSummaryItems.BodyStructure | MessageSummaryItems.Envelope);

    foreach (var msg in msgs) {
        var bodyPart = msg.TextBody; // <-- this returns null for the latter email, but contains a body for the former
        var body = await inbox.GetBodyPartAsync(msg.UniqueId, bodyPart) as TextPart;
        if (_config.SendingAddresses.Any(msg.Envelope.From.Mailboxes.Select(a => a.Address).Contains)) { // sent from valid address
            // parse and process email body
        } else {
            // discard and expunge
        }
    }
} catch (Exception e) {
    // log exception
}

For brevity, here's an example. This email contains a TextBody when fetched using MailKit:

Received: from [ExchangeHost] ([ExchangeIP]) by [ExchangeHost]
 ([ExchangeIP]) with Microsoft SMTP Server (TLS) id 15.0.1320.4; Thu, 6 Aug 2020
 17:30:12 -0400
Received: from [SenderHost] ([SenderIP]) by
 [ExchangeHost] ([ExchangeIP]) with Microsoft SMTP Server id 15.0.1320.4
 via Frontend Transport; Thu, 6 Aug 2020 17:30:11 -0400
IronPort-SDR: [redacted]
X-IronPort-AV: [redacted]
X-AuditID: [redacted]
MIME-Version: 1.0
Message-ID: <[redacted]>
From: <[SenderAddr1]>
To: <[MyExchangeAddr]>
Date: Thu, 6 Aug 2020 14:30:03 -0700
Subject: [redacted]
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
Return-Path: [SenderAddr1]
X-MS-Exchange-Organization-AuthSource: [ExchangeHost]
X-MS-Exchange-Organization-AuthAs: Anonymous
X-GFI-SMTP-Submission: 1
X-GFI-SMTP-HelloDomain: [SenderHost]
X-GFI-SMTP-RemoteIP: [SenderIP]
X-MS-Exchange-Organization-Network-Message-Id: [redacted]
X-MS-Exchange-Organization-AVStamp-Enterprise: 1.0

This email header is a reply to the aforementioned email. When fetched in MailKit, it did not have a TextBody, but rather it had an HtmlBody:

Received: from [ExchangeHost] ([ExchangeIP]) by [ExchangeHost]
 ([ExchangeIP]) with Microsoft SMTP Server (TLS) id 15.0.1320.4 via Mailbox
 Transport; Mon, 10 Aug 2020 11:27:16 -0400
Received: from [ExchangeHost] ([ExchangeIP]) by [ExchangeHost]
 ([ExchangeIP]) with Microsoft SMTP Server (TLS) id 15.0.1320.4; Mon, 10 Aug 2020
 11:27:16 -0400
Received: from [SenderHost] ([SenderIP]) by
 [ExchangeHost] ([ExhcangeIP]) with Microsoft SMTP Server id 15.0.1320.4
 via Frontend Transport; Mon, 10 Aug 2020 11:27:15 -0400
IronPort-SDR: [redacted]
X-IronPort-AV: [redacted]
From: <[SenderAddr2]>
To: <[MyExchangeAddr]>, <[SenderAddr1]>
Subject: RE: [redacted]
Thread-topic: [redacted]
Thread-index: [redacted]
Date: Mon, 10 Aug 2020 15:27:07 +0000
Message-ID: <[redacted]>
References: <[redacted]>
In-Reply-To: <[redacted]>
Accept-Language: en-US
Content-Language: en-US
X-MS-Has-Attach:
X-MS-TNEF-Correlator:
x-ms-exchange-messagesentrepresentingtype: 1
x-ms-exchange-transport-fromentityheader: Hosted
x-tm-snts-smtp: [redacted]
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
Return-Path: [SenderAddr2]
X-GFI-SMTP-Submission: 1
X-GFI-SMTP-HelloDomain: [SenderHost]
X-GFI-SMTP-RemoteIP: [SenderIP]
X-MS-Exchange-Organization-Network-Message-Id: [redacted]
X-MS-Exchange-Organization-AVStamp-Enterprise: 1.0
X-Auto-Response-Suppress: DR, OOF, AutoReply
X-MS-Exchange-Organization-AuthSource: [ExchangeHost]
X-MS-Exchange-Organization-AuthAs: Anonymous

The HTMLBody of the latter email from MailKit:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Exchange Server">
<!-- converted from text -->
<style><!-- .EmailQuote { margin-left: 1pt; padding-left: 4pt; border-left: #800000 2px solid; } --></style>
</head>
<body>
<!-- the stuff that should be in plain text, formatted as HTML -->
</body>
</html>

In Outlook, that latter email is formatted in plain text, just like the Content-Type of its header specifies. Since the message is properly formatted in Outlook, my question is either:

  1. is there something I need to do when using MailKit to prevent this conversion from happening?
  2. (as I suspect is more likely) is there some option my sysadmin needs to set for the Exchange account to prevent this automatic conversion from occurring?

I've read the solutions here and in other topics, but none of them appear to be applicable today as any question asked on this topic is nearly a decade old.


Solution

  • So, I discovered that the reason for Exchange acting up was because I was duplicating the emails I was receiving for testing purposes. Despite the duplicated emails having IDENTICAL headers, Exchange was converting only the copied ones to HTML when being fetched using MailKit. The originals are being fetched as expected, however. For future reference to anyone, do not copy/paste emails in your inbox if you are expecting it to retain its plain text!