Dark Mode Simulation
Simulate how email clients render your email in dark mode.
simulateDarkMode
Generates a dark mode variant of the transformed HTML for a specific client.
function simulateDarkMode(
html: string,
clientId: string
): { html: string; warnings: CSSWarning[] }Parameters
| Parameter | Type | Description |
|---|---|---|
html | string | Transformed HTML (output of transformForClient) |
clientId | string | Client ID to simulate dark mode for |
Returns
| Field | Type | Description |
|---|---|---|
html | string | HTML with dark mode CSS applied |
warnings | CSSWarning[] | Dark-mode-specific warnings |
Example
import { transformForClient, simulateDarkMode } from "@emailens/engine";
const transform = transformForClient(emailHtml, "gmail-web");
const darkMode = simulateDarkMode(transform.html, "gmail-web");
console.log(darkMode.warnings.length); // Dark-mode-specific issuesDark mode support by client
| Client | Dark mode | Behavior |
|---|---|---|
| Gmail Web | Yes | UI-only (no content inversion) |
| Gmail iOS | Yes | Full color inversion |
| Gmail Android | Yes | Partial color inversion |
| Outlook 365 | Yes | Partial color inversion |
| Outlook (New) | Yes | Partial color inversion |
| Outlook Classic | Yes | Full color inversion |
| Apple Mail (all) | Yes | Respects prefers-color-scheme; partial inversion if absent |
| Yahoo Mail | Yes | UI-only (no content inversion) |
| Samsung Mail | Yes | Respects prefers-color-scheme; partial inversion if absent |
| Thunderbird | Yes | Respects prefers-color-scheme (v140+); full inversion if absent |
For clients with UI-only dark mode (Gmail Web, Yahoo Mail), simulateDarkMode applies body wrapper styling but does not invert email content colors.
How simulation works
Emailens simulates dark mode by:
- Inverting light backgrounds to dark equivalents
- Adjusting text colors for contrast
- Checking for
prefers-color-scheme: darkmedia queries (clients that respect them skip forced inversion when present) - Applying client-specific dark mode behaviors (full vs partial inversion, UI-only darkening)
Grading contrast in the dark render
Simulating the render is half of it. checkDarkModeContrast(html) grades the
text contrast of the result, which is where the failure actually shows up.
There are two ways an email breaks in dark mode, and they need separate checks:
- Clients that force an inversion. Gmail Android inverts partially and
Gmail iOS fully, and they disagree: a colour just under Android's lightness
threshold is left alone there while the surface behind it is repainted.
checkDarkModeContrastruns both. - The email's own dark block.
checkDarkStylesContrastFromDom($)applies the email's@media (prefers-color-scheme: dark)rules the way Apple Mail, Superhuman and Thunderbird would. A dark block that repaints a card but does not re-colour the text sitting on it lands at 1:1, and no light-mode check can see it.
auditEmail merges both into report.darkContrast, deduplicated per element.
Note: Previews are simulated approximations rendered in Chromium. Actual rendering may differ in native email clients due to engine-specific quirks (e.g., Outlook's Word engine, Apple Mail's WebKit).