在浏览器中HTML看起来很好,但在电子邮件中却不行。

3
我在处理电子邮件编码时遇到了一些问题。我正在从磁盘读取HTML文件并通过Gmail发送它。当我在浏览器中打开HTML时,它看起来很好。当我从Visual Studio复制HTML字符串并将其保存为HTML文件时,它看起来很好。但是,当我收到电子邮件时,它包含了一堆无效字符。甚至列表符号也出错了!我确定这是一个编码问题,但该文件已编码为UTF-8,直到转换为RAW并通过Gmail发送之前都很好。

下面是处理过程。我们使用OpenXML SDK从docx中读取,然后使用HtmlConverter将文档保存为HTML。稍后,从文件中读取HTML,将其转换为RAW格式并通过GMail API发送。

下面是一些相关的代码片段:

这是使用HtmlConverter保存HTML文件的位置。

HtmlConverterSettings settings = new HtmlConverterSettings()
{
    AdditionalCss = "body { margin: 1cm auto; max-width: 20cm; padding: 0; }",
    FabricateCssClasses = true,
    RestrictToSupportedLanguages = false,
    RestrictToSupportedNumberingFormats = false,
};

XElement htmlElement = HtmlConverter.ConvertToHtml( wdWordDocument, settings );
var html = new XDocument(
    new XDocumentType( "html", null, null, null ),
    htmlElement );

var htmlString = html.ToString( SaveOptions.DisableFormatting );
File.WriteAllText( destFileName.FullName, htmlString, Encoding.UTF8 );

这里是读取存储的HTML并将其转换为通过Gmail发送的地方。(我们使用Mimekit进行转换。)
// Create the message using MimeKit/System.Net.Mail.MailMessage
MailMessage msg = new MailMessage();
msg.Subject = strEmailSubject; // Subject
msg.From = new MailAddress( strUserEmail ); // Sender
msg.To.Add( new MailAddress( row.email ) ); // Recipient
msg.BodyEncoding = Encoding.UTF8;
msg.IsBodyHtml = true; 

// We need to loop through our HTML Document and replace the images with a CID so that they will display inline
var vHtmlDoc = new HtmlAgilityPack.HtmlDocument();
vHtmlDoc.Load( row.file ); // Read the body, from HTML file
...
msg.Body = vHtmlDoc.DocumentNode.OuterHtml;

// Convert our System.Net.Mail.MailMessage to RAW with Base64 encoding for Gmail
MimeMessage mimeMessage = MimeMessage.CreateFromMailMessage( msg );

Google.Apis.Gmail.v1.Data.Message message = new Google.Apis.Gmail.v1.Data.Message();
message.Raw = Base64UrlEncode( mimeMessage.ToString() );
var result = vGMailService.Users.Messages.Send( message, "me" ).Execute();

这是我们如何进行base64编码的:

private static string Base64UrlEncode( string input )
{
var inputBytes = System.Text.Encoding.UTF8.GetBytes( input );
// Special "url-safe" base64 encode.
return Convert.ToBase64String( inputBytes )
                  .Replace( '+', '-' )
                  .Replace( '/', '_' )
                  .Replace( "=", "" );
}

这封电子邮件最终成为“Content-Type: multipart/mixed”,其中包含两种选择。其中一种是:
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

另一个是

Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

纯文本和HTML都包含类似=C3=A2=E2=82=AC=E2=84=A2的字符串,表示撇号,而HTML部分包含一个带有奇怪的“3D”字符的HTML头。

<meta charset=3D"UTF-8"><title></title><meta name=3D"Generator"=
 content=3D"PowerTools for Open XML">

在转换为Base64并发送之前,HTML中没有任何奇怪的内容。

你有什么想法这个问题可能是什么?这与UTF8和Mimekit有关吗?


我无法回答你的问题,但我会为你的努力点赞。 - adv12
你为什么要替换Base64字符串的部分内容?我不理解注释中“特殊的“url-safe” base64编码”的含义。 - Equalsk
你有检查过MimeKit的输出是否符合RFC 2822标准吗?因为Gmail API文档说如果你使用原始数据,那就需要这个标准。 - Alex Paven
@Equalsk,Base64编码字符串不安全,因为它们可以包含“+”和“/”字符。[https://dev59.com/Y2Ys5IYBdhLWcg3wBvf7#13195218] - mack
1
我怀疑该API是否使用URL通过参数接收数据。你不能仅仅从base64字符串中截取一些位。 - Equalsk
不要使用MimeMessage.ToString() - 您需要使用MimeMessage.WriteTo(Stream)将其写入MemoryStream或其他流中。ToString()方法使用iso-8859-1编码将整个消息转换为字符串,无论消息的文本部分使用什么编码(注意:每个文本部分可以使用不同的字符集)。 - jstedfast
2个回答

0
你的问题的答案是:没有问题。这只是原始数据的呈现方式,使用了quoted-printable编码。如果你发送邮件并查看其源代码,Gmail也会以此方式呈现它。

谢谢@brandon927,那么我该如何使文本在电子邮件中正确显示? - mack

0

以下是您的代码应该如何编写,以获取“原始”消息数据,以便与Google的API一起使用:

using (var stream = new MemoryStream ()) {
    message.WriteTo (stream);

    var buffer = stream.ToArray ();
    var base64 = Convert.ToBase64String (buffer)
        .Replace( '+', '-' )
        .Replace( '/', '_' )
        .Replace( "=", "" );

    message.Raw = base64;
}

正如brandon927所指出的那样,text/html邮件部分的内容已经进行了quoted-printable编码。这是一种MIME编码,用于传输以确保其适合7位ASCII范围内。

您需要解码才能获得原始HTML。

使用MimeKit,如果您使用mimeMessage.HtmlBody或者将表示text/html部分的强制转换为并访问


非常感谢 @jstedfast!上周我花了好几个小时在这个问题上。我用你的代码替换了 message.Raw = Base64UrlEncode( mimeMessage.ToString() ) 这一行,现在邮件在 Gmail 和我的邮件客户端中都能正确显示了。如果没有你,我可能永远也想不到这个解决方法。:) - mack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接