html-emailsvelteemail-clientsanitize

Sanitize email html body and increase zoom level HTML


I am making an email client for blind people (well, legally blind anyways), and I am trying to render the HTML body for the emails, in a safe way, but without losing the style of the original content. I also want all the content to have increased the size of everything, especially the text.


Solution

  • I would recommend using an iframe which can prevent script execution via the sandbox attribute. You can add additional styling to set a specific root font size, though this may not work as expected depending on the mail's own styling.

    <script>
        let mail = `
            <h1>Title</h1>
            Lorem ipsum dolor sit
            
            <!-- Svelte parser does not like additional script tags. -->
            <${''}script>alert('!')</${''}script>
        `;
        
        $: document = mail + `
            <style>
                html, body { font-size: 32px; }
            </style>
        `
    </script>
    
    <iframe srcdoc={document} title="Mail message" sandbox />
    
    <style>
        iframe {
            border: none;
            width: 100%;
            height: 100%;
        }
    </style>
    

    REPL

    As an alternative to the font size, the whole frame can be scaled up using a transform, its size has to be reduced proportionally:

    iframe {
        border: none;
        width: calc(100% / 2);
        height: calc(100% / 2);
        transform-origin: 0 0;
        transform: scale(2);
    }
    

    REPL


    If you need more direct access to the the generated content, e.g. via events, you can instead sanitize the HTML using one of the various libraries out there (e.g. xss or sanitize-html). The HTML can then be inserted using {@html ...}.

    To handle a click on a link, you can wrap the content in an element and handle the click there, checking whether the target was a link element.

    <script>
        let mail = `
            <h1>Title</h1>
            <a href="http://stackoverflow.com">Stack Overflow</a>
        `;
        
        function sanitize(html) {
            // Use some sanitizer package here
            return html;
        }
        
        function onClick(e) {
            if (e.target.tagName == 'A') {
                e.preventDefault();
                alert('Links to: ' + e.target.href);
            }
        }
    </script>
    
    <div class="container" on:click={onClick}>
        {@html sanitize(mail)}
    </div>
    
    <style>
        .container {
            border: none;
            width: calc(100% / 2);
            height: calc(100% / 2);
            transform-origin: 0 0;
            transform: scale(2);
        }
    </style>
    

    (Sanitization omitted, because the mentioned packages are not compatible with the REPL.)

    REPL