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

Posted

技术标签:

【中文标题】HTML 在浏览器中看起来不错,但在电子邮件中却不行【英文标题】:HTML looks okay in browser but not in email 【发布时间】:2017-10-04 04:05:20 【问题描述】:

我在使用电子邮件编码时遇到了一些问题。我正在从磁盘读取 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 部分包含一个 HTML 标头,其中包含奇怪的“3D”字符.

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

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

任何想法可能是什么问题?这和 UTF8 和 Mimekit 有关系吗?

【问题讨论】:

我不能回答你的问题,但它得到了我的努力。 为什么要替换部分 Base64 字符串?我不明白Special "url-safe" base64 encode 的评论是什么意思。 您是否检查过 mimekit 的输出是否符合 RFC 2822?因为这就是 GMail API 文档所说的,如果您使用 Raw,则需要它。 @Equalsk,Base64 编码的字符串不是 URL 安全的,因为它们可以包含“+”和“/”字符。 [***.com/questions/13195143/… 我怀疑 API 使用 URL 来通过参数接收数据。您不能只从 base64 字符串中切出位。 【参考方案1】:

这是您的代码在获取“原始”消息数据以用于 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 mime 部分的内容已被引用-打印编码。这是一种用于传输的 MIME 编码,以确保它适合 7 位 ascii 范围。

您需要对此进行解码才能获得原始 HTML。

使用 MimeKit,如果您使用 mimeMessage.HtmlBody 或者如果您将表示 text/html 部分的 MimeEntity 转换为 TextPart 并访问 Text 属性,则可以为您完成此操作。

【讨论】:

非常感谢@jstedfast!我上周花了几个小时在这上面。我用您的代码替换了 message.Raw = Base64UrlEncode( mimeMessage.ToString() ) 行,现在电子邮件在 Gmail 和我的电子邮件客户端中正确显示。我可能永远也想不通。 :)【参考方案2】:

您的问题的答案是:没有问题。这就是 Raw 的呈现方式,quoted-printable 编码。如果您发送电子邮件并查看其来源,Gmail 也会以这种方式呈现它。

【讨论】:

谢谢@brandon927 那么我该如何让文本在电子邮件中正确显示呢?

以上是关于HTML 在浏览器中看起来不错,但在电子邮件中却不行的主要内容,如果未能解决你的问题,请参考以下文章

响应式网站在浏览器调整大小时看起来不错,但在真正的 ipad 中却很尴尬

NSToolbarItem 图像在运行的应用程序中看起来很糟糕,但在界面生成器中却没有

React 本机选择器在 android 中看起来不错,但在 ios 中很糟糕

代码签名错误,但在设置中看起来不错

UIButton 图像在 IB 中看起来不错,但在应用程序上显示时会被拉伸

字体在 iPhone X 中看起来很混乱,而在 iPhone 7 中看起来不错