Skip to content

Email preview renders in Quirks Mode — DOCTYPE is lost in the dashboard iframe #5

Open

Description

@theChaosCoder

I wanted to show system emails in testing for my testers and noticed a rendering problem:

The HTML preview in the MailWeb dashboard renders emails slightly differently than mail clients (and than MailWeb's own share view). Typical symptoms are the classic Quirks Mode artifacts in table-based email layouts: small gaps below images, different line heights and table cell spacing.

Rendering in preview tab (wrong)
Image

Rendering via share button view (correct)
Image

Cause

In resources/js/components/EmailPreview.vue, updateIframe() parses the stored HTML with DOMParser and then writes emailDoc.documentElement.outerHTML into the iframe via document.write():

  const parser = new DOMParser();
  const emailDoc = parser.parseFromString(props.email.body_html, 'text/html');

  emailDoc.querySelectorAll('a').forEach((link) => {
      link.setAttribute('target', '_blank');
      link.setAttribute('rel', 'noopener noreferrer');
  });

  iframeDoc.open();
  iframeDoc.write(emailDoc.documentElement.outerHTML);
  iframeDoc.close();

documentElement.outerHTML only serializes the element — the declaration is dropped. A document written without a doctype renders in Quirks Mode, which changes layout behavior exactly in the ways email templates are
sensitive to (inline images on the text baseline, table spacing, etc.).

The public share view does not have this problem because email-share.blade.php passes the original HTML straight through:

blade
<iframe id="email-iframe" srcdoc="{{ $email->body_html }}"></iframe>

Steps to reproduce

  1. Send any email built with a table-based layout and a full header (e.g. a classic 600px transactional template with header images).
  2. Open it in the MailWeb dashboard → Preview tab.
  3. Compare with the share view of the same email (or with Mailpit/a mail client): the dashboard preview shows small rendering differences (image gaps, spacing).
  4. Inspect the preview iframe: document.compatMode is "BackCompat" (Quirks Mode) instead of "CSS1Compat".

Suggested fix

Serialize the doctype along with the document, or avoid the re-serialization entirely — e.g.:


  const doctype = emailDoc.doctype
      ? `<!DOCTYPE ${emailDoc.doctype.name}>`
      : '<!DOCTYPE html>';

  iframeDoc.open();
  iframeDoc.write(doctype + emailDoc.documentElement.outerHTML);
  iframeDoc.close();

Alternatively, bind the (link-rewritten) HTML to the iframe's srcdoc attribute, matching the behavior of the share view.

Activity

  1. added a commit that references this issue on Jul 25, 2026
    4691180
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions