PreMailer.Net
PreMailer.Net copied to clipboard
HTML entities are decoded when using MoveCssInline
Hi, thanks for all your work on PreMailer.Net
When I use MoveCssInline, any HTML entities (such as ©
) get decoded (ie to the actual character ©
)
This is a problem, because some major email clients (eg Gmail) can't seem to display these decoded HTML entities, they just get display as question marks instead.
Am I getting something wrong?
Follow the links in that link: https://github.com/milkshakesoftware/PreMailer.Net/issues/114
I couldn't find a solution to the problem linked to from that issue, only someone saying that they had overcome the problem using HTMLAgilityPack. So I've done the same, calling
HtmlEntity.Entitize(input);
after using MoveCssInline.
Seems to be working, haven't really tested it thoroughly yet.
John.
Just a warning on the HTMLAgilityPack, I used that workaround and it turned into a disaster. Now HTMLAgilityPack is causing errors when it hits an invalid html entity.
http://htmlagilitypack.codeplex.com/workitem/31915
There is a patch for it but you won't get it from Nuget. It appears like HTMLAgilityPack is just not getting updated anymore. There are a number of patches by other users for the last 4 years still under "Being evaluated".
I did notice that the issue appears to be within AngleSharp. https://github.com/AngleSharp/AngleSharp/issues/396
At this point, I don't have any kind of working solution short of forking HTMLAgilityPack and fixing "The given key was not present in the dictionary" errors.
A working Solution could be a custom implementation of a HtmlFormatter
using var premailer = new PreMailer.Net.PreMailer(input);
var result = premailer.MoveCssInline(customFormatter: new MyHtmlFormatter());
public class MyHtmlFormatter : Ganss.XSS.HtmlFormatter /* <- HtmlSanitizer v5.0.376 */ {
/// <summary>
/// Escape Text with human readable escapes
/// </summary>
public override string Text(ICharacterData text) {
return Escape(text.Data);
static string Escape(string content) {
var sb = StringBuilderPool.Obtain();
var sb2 = StringBuilderPool.Obtain();
for (int index = 0; index < content.Length; ++index) {
switch (content[index]) {
case '&':
Flush();
sb.Append("&");
break;
case '<':
Flush();
sb.Append("<");
break;
case '>':
Flush();
sb.Append(">");
break;
case ' ':
Flush();
sb.Append(" ");
break;
case 'ä':
Flush();
sb.Append("ä");
break;
case 'ö':
Flush();
sb.Append("ö");
break;
case 'ü':
Flush();
sb.Append("ü");
break;
case 'Ä':
Flush();
sb.Append("Ä");
break;
case 'Ö':
Flush();
sb.Append("Ö");
break;
case 'Ü':
Flush();
sb.Append("Ü");
break;
case 'ß':
Flush();
sb.Append("ß");
break;
case '\r':
Flush();
sb.Append("\r");
break;
case '\n':
Flush();
sb.Append("\n");
break;
case '\t':
Flush();
sb.Append("\t");
break;
case '+':
Flush();
sb.Append("+");
break;
case '?':
Flush();
sb.Append("?");
break;
default:
sb2.Append(content[index]);
break;
}
}
Flush();
sb2.ToPool();
return sb.ToPool();
void Flush() {
if (sb2.Length > 0) {
sb.Append(HtmlEncoder.Default.Encode(sb2.ToString()));
sb2.Clear();
}
}
}
}
}
Fixed presumably long time ago, verified in c51393b8f085c1905dfcc50122498dfc58ac6eb2