简体   繁体   English

为什么GMail使用可报价打印的编码破坏带有最小化标记/ HTML的电子邮件的内联(CSS)样式?

[英]Why does GMail break inline (CSS) styles for an email with minified markup/HTML using quote-printable encoding?

I had an email that was getting clipped by GMail (around 120Kb in size — according to http://www.adestra.com/avoid-gmail-clipping-emails/ , GMail starts clippping the messages at 102Kb) 我收到一封电子邮件,该邮件已被GMail裁剪(大小约为120Kb,根据http://www.adestra.com/avoid-gmail-clipping-emails/,GMail开始以102Kb的速度裁剪邮件)

GMail剪辑电子邮件

To reduce the email size, I decided to try out both django-htmlmin and plain ol' re.sub(r'\\n\\s*(\\S)', r'\\1', email_html_content) (Modifying markup using regex is a discussion for another day). 为了减小电子邮件的大小,我决定尝试使用django-htmlmin和普通ol're.sub re.sub(r'\\n\\s*(\\S)', r'\\1', email_html_content) (使用regex修改标记是讨论另一天)。 Both these techniques resulted in 30%+ reduction in email size, but both solutions broke the rendering in GMail. 这两种技术都使电子邮件大小减少了30%以上,但是这两种解决方案都破坏了GMail中的呈现。 When inspecting the broken design using Dev Tools, it seems some of the elements are not getting any inline styles, apparently at random. 当使用开发工具检查损坏的设计时,似乎某些元素没有得到任何内联样式,显然是随机的。

GMail中的元素,没有任何内联样式

However, when I clicked on 'Show Original' to view the raw email, I'm seeing inline styles for the element. 但是,当我单击“显示原始”以查看原始电子邮件时,我看到该元素的内联样式。

原始电子邮件中可见的内联样式

When checking the raw email, I saw that it is encoded using the quote-printable format. 检查原始电子邮件时,我看到它是使用quote-printable格式编码的。 Which means, even though my entire email is just 1 line when minified, line breaks ( = in quote-printable format) are inserted automatically, as is visible in the picture above. 这意味着,即使我的电子邮件在最小化时只有1行,但也会自动插入换行符( =可打印报价的格式),如上图所示。 Some of these line breaks ( = characters at the end of the line) appear mid-attribute values, but the email client seems to be ignoring these breaks and I don't think they are cause of the broken rendering (even my original email with unminified markup had such line breaks, and it was being rendered fine — according to my reading, it the email spec that suggests lines have a maximum limit of 78(?) characters). 其中一些换行符( =行尾的字符)出现在属性值中间,但是电子邮件客户端似乎忽略了这些换行符,而且我也不认为这是导致渲染中断的原因(即使我的原始电子邮件带有未缩小的标记具有这样的换行符,并且可以很好地显示-根据我的阅读,这是电子邮件规范,建议换行的最大限制为78(?)个字符)。

Another pattern I saw in the raw email code was after a chunk of lines (each delimited by a = ), there seems to be a paragraph that is delimited by a =0D character. 我在原始电子邮件代码中看到的另一个模式是在一行行之后(每行都由a =分隔),似乎有一个段落由=0D字符分隔。 Each paragraph is not the same size and I'm cannot find any source on why these characters are being inserted in a one-line, minified markup email. 每个段落的大小都不相同,我找不到任何有关为什么将这些字符插入到一行的最小化标记电子邮件中的任何信息。 The paragraph pattern can be seen in the image below: 可以在下图中看到段落模式:

由<code> = 0D </ code>字符分隔的随机段落

Even this character is appearing mid-attribute value for certain tags and I think this might be the reason the rendering is breaking. 甚至对于某些标签,此字符也显示为中间属性值,我认为这可能是渲染中断的原因。 I got the rendering working again by using re.sub(r'\\n\\s*(\\S)', r'\\n\\1', email_body) instead of re.sub(r'\\n\\s*(\\S)', r'\\1', email_body) — ie each tag (opening or closing) on a separate line instead of mashing up everything in just one line. 我通过使用re.sub(r'\\n\\s*(\\S)', r'\\n\\1', email_body)而不是re.sub(r'\\n\\s*(\\S)', r'\\1', email_body) ,即每个标签(打开或关闭)都放在单独的一行中,而不是将所有内容都re.sub(r'\\n\\s*(\\S)', r'\\1', email_body)在一行中。 This increased the size of the email, but got rid of the =0D characters from appearing mid-attribute value. 这增加了电子邮件的大小,但是摆脱了中属性值出现时的=0D字符。 Now it is at the end of each line and the email is rendering fine. 现在在每一行的末尾,电子邮件呈现良好。

每个标签在单独的行上

So, my question is, how do I minify my email HTML and still produce an unbroken rendering within email clients? 因此,我的问题是,如何缩小电子邮件HTML并仍在电子邮件客户端中生成完整的渲染图? What is causing the broken rendering and how may I go about fixing it? 是什么导致渲染损坏,我该如何修复它?

I stumbled upon exactly the same problem, although I wasn't using any custom regex patterns for minifying html. 我偶然发现了完全相同的问题,尽管我没有使用任何自定义正则表达式模式来缩小html。

Turns out, the problem is that some html parsers (including gmail) have limitations for the line length of the html that is being sent. 事实证明,问题在于某些html解析器(包括gmail)对正在发送的html的行长有限制。

This article explains nicely what's going on. 本文很好地解释了正在发生的事情。 Just like you noticed the html parsers have their own ways of splitting long lines and creating new line breaks. 就像您注意到的html解析器有他们自己的方式来分割长行和创建新的换行符。 And these ways fail. 这些方法失败了。

So the solution is to minify you html emails in a way that keeps all your lines not longer than a specific length. 因此,解决方案是通过使所有行不超过特定长度的方式来最小化html电子邮件。

I've successfully used this html-minifier (actually I used gulp-htmlmin which uses the "html-minifier") passing { maxLineLength: 996 } as an option. 我已经成功地使用这个HTML-minifier (其实我用一口-htmlmin它采用“HTML-minifier”)经过{ maxLineLength: 996 }作为一个选项。

The emails are no longer broken :) 电子邮件不再损坏:)

There are many things that don't work in one or another email client and unfortunately this is much more common than in the browser world. 许多事情在一个或另一个电子邮件客户端中不起作用,但是不幸的是,这比浏览器世界中的更为普遍。 They are not supported as security precautions or because email client developers were lazy to implement their support. 不支持将它们用作安全预防措施,或者因为电子邮件客户端开发人员不愿意实现其支持。

I recommend to read https://www.campaignmonitor.com/css/ as a starting point to ensure that your email is going to be rendered correctly. 我建议您阅读https://www.campaignmonitor.com/css/作为起点,以确保您的电子邮件能够正确呈现。

I think I see what is causing your problems. 我想我明白是什么导致了您的问题。

In your file you have carriage return line feed line endings. 在您的文件中,您有回车换行符。

By doing re.sub(r'\\n\\s*(\\S)', r'\\1', email_html_content) you remove the line feeds but leave carriage returns intact, which in return get encoded in quoted printable encoding (=0D). 通过执行re.sub(r'\\n\\s*(\\S)', r'\\1', email_html_content)您删除了换行符,但保留了回车符,而回车符re.sub(r'\\n\\s*(\\S)', r'\\1', email_html_content)引号的可打印编码方式进行了编码(= 0D )。 These chars are causing your problems. 这些字符导致您的问题。 This is also why using re.sub(r'\\n\\s*(\\S)', r'\\n\\1', email_body) works. 这也是为什么使用re.sub(r'\\n\\s*(\\S)', r'\\n\\1', email_body)可以工作的原因。 The problems are caused by sole carriage return signs while carriage return - line feed pairs work ok. 问题是由回车时唯一的回车标志引起的-换行对工作正常。

If I understand your intention correctly to remove unnecessary white space you should modify the code to strip carriage return signs as well: 如果我正确理解了删除多余空格的意图,则还应该修改代码以去除回车符:

re.sub(r'\r\n\s*(\S)', r'\1', email_html_content)

This should reduce space and will not cause problems with interpreting the css file. 这将减少空间,并且不会在解释css文件时引起问题。

With that said, wouldn't it be better to improve the regex to something like that: 话虽如此,将正则表达式改进为类似的东西不是更好:

re.sub(r'\s*\r\n\s*', r'', email_html_content)

This works in this way: find any number of white space, carriage return line feed pair and any number of white space, and remove them, instead of find carriage return line feed pair, any number of white space and one non white space char and replace it with the char. 这是这样工作的:找到任意数量的空格,回车换行对和任意数量的空白,然后将它们删除,而不是查找任意回车对,任意数量的空白和一个非空白char和将其替换为char。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM