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:
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.
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!