PreMailer.Net icon indicating copy to clipboard operation
PreMailer.Net copied to clipboard

HTML entities are decoded when using MoveCssInline

Open passledevelopers opened this issue 7 years ago • 5 comments

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?

passledevelopers avatar Sep 09 '16 10:09 passledevelopers

Follow the links in that link: https://github.com/milkshakesoftware/PreMailer.Net/issues/114

bastienJS avatar Sep 09 '16 20:09 bastienJS

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.

passledevelopers avatar Sep 12 '16 08:09 passledevelopers

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".

tlewis17 avatar Sep 28 '16 16:09 tlewis17

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.

tlewis17 avatar Sep 28 '16 17:09 tlewis17

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("&amp;");
                        break;
                    case '<':
                        Flush();
                        sb.Append("&lt;");
                        break;
                    case '>':
                        Flush();
                        sb.Append("&gt;");
                        break;
                    case ' ':
                        Flush();
                        sb.Append("&nbsp;");
                        break;

                    case 'ä':
                        Flush();
                        sb.Append("&auml;");
                        break;
                    case 'ö':
                        Flush();
                        sb.Append("&ouml;");
                        break;
                    case 'ü':
                        Flush();
                        sb.Append("&uuml;");
                        break;
                    case 'Ä':
                        Flush();
                        sb.Append("&Auml;");
                        break;
                    case 'Ö':
                        Flush();
                        sb.Append("&Ouml;");
                        break;
                    case 'Ü':
                        Flush();
                        sb.Append("&Uuml;");
                        break;
                    case 'ß':
                        Flush();
                        sb.Append("&szlig;");
                        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();
                }
            }
        }
    }
}

r-Larch avatar Apr 26 '21 12:04 r-Larch

Fixed presumably long time ago, verified in c51393b8f085c1905dfcc50122498dfc58ac6eb2

martinnormark avatar Dec 09 '22 23:12 martinnormark