MapiMessage Unicode translation

I am having an issue saving the body of a Chinese email. The text displays as corrupted junk characters (e.g., ÊN)Y b...) instead of the original Chinese text (今天我會寄...). How can I save it in Unicode while preserving the original text? I am using Aspose.Email.Mapi.

Hello @kumarpiyush01,

Thank you for reporting the issue.

To investigate this, could you please provide:

  1. A sample code snippet that demonstrates how you load and save the message body.
  2. A sample email file that reproduces the problem.

With both the code and the sample file, we will be able to verify the original character encoding and reproduce the issue on our side.

1. Sample code snippet

AsposeMApi.MapiMessage mailMessage = new AsposeMApi.MapiMessage();

XmlNode htmlNode = xmlDoc.SelectSingleNode("//htmlbody");
if (htmlNode != null && File.Exists(htmlNode.InnerText))
    body = ReadFileSafe(htmlNode.InnerText);

string ReadFileSafe(string path)
{
    if (!File.Exists(path))
        return string.Empty;
    byte[] bytes = File.ReadAllBytes(path);

    string content;

    if (bytes.Length >= 2)
    {
        if (bytes[0] == 0xFF && bytes[1] == 0xFE)
            content = Encoding.Unicode.GetString(bytes);
        else if (bytes[0] == 0xFE && bytes[1] == 0xFF)
            content = Encoding.BigEndianUnicode.GetString(bytes);
        else if (bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
            content = Encoding.UTF8.GetString(bytes);
        else
            content = Encoding.Default.GetString(bytes);
    }
    else
        content = Encoding.Default.GetString(bytes);

    return content;
}
string htmlBody = emlFields.Body;

mailMessage.SetBodyContent(htmlBody,BodyContentType.Html);

mailMessage.Save(EmlfilePath, SaveOptionsAspose.DefaultEml);

2. File content - html body

html.txt-> html body of the mail.

<font size="4">Hi Vincent,</font>
<ol type="1">
<li>
<li><font size="4">加價無法減免, 因為是拜託工廠上機的,量少他們也賺不了錢的</font>
<li><font size="4">報價單裡面有滿q'ty 2000yds沒有加價 </font>
<li><font size="4">GPW-190T 三款合併生產, </font><font size="4">第一个是本白后再印花。 後加工工艺也不一样,進的染厂都不同, 無法減少加價</font></ol>
<br>
<br>
<br>
<font size="4">Best regards,</font><br>
<br>
<font size="4">Angel Peng</font><br>
<br>
<font size="4">Globa Concep 繒貿國際有限公司</font><br>
<br>
<font size="4">2th Fl., 333 Lung Chiang Road, Taiwan </font><br>
<br>
<font size="4">Tel: 886 2 2507 2234 ext 24</font><br>
<b><font size="4" face="Calibri">寄件日期:</font></b><font size="4" face="Calibri"> </font><font size="4" face="Calibri">2025年9月18日 上午 09:17</font><br>
<b><font size="4" face="Calibri">主旨:</font></b><font size="4" face="Calibri"> </font><font size="4" face="Calibri">DSG surcharge</font><font size="4"> </font><br>
<font size="4"> </font><br>
<font face="sans-serif">Hi Angel,</font><font size="4"> </font><br>
<br>
<font face="sans-serif">附件為DSG 要下銷樣的dye lot surcharge明細,我有把你先前報給我的加價給客人,但Kirsten有意見。</font><font size="4"> </font><br>
<font face="sans-serif">我把需要你幫忙的部份寫在comment裡,再麻煩請幫忙問一下工廠。</font><font size="4"> </font><br>
<br>
<font face="sans-serif">另外,DSG 的case 未來將會由Whitney及LuLu接手處理,她們共同信箱為 r6@mail.tahhsin.com.tw</font><font size="4"> </font><br>
<font face="sans-serif">再麻煩好好照顧她們倆。</font><font size="4"> </font><br>
<br>
<br>
<font face="sans-serif">Thanks,</font><font size="4"> </font><br>
<br>
<font face="sans-serif">Vincent,</font><font size="4"> </font><a style="display: inline-block; text-align: center" href="" title="TH- DSG- 2025.xls"><img src="cid:Body.png@0.740" width="32" height="32" alt="TH- DSG- 2025.xls" border="0"> - TH- DSG- 2025.xls</a><a style="display: inline-block; text-align: center" href="" title="TH- DSG- 2025.xls"><img src="cid:Body.png@0.A86" width="32" height="32" alt="TH- DSG- 2025.xls" border="0"> - TH- DSG- 2025.xls</a><br>

Hello @kumarpiyush01,

Thank you for providing the sample code.

We will analyze the code and update you as soon as we have any findings or need additional information.

@kumarpiyush01,

Hello,

We reproduced your scenario using the latest Aspose.Email for .NET (25.x), and the good news is that the issue is not in Aspose.Email’s saving. The text is already corrupted before it reaches SetBodyContent, inside your ReadFileSafe method.

Your html.txt is UTF-8 without a BOM (the typical case). None of the BOM checks in ReadFileSafe match it, so it falls through to the last branch:

else
    content = Encoding.Default.GetString(bytes);

The behavior of Encoding.Default depends on the runtime:

  • .NET Framework 4.x → it is the system ANSI code page (e.g. 1252). Your UTF-8 bytes get mis-decoded here, producing the junk you see (ÊN)Y b…, åŠ åƒ¹…).
  • .NET Core / .NET 6/8 → it is always UTF-8, so the same code reads correctly.

So the Chinese text becomes mojibake the moment the file is read. SetBodyContent and Save then persist that already-broken string. We confirmed this at the byte level: the character (UTF-8 E5 8A A0) gets stored in the EML as =C3=A5=C5=A0 (mojibake) in the broken case, versus the correct =E5=8A=A0 when the file is read properly.

We also verified that changing the message code page (PR_INTERNET_CPID / PR_MESSAGE_CODEPAGE to 65001) makes no difference, confirming the save path is not the problem.

The fix

Please replace Encoding.Default with UTF-8 as the fallback. The simplest robust approach is to let a StreamReader detect a BOM and otherwise decode as UTF-8:

string ReadFileSafe(string path)
{
    if (!File.Exists(path)) return string.Empty;
    // Honors UTF-8/16/32 BOM if present; otherwise decodes as UTF-8 —
    // never the machine-dependent ANSI code page.
    using var reader = new StreamReader(path, new UTF8Encoding(false),
                                        detectEncodingFromByteOrderMarks: true);
    return reader.ReadToEnd();
}

With this change, your original SetBodyContent + Save(..., SaveOptions.DefaultEml) code preserves the Chinese text correctly and writes a proper UTF-8 EML on both .NET Framework and .NET Core/8.

(If any of your source files are genuinely legacy-encoded rather than UTF-8 — e.g. Big5 — decode those explicitly with their real code page, e.g. Encoding.GetEncoding(950). The point is that the source’s encoding matters, not the running machine’s default.)

Please give this a try and let us know if the issue persists.

Thank you.

converted.png (11.3 KB)

actualtext.png (5.3 KB)

BodyText.png (7.9 KB)

Thank you for the update.

We are working on .NET Framework 4.7.2. Please see the attachments (actualtext.png vs. converted.png). Aspose.Email for .NET is still failing to preserve the actual text during the conversion.

Please review the attached documents again. This is a critical blocker for us, so please resolve this issue as soon as possible.

Hi @kumarpiyush01
We were unable to reproduce the issue because the code you provided is incomplete, contains undeclared variables, and does not compile.

Instead, we’ve created a simple console application demonstrating the correct behavior of Aspose.Email for .NET Framework 4.7.2 using the text file you provided.

Please feel free to modify and extend our demo application to reproduce the issue you’re experiencing. Once we’re able to observe the issue on our end, we’ll do our best to help you resolve it.
ConsoleApp1.zip (6.5 KB)

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(path);

XmlNode htmlNode = xmlDoc.SelectSingleNode(“//htmlbody”);
XmlNode rtfNode = xmlDoc.SelectSingleNode(“//rtfbody”);
XmlNode plainNode = xmlDoc.SelectSingleNode(“//plainbody”);

string body = string.Empty;
string bodyType = “1”;
string bodyPath = string.Empty;

if (htmlNode != null && File.Exists(htmlNode.InnerText))
{
body = File.ReadAllText(htmlNode.InnerText);
bodyType = “2”;
}
else if (rtfNode != null && File.Exists(rtfNode.InnerText))
{

 body = File.ReadAllText(rtfNode.InnerText);
 bodyType = "3";

}
else if (plainNode != null && File.Exists(plainNode.InnerText))
{
Debugger($"plainNode {plainNode} ");// testing…
body = File.ReadAllText(plainNode.InnerText);
bodyType = “1”;
}

using AsposeMApi = Aspose.Email.Mapi;
AsposeMApi.MapiMessage mailMessage = new AsposeMApi.MapiMessage();

if (emlFields.BodyType == “2”) // HTML
{
string htmlBody = emlFields.Body;
mailMessage.SetBodyContent(htmlBody, Aspose.Email.Mapi.BodyContentType.Html);
}
else if (emlFields.BodyType == “3”) // RTF
{
mailMessage.SetBodyContent(emlFields.Body, Aspose.Email.Mapi.BodyContentType.Rtf);
}
else // PLAIN
{
mailMessage.SetBodyContent(emlFields.Body, Aspose.Email.Mapi.BodyContentType.PlainText);
}

//saveAs = 1 → Eml | saveAs = 2 → Msg
if (SaveType == 1)
{
mailMessage.Save(EmlfilePath, SaveOptionsAspose.DefaultEml);
}
else if(SaveType == 2)
{
mailMessage.Save(EmlfilePath, SaveOptionsAspose.DefaultMsg);
}

The issue still persist please analyze the code and resolve my issue related to unicode body.

@kumarpiyush01

We are still unable to reproduce the issue.

We do not know what emlFields is, and we do not have the data that you pass to the following code to set the message body:

string htmlBody = emlFields.Body;
mailMessage.SetBodyContent(htmlBody, Aspose.Email.Mapi.BodyContentType.Html);

If you are passing the html.txt file that you provided earlier, Aspose.Email works correctly. Please see the result in the sample project we attached above.

If you are using different input data, please provide a complete, compilable sample project (or at least the value of emlFields.Body ) so that we can reproduce the issue on our side.

Hi,

Thank you for your response.

To clarify, emlFields is our custom class that stores email properties such as Body, From, To, Subject, etc. The value assigned to emlFields.Body is extracted from the XML and populated using the following code:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(path);

XmlNode htmlNode = xmlDoc.SelectSingleNode(“//htmlbody”);
XmlNode rtfNode = xmlDoc.SelectSingleNode(“//rtfbody”);
XmlNode plainNode = xmlDoc.SelectSingleNode(“//plainbody”);

string body = string.Empty;
string bodyType = “1”;

if (htmlNode != null && File.Exists(htmlNode.InnerText))
{
body = File.ReadAllText(htmlNode.InnerText);
bodyType = “2”;
}
else if (rtfNode != null && File.Exists(rtfNode.InnerText))
{
body = File.ReadAllText(rtfNode.InnerText);
bodyType = “3”;
}
else if (plainNode != null && File.Exists(plainNode.InnerText))
{
body = File.ReadAllText(plainNode.InnerText);
bodyType = “1”;
}

After reading the content, we assign it to our email fields object:

emlFields.Body = body;
emlFields.BodyType = bodyType;

Later, we use:

mailMessage.SetBodyContent(emlFields.Body, Aspose.Email.Mapi.BodyContentType.Html);

(or RTF/PlainText depending on BodyType).

From our debugging, the body content appears correct immediately after File.ReadAllText() and before calling SetBodyContent(). However, after the EML/MSG is generated, the Unicode characters (Chinese text in our test case) appear corrupted.

@kumarpiyush01

If you pass the previously provided html.txt file, Aspose.Email works correctly. Please see the result in the sample project attached above.

Please provide a complete, compilable sample project with a specific input string for the SetBodyContent method that reproduces the issue, as we previously shared with you.