Email Accessibility Check (HTML email templates)
Pricing
Pay per usage
Email Accessibility Check (HTML email templates)
Batch-checks HTML email templates for machine-checkable accessibility problems: missing alt text, low colour contrast, missing lang and title, layout tables without role=presentation, heading jumps, vague link text, tiny or all-caps text. One row and one report per template.
Pricing
Pay per usage
Rating
0.0
(0)
Developer
Madrasco
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 hours ago
Last modified
Categories
Share
Check a batch of HTML email templates for accessibility problems a machine can verify. Give the actor template URLs, paste the HTML, or point it at a key-value store of uploaded .html files. For each template you get one dataset row (counts by severity and rule, plus every finding) and a readable HTML and Markdown report in the key-value store.
Each finding has a rule ID, a severity, a plain-English message, the element's CSS selector path, its line number and a snippet of the start tag, so you can find it in your template.
What it checks
| Rule ID | Severity | What it flags | Based on |
|---|---|---|---|
img-alt-missing | error | <img> with no alt attribute | WCAG 2.2 SC 1.1.1 |
img-spacer-alt | warning | Spacer or tracking image (1-2 px wide/high, or named like spacer.gif) whose alt is not empty | WCAG 2.2 SC 1.1.1 |
img-alt-filename | warning | Alt text that is a file name (IMG_0042.jpg) | WCAG 2.2 SC 1.1.1 |
link-no-name | error | Link with no text and only images with empty or missing alt | WCAG 2.2 SC 2.4.4 |
link-text-vague | warning | Link text such as "click here", "here", "read more", "learn more" | WCAG 2.2 SC 2.4.4 |
link-text-url | warning | Link text that is a bare URL | WCAG 2.2 SC 2.4.4 |
contrast-low | error | Text whose colour and background colour are both declared, with a contrast ratio below 4.5:1 (3:1 for large text: 24px, or 18.66px bold), computed with the WCAG 2.x relative-luminance formula | WCAG 2.2 SC 1.4.3 |
html-lang-missing | error | <html> without lang (or xml:lang) | WCAG 2.2 SC 3.1.1 |
title-missing | warning | No <title>, or an empty one | WCAG 2.2 SC 2.4.2 |
table-role-missing | warning | Table without role="presentation" (or none) that has no <th>, <caption> or summary, so it is treated as a layout table | WCAG 2.2 SC 1.3.1 |
heading-order | warning | Heading level that skips a level (<h1> then <h3>) | WCAG 2.2 SC 1.3.1 (practice check) |
font-size-small | warning | Text with a declared font size below 14px (configurable) | practice check, not a WCAG rule |
all-caps-text | warning | 20+ letters over 3+ words in capitals, typed or via text-transform: uppercase | practice check, not a WCAG rule |
preheader-missing | info | No hidden preheader text before the first visible text | practice check |
Styles are read from inline style attributes, <style> blocks (type, class, ID and descendant selectors, with specificity and !important), and legacy attributes (bgcolor, background, <font color size>, <body text>). Hidden text (display:none, zero font size, visibility:hidden, max-height:0 with overflow:hidden, mso-hide:all, aria-hidden) is skipped. Font size and visibility are inherited the way a browser inherits them, so text that sets its own size inside a font-size:0 wrapper (as MJML and hybrid layouts produce) is checked.
How we tested it: on 133 public open-source email templates from 8 GitHub repositories (28 of them MJML output), run 2026-09-26, the actor flagged low contrast in the same 99 templates as the open-source axe-core checker and found none in the same 34.
What it does not check
Each report has a Not checked section that counts what the actor could not assess in that template, for example:
- text over background images or gradients (contrast can't be measured from HTML);
- text whose colour or background is not declared (the email client's default applies; we don't guess);
- colours written as
hsl(),var()or other forms it can't resolve; @mediablocks (dark-mode and mobile styles) and complex selectors (pseudo-classes, attribute selectors);- external stylesheets (not fetched);
- text inside images and whether alt text is accurate (needs a person);
- whether a plain-text version is sent (that is set in your email platform, not in the HTML).
This actor does not certify WCAG conformance or legal compliance (for example under accessibility laws). It runs a fixed list of automated checks; many accessibility requirements need a person to judge, and email clients change how HTML is rendered.
Input
- Template URLs: links to raw HTML templates that work without a login. Private and local network addresses are refused; each download has a 30-second network timeout and a 5 MB limit by default.
- HTML templates (pasted): a JSON list of
{"name": "...", "html": "..."}objects, or plain HTML strings. - Key-value store with uploaded templates: pick a store from your account; every record whose key ends in
.html/.htmor whose content type is HTML is checked (or only the keys you list). - Include notes (default on), Minimum font size (default 14px), Maximum template size (default 5 MB).
Up to 500 templates per run.
Output
Dataset: one row per template (view "Templates"; view "Findings" shows one line per finding):
{"name": "newsletter.html", "source": "https://example.com/newsletter.html", "status": "checked","errors": 2, "warnings": 1, "infos": 0,"issuesByRule": {"contrast-low": 1, "img-alt-missing": 1, "link-text-vague": 1},"findings": [{"rule": "contrast-low", "severity": "error", "line": 19,"selector": "html > body > table > tr > td > p:nth-of-type(1)", "snippet": "<p class=\"muted\">","message": "Contrast 2.32:1 (#aaaaaa on #ffffff); needs 4.5:1 for normal text (16px).","text": "Low contrast grey text on white.", "contrastRatio": 2.32, "required": 4.5,"foreground": "#aaaaaa", "background": "#ffffff"}],"notChecked": [{"what": "text over background images (contrast not measurable)", "count": 1}],"reportKey": "001-newsletter.html", "reportUrl": "https://api.apify.com/v2/key-value-stores/.../records/001-newsletter.html"}
(Shortened example.) A template that can't be loaded gets a row with status load-failed and the reason.
Key-value store: NNN-<name>.html and NNN-<name>.md per template, and OUTPUT with run totals.
If your account's storage access is set to Restricted, the reportUrl link opens only while you are signed in to Apify; you can also open the reports from the run's Storage tab.
Privacy
Templates are loaded into the run, checked in memory and written only to your own Apify storage. Nothing is sent anywhere else. Pasted HTML is kept in the run input like any Apify input.
Support
Open an issue on the actor's Issues tab. This actor is built and maintained with AI assistance by Madrasco; a human owner can be reached on request through the Issues tab.