Questions have been sent to the developer community developercommunity.visualstudio.com/content/pro…

The Github repository involved: github.com/xiangyuecn/…

.NET developer community rich text editor is too difficult to use, or simple book editor is good, and then dig the gold layout is good, and finally like cnblog can modify the layout CSS.

It’s all bullshit. Get me a new one that looks good.

What went wrong

The function in question:

//https://source.dot.net/#System.Net.Mail/System/Net/Mail/SmtpClient.cs,966 //https://referencesource.microsoft.com/#System/net/System/Net/mail/SmtpClient.cs,892 void SendMailCallback(IAsyncResult  result) { ... // Notice the ServerSupportsEai, the allowUnicode parameter message.BeginSend(writer, DeliveryMethod! = SmtpDeliveryMethod.Network, ServerSupportsEai, new AsyncCallback(SendMessageCallback), result.AsyncState); . }Copy the code

ServerSupportsEai is located in the allowUnicode parameter. All places in SmtpClient that involve the allowUnicode argument, give the IsUnicodeSupported() return value. But this is the only exception.

Let’s see the IsUnicodeSupported function:

//https://referencesource.microsoft.com/#System/net/System/Net/mail/SmtpClient.cs,382 private bool IsUnicodeSupported() {if (DeliveryMethod = = SmtpDeliveryMethod.Net work) {/ / watch ServerSupportsEai and SmtpDeliveryFormat return here (ServerSupportsEai && (DeliveryFormat == SmtpDeliveryFormat.International)); } else { return (DeliveryFormat == SmtpDeliveryFormat.International); }}Copy the code

DeliveryFormat can be assigned, so let’s find out where ServerSupportsEai is evaluated:

//https://referencesource.microsoft.com/#System/net/System/Net/mail/smtpconnection.cs,280 internal void ParseExtensions(string[] extensions) { ... // If the server supports SMTPUTF8, If (string.pare (extension, 0, "SMTPUTF8", 0, 8, StringComparison.OrdinalIgnoreCase) == 0) { ((SmtpPooledStream)pooledStream).serverSupportsEai = true; }... }Copy the code

Resulting phenomenon

SendMailCallback is called by SmtpClient.SendAsync (SendMailAsync will call SendAsync), so the asynchronous operation is completely out of control by the DeliveryFormat parameter we set. Utf-8 content (such as Chinese) transcoding depends on the mood of the email server!!

DeliveryFormat SmtpClient object attribute assignment for SmtpDeliveryFormat. SevenBit, require E-mail using 7-bit ASCII format, and send by asynchronous method; Utf-8 content (such as Chinese) in the original Subject and attachment file name will be transcoded; But if EHLO returns SMTPUTF8, the SmtpClient object will send utF-8 without transcoding! The sent data content is inconsistent with the expected data content!!

The synchronous method Send is not affected by this.

The solution

The ServerSupportsEai in the SendMailCallback function should be supported with IsUnicodeSupported, and the Bug is resolved.

Affected version

  • .NET Framework 4.5-4.7.2 (latest version), estimated to be the full series
  • The latest version of.NET Core is also affected by this

A record of.net framework bugs found

DKIM signature function written after the test of many mailboxes, can pass the verification. However, the next day’s test found that no mailbox passed the verification, and the body part of the downloaded email source code was very different from the one saved locally, which was reflected in the email theme and attachment file name. The local code was Base64, and the downloaded Chinese characters.

The first problem is found in Outlook, their home will tell you whether the DKIM signature is correct. None of the mail sent directly locally has passed the signature verification, but it is ok to send through the email server. Contrast direct mail and server mail source code difference, found that the mailbox server does not have Chinese, direct hair inside the Chinese place is all Chinese.

It seems that there is something wrong with the Chinese part. Then try to change all the Chinese in the email into English and send it. After thinking about it, yesterday’s test seems to be all in English, because I wrote the content of the email once and basically will not change.

At this point, I feel that the Outlook server is doing something. Is the protocol used by the email server to send emails different from that used by our Smtp protocol? But I didn’t find anything relevant. Then test the QQ mailbox, netease, yeah.net, and caught the package looked at it and found that the switch SmtpClient. DeliveryFormat parameters, using SevenBit (this value as the default value) (in Chinese), encoding QQ mailbox no problem, netease has a problem; There is a problem with using International (Chinese does not code) QQ mailbox, but no problem with NetEase.

Packet capture Finds that when SevenBit is used, the Chinese part sends Base64 encoding to QQ mailbox, Sends Chinese content to NetEase, and saves Base64 encoding locally (the content is the same as that used in signing emails). The opposite is true with International. The signed data is inconsistent with the sent data, so no matter how you change this parameter, one of them is wrong.

Why is that? Refer to the.net source code, have a look at the coding part, found basically every involves a character encoding, send incoming allowUnicode parameters, all allowUnicode = SmtpClient IsUnicodeSupported (), but there is only one exception:

[omitted here, see above]

SendMailCallback is called by SmtpClient.SendAsync (SendMailAsync will call SendAsync), so the asynchronous operation is completely out of control by the DeliveryFormat parameter we set. Chinese transcoding or not completely depends on the mood of the email server!! The ServerSupportsEai in the function should be replaced with uniform IsUnicodeSupported, and the Bug is resolved.

But, we can’t get to this place, so the Hook, the SmtpClient. ServerSupportsEaiHook, if is SendMailCallback calls will return IsUnicodeSupported ().

But, DotNetDetour libraries can Hook the String. The Length attribute, but not HookSmtpClient. ServerSupportsEai attribute, don’t know what reason. Finally debugging tired of giving up.

Using smtpClient. Send at the end does not have this problem, and it replaces all asynchronous operations with synchronous ones, with much less code. After Bug repair is completed, DKIM signature verification can be passed when sending Emails in English and Chinese to Outlook, QQ and NetEase.