Skip to main content
Technology & EngineeringEmail Template346 lines

Dark Mode Email

Dark mode support patterns for email templates across major email clients

Quick Summary18 lines
You are an expert in implementing dark mode support for email templates across major email clients.

## Key Points

1. **Do nothing**: Accept client-side auto-inversion. Works if your design uses moderate colors.
2. **Defensive design**: Choose colors that look acceptable in both light and dark contexts without any media queries.
3. **Full dark mode targeting**: Use `prefers-color-scheme: dark` media queries plus Outlook-specific attribute selectors.
- Background: #ffffff (light) — may get inverted to ~#1a1a1a
- Text: #333333 — inverts to ~#cccccc (still readable)
- Accent: #5469d4 — mid-range blue survives inversion
- Secondary text: #525f7f — inverts to a light gray
- Avoid: pure black #000000 (stays black in some inversions)
- Avoid: very light grays (become nearly invisible on dark)
- Always include the `color-scheme: light dark` meta tags and CSS property. Without them, Apple Mail and Windows Mail will not activate your custom dark mode styles.
- Use class-based selectors inside `@media (prefers-color-scheme: dark)` — this is the most widely supported approach.
- Add `!important` to all dark mode overrides to ensure they take precedence over inline styles.
skilldb get email-template-skills/Dark Mode EmailFull skill: 346 lines
Paste into your CLAUDE.md or agent config

Dark Mode Email — Email Templates

You are an expert in implementing dark mode support for email templates across major email clients.

Core Philosophy

Overview

Dark mode in email is handled very differently from the web. Email clients apply dark mode in one of three ways: no change (respecting the original design), partial color inversion (auto-adjusting light backgrounds and dark text), or full inversion (reversing all colors). Since each client behaves differently and there is no universal standard, dark mode email support requires a combination of CSS media queries, strategic color choices, and defensive design.

Core Concepts

How Email Clients Handle Dark Mode

ClientBehaviorRespects prefers-color-scheme?
Apple Mail (macOS/iOS)Full supportYes
Outlook.com / Outlook appPartial color inversionPartial — targets [data-ogsc] and [data-ogsb]
Gmail (Android)Full color inversionNo
Gmail (iOS)No dark mode changesN/A
Gmail (web)No dark mode changesN/A
Yahoo MailPartial inversionNo
Windows MailRespects prefers-color-schemeYes

Three Levels of Dark Mode Strategy

  1. Do nothing: Accept client-side auto-inversion. Works if your design uses moderate colors.
  2. Defensive design: Choose colors that look acceptable in both light and dark contexts without any media queries.
  3. Full dark mode targeting: Use prefers-color-scheme: dark media queries plus Outlook-specific attribute selectors.

The color-scheme Meta Tag

Signal to email clients that your email supports dark mode:

<head>
  <meta name="color-scheme" content="light dark" />
  <meta name="supported-color-schemes" content="light dark" />
  <style>
    :root {
      color-scheme: light dark;
    }
  </style>
</head>

This tells clients like Apple Mail to allow your dark mode styles rather than applying their own inversion.

Implementation Patterns

Basic Dark Mode with Media Queries

<head>
  <meta name="color-scheme" content="light dark" />
  <meta name="supported-color-schemes" content="light dark" />
  <style>
    :root {
      color-scheme: light dark;
    }

    @media (prefers-color-scheme: dark) {
      /* Body and wrapper backgrounds */
      .email-bg {
        background-color: #1a1a2e !important;
      }
      .email-container {
        background-color: #16213e !important;
      }

      /* Text colors */
      .text-primary {
        color: #e0e0e0 !important;
      }
      .text-secondary {
        color: #a0a0b0 !important;
      }
      .text-heading {
        color: #ffffff !important;
      }

      /* Links */
      .link {
        color: #818cf8 !important;
      }

      /* Buttons — usually fine as-is if already using brand colors */
      .btn-primary {
        background-color: #6366f1 !important;
      }

      /* Borders and dividers */
      .divider {
        border-color: #2d2d44 !important;
      }

      /* Images */
      .logo-dark {
        display: block !important;
        max-height: none !important;
      }
      .logo-light {
        display: none !important;
        max-height: 0 !important;
      }
    }
  </style>
</head>

<body>
  <table role="presentation" class="email-bg" cellpadding="0" cellspacing="0" border="0" width="100%"
         style="background-color: #f6f9fc;">
    <tr>
      <td style="padding: 40px 16px;">
        <table role="presentation" class="email-container" cellpadding="0" cellspacing="0" border="0"
               width="600" style="max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px;">
          <tr>
            <td style="padding: 32px 40px;">
              <h1 class="text-heading" style="color: #1a1a1a; font-size: 22px; margin: 0 0 16px;">
                Your weekly summary
              </h1>
              <p class="text-primary" style="color: #333333; font-size: 16px; line-height: 24px;">
                Here's what happened this week.
              </p>
              <a class="link" href="https://example.com" style="color: #5469d4;">
                View full report
              </a>
            </td>
          </tr>
        </table>
      </td>
    </tr>
  </table>
</body>

Logo Swapping for Dark Mode

Provide a light logo for dark backgrounds:

<style>
  @media (prefers-color-scheme: dark) {
    .logo-light { display: none !important; max-height: 0 !important; overflow: hidden !important; }
    .logo-dark { display: block !important; max-height: none !important; }
  }
</style>

<!-- Light mode logo (default) -->
<img class="logo-light"
     src="https://example.com/logo-dark.png"
     alt="Company"
     width="150" height="40"
     style="display: block; border: 0;" />

<!-- Dark mode logo (hidden by default) -->
<img class="logo-dark"
     src="https://example.com/logo-light.png"
     alt="Company"
     width="150" height="40"
     style="display: none; max-height: 0; overflow: hidden; border: 0;" />

Outlook-Specific Dark Mode Targeting

Outlook apps use [data-ogsc] (text color override) and [data-ogsb] (background color override):

<style>
  /* Standard dark mode */
  @media (prefers-color-scheme: dark) {
    .dark-bg { background-color: #1a1a2e !important; }
    .dark-text { color: #e0e0e0 !important; }
  }

  /* Outlook app dark mode overrides */
  [data-ogsc] .dark-text {
    color: #e0e0e0 !important;
  }
  [data-ogsb] .dark-bg {
    background-color: #1a1a2e !important;
  }
</style>

Transparent PNG Trick for Images

Images with transparent backgrounds break on dark backgrounds. Add a subtle padding/background:

<style>
  @media (prefers-color-scheme: dark) {
    .img-padded {
      background-color: #ffffff !important;
      border-radius: 8px !important;
      padding: 8px !important;
    }
  }
</style>

<img class="img-padded"
     src="https://example.com/icon.png"
     alt="Feature icon"
     width="48" height="48"
     style="display: block; border: 0;" />

Defensive Color Palette

Choose colors that work reasonably in both light and dark contexts without any media query support:

<!--
  Defensive palette:
  - Background: #ffffff (light) — may get inverted to ~#1a1a1a
  - Text: #333333 — inverts to ~#cccccc (still readable)
  - Accent: #5469d4 — mid-range blue survives inversion
  - Secondary text: #525f7f — inverts to a light gray
  - Avoid: pure black #000000 (stays black in some inversions)
  - Avoid: very light grays (become nearly invisible on dark)
-->

<!-- Use medium-contrast colors that survive inversion -->
<td style="background-color: #ffffff; color: #333333;">
  <p style="font-size: 16px; line-height: 24px;">
    This text uses #333333 which inverts gracefully.
  </p>
  <p style="font-size: 14px; color: #525f7f;">
    Secondary text in #525f7f also inverts well.
  </p>
</td>

Full Template with Dark Mode

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta name="color-scheme" content="light dark" />
  <meta name="supported-color-schemes" content="light dark" />
  <title>Notification</title>
  <style>
    :root { color-scheme: light dark; }

    @media (prefers-color-scheme: dark) {
      .body-bg { background-color: #0f0f1a !important; }
      .card-bg { background-color: #1a1a2e !important; }
      .heading { color: #ffffff !important; }
      .body-text { color: #c8c8d4 !important; }
      .muted-text { color: #8888a0 !important; }
      .divider { border-color: #2a2a40 !important; }
      .footer-bg { background-color: #141428 !important; }
    }

    [data-ogsc] .heading { color: #ffffff !important; }
    [data-ogsc] .body-text { color: #c8c8d4 !important; }
    [data-ogsb] .card-bg { background-color: #1a1a2e !important; }
  </style>
</head>
<body style="margin: 0; padding: 0;">
  <table role="presentation" class="body-bg" cellpadding="0" cellspacing="0" border="0" width="100%"
         style="background-color: #f0f2f5;">
    <tr>
      <td style="padding: 40px 16px;">
        <table role="presentation" class="card-bg" cellpadding="0" cellspacing="0" border="0"
               width="600" style="max-width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; overflow: hidden;">
          <tr>
            <td style="padding: 32px 40px;">
              <h1 class="heading" style="margin: 0 0 12px; font-size: 22px; color: #1a1a1a; font-family: Helvetica, Arial, sans-serif;">
                New sign-in detected
              </h1>
              <p class="body-text" style="margin: 0 0 24px; font-size: 16px; line-height: 24px; color: #333333; font-family: Helvetica, Arial, sans-serif;">
                Your account was accessed from a new device. If this was you, no action is needed.
              </p>
              <table role="presentation" cellpadding="0" cellspacing="0" border="0">
                <tr>
                  <td style="border-radius: 4px; background-color: #ef4444;">
                    <a href="https://example.com/security"
                       style="display: inline-block; padding: 14px 32px; color: #ffffff; font-size: 16px; font-weight: bold; text-decoration: none; font-family: Helvetica, Arial, sans-serif;">
                      Secure My Account
                    </a>
                  </td>
                </tr>
              </table>
            </td>
          </tr>
          <tr>
            <td style="padding: 0 40px;">
              <hr class="divider" style="border: none; border-top: 1px solid #e6ebf1; margin: 0;" />
            </td>
          </tr>
          <tr>
            <td class="footer-bg" style="padding: 24px 40px;">
              <p class="muted-text" style="margin: 0; font-size: 12px; line-height: 18px; color: #8898aa; font-family: Helvetica, Arial, sans-serif;">
                This email was sent because a new login was detected. If you didn't sign in, please secure your account immediately.
              </p>
            </td>
          </tr>
        </table>
      </td>
    </tr>
  </table>
</body>
</html>

Best Practices

  • Always include the color-scheme: light dark meta tags and CSS property. Without them, Apple Mail and Windows Mail will not activate your custom dark mode styles.
  • Use class-based selectors inside @media (prefers-color-scheme: dark) — this is the most widely supported approach.
  • Add !important to all dark mode overrides to ensure they take precedence over inline styles.
  • Design your light mode with moderate contrast (avoid pure black #000000 and pure white #ffffff for text and backgrounds) so that automatic inversion by Gmail and Yahoo produces acceptable results.
  • Supply both a light-background and dark-background version of your logo.
  • Test in Apple Mail (full support), Outlook app (partial), and Gmail Android (auto-inversion) to cover the three major dark mode behaviors.
  • Use semi-transparent borders (border: 1px solid rgba(0,0,0,0.1)) where supported, as they adapt naturally to both light and dark backgrounds.
  • For images with transparent backgrounds, add a white or light background in dark mode to maintain visibility.

Common Pitfalls

  • Forgetting !important: Inline styles have higher specificity than <style> block rules. Dark mode styles without !important will be ignored.
  • Testing only in Apple Mail: Apple Mail has the best dark mode support. Designs that look perfect there can break in Outlook or auto-invert poorly in Gmail Android.
  • Using images for text content: When clients invert colors, images remain unchanged while surrounding colors shift. Text-as-image becomes unreadable against an inverted background.
  • Pure black backgrounds in dark mode: Using #000000 for dark mode backgrounds creates harsh contrast. Use dark grays like #1a1a2e or #16213e for a more comfortable reading experience.
  • Ignoring Gmail's auto-inversion: Gmail Android inverts colors automatically with no way to override. If your design uses unusual color combinations, test what the inversion produces.
  • Not providing a background color on images: Transparent PNGs (logos, icons) become invisible on dark backgrounds. Always set a fallback background.
  • Assuming @media works everywhere: Gmail web and many mobile Gmail contexts strip <style> blocks entirely. Your light mode design must be acceptable without any dark mode CSS.

Anti-Patterns

Over-engineering for hypothetical scale. Building for millions of users when you have hundreds adds complexity without value. Solve today's problems first.

Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide well wastes time and introduces unnecessary risk.

Premature abstraction. Creating elaborate frameworks and utilities before you have enough concrete cases to know what the abstraction should look like produces the wrong abstraction.

Neglecting error handling at boundaries. Internal code can trust its inputs, but system boundaries (user input, APIs, file I/O) require defensive validation.

Skipping documentation for obvious code. What is obvious to you today will not be obvious to your colleague next month or to you next year.

Install this skill directly: skilldb add email-template-skills

Get CLI access →