DEV Community

Cover image for Resizing Images for Email Campaigns: A Frontend Engineer’s Playbook
Tea-sip for Lizely

Posted on

Resizing Images for Email Campaigns: A Frontend Engineer’s Playbook

Email clients are the most hostile rendering environment most web engineers will touch this year. Outlook on Windows ignores CSS background images, Gmail strips <style> blocks from forwarded messages, Apple Mail ignores height on img if the source has a fixed width attribute, and every mobile client downsamples differently. Resize an image the wrong way and your carefully designed newsletter lands in the inbox looking like a captcha. Resize it the right way and it survives all of it.

This article is the playbook I wish I’d had when I inherited a transactional email pipeline that was shipping 1.4 MB JPEGs into a user base where 60% read on mobile networks. I’ll cover the sizing decisions, the HTML constraints, and the QA loop that catches regressions before they reach production.

Why Email Forces Different Rules Than the Web

The web has progressive enhancement. Email has progressive degradation: every client is the worst client. The HTML Living Standard treats <img> as a replaced element with intrinsic dimensions, but most email clients pre-process the markup, rewrite the DOM, and sometimes re-encode images before display. The result is that your pixel-perfect mockup in Litmus or Email on Acid is not the same pipeline your recipient sees.

A few constraints shape every decision below:

  • Outlook (Word rendering engine) still re-proxies images through a CDN and can recompress them. Sending a noisy JPEG gives it permission to make things worse.
  • Gmail’s web client strips images that are not https://, or that have a src attribute longer than ~2,000 characters. Every query string on a resizing CDN costs you headroom.
  • Apple Mail (macOS and iOS) respects srcset and sizes more reliably than Gmail does, but it caches aggressively and ignores cache-busting unless you rotate the entire cid:.
  • Dark mode clients (iOS Mail, Gmail iOS) may invert background colors. Transparent PNGs of UI chrome look fine; opaque JPEGs with baked-in backgrounds look like day-glo.

A safe default is a single image per visual concept, sized for the most common reading viewport, with CSS that holds it together if the image fails to load. That is the opposite of how you’d ship a hero image on a marketing site.

The Sizing Math That Actually Matters

I size once, in code, and reuse the numbers. Open the analytics for the last six issues of your newsletter on whatever platform you use, and pull the distribution of email client and viewport sizes. If you don’t have that, the approximate breakdown from Litmus’s annual email client market share reports is a reasonable starting point until you have your own data.

Three buckets cover nearly every case:

Slot Logical width Pixel width @2x Pixel width @3x Notes
Full-bleed 600 px 1200 px 1800 px Banded hero, broken rarely
Two-column 280 px 560 px 840 px Card images, product thumbnails
Inline/icon 48 px 96 px 144 px Icons, avatars, badges

Three questions decide which bucket an asset belongs in:

  1. What is the role of the image — hero, product, supporting, or functional?
  2. At what width fraction does it sit in the 600 px content column?
  3. What is the worst-case device pixel ratio you’ll target? iOS Safari goes to 3x on iPhone Pro Max; Android Chrome on mid-range hardware hits 2x and stops.

For 2x output I keep one master, resize to 1200 px wide, and re-encode. For 3x I generate a parallel 1800 px variant. I do not send both — I pick based on the dominant client. If your list is 70%+ iOS Mail, send the 3x master and let Android downsample. If your list is mixed Gmail and Outlook, ship the 2x master, because Outlook’s re-compression already costs you roughly 15%.

Choosing a Format That Survives the Pipeline

I default to a short decision tree rather than a rule, because the answer changes with the image type:

  • Photographic hero or lifestyle shot: JPEG, quality 78–82, mozjpeg if available. Strip the EXIF; email clients don’t display it and the metadata leaks PII.
  • Logo, line art, badges with text: PNG-8 with adaptive palette, or better, an SVG. SVG support in email is uneven — Gmail and Outlook strip it — so embed SVG only when you control both clients, and fall back to a high-DPI PNG otherwise.
  • Screenshots of UI: WebP is now supported in Apple Mail and Gmail iOS/Android, but Outlook does not render it. If your recipient set includes any meaningful Outlook share, stick with PNG. The extra 30% on file size is not worth a broken screenshot.
  • Animations or motion: Short looped GIF, but cap at 200 KB. Email clients do not autoplay GIFs silently above 1 MB on mobile data.

Format selection is downstream of resizing, not independent of it — a 1200 px image encoded badly in any format will fail Outlook’s re-compression tests. The MDN article on image file type and format guidance is a useful cross-check, especially the section on browser support, which overlaps about 80% with email client support.

A Practical Workflow You Can Run From a Makefile

Below is the loop I use, stripped of the proprietary tooling. Each step is its own command, so it slots into CI.

  1. Audit the brief. Read the design spec and write down the role, target slot, and alternate text for every image in the issue. If the brief does not include alt text, ask for it. No image ships without it. Accessibility is non-negotiable; the W3C alt text decision tree is short and concrete.
  2. Generate masters at 3x. A single convert (ImageMagick) or magick command resizes from the design source to 1800 px wide for full-bleed and 840 px for two-column. Lanczos resampling is fine for photos; bicubic for screenshots.
  3. Encode for the target slot. Run separate passes at 1200 px and 1800 px. Strip metadata with mogrify -strip. Set JPEG quality 80 for full-bleed, 78 for two-column, 85 for inline icons.
  4. Measure. Reject any output above the slot’s budget. A 1200 px JPEG of a clean lifestyle shot should not exceed 180 KB; a screenshot PNG should not exceed 220 KB. If it does, drop the width one step and re-encode.
  5. Tag the file. Rename to {slot}_{role}_{2x|3x}.{ext} and drop into the email build directory. The naming makes it impossible for an editor to grab the wrong variant.
  6. Render in a real client. Pin the campaign to Litmus or Email on Acid, or open in Mail.app and Outlook desktop, and screenshot. Compare to the design spec at 100% zoom on a 1x display and on a 3x display.

QA: The Three Screenshots That Catch 80% of Bugs

Most email regressions are visible in three screenshots, taken every run:

  • Outlook desktop on Windows, reading pane at default zoom. Look for stretched logos (a giveaway that the source aspect ratio didn’t match the width and height attributes), and missing alt text fallbacks.
  • Gmail iOS app on the latest iPhone, portrait, with the message open at the top. Scroll once and confirm that the second image renders crisp, not blurred. A blurred image means the 3x variant was uploaded to a 2x slot, or vice versa.
  • Apple Mail macOS with dark mode enabled. Confirm that any UI chrome sitting on the image has enough contrast in both modes. A common failure: a light-gray button PNG on a hero image that vanishes when the background inverts.

Anything that survives those three screenshots will survive the long tail. Anything that breaks one of them is fixed and re-run before the issue ships.

Trade-offs Worth Naming Out Loud

A few decisions that come up often and that I’ve changed my mind on over time:

  • File size versus image count. Twenty sharp small images beat eight compressed posters. Gmail’s pre-processor stalls on large combined payloads more than on small individual ones.
  • srcset versus a single 3x master. srcset is honored by Apple Mail and recent Yahoo/AOL webmail. It is ignored by older Outlooks. If your list has more than 15% Outlook desktop, ship one 2x master and accept the soft rendering on a Pro Max display. Most readers will not notice.
  • CDN resizing versus build-time resizing. CDN resizing (?w=1200) is convenient, but the resulting URLs are long, brittle, and stripped or shortened unpredictably by Gmail. Build-time resizing means losing flexibility but gaining predictability. For newsletters I prefer the latter.
  • Aspect ratio fixity. The image always declares its width and height attributes in the HTML, so the layout reserves space even when the image fails to load. For a deeper walkthrough on avoiding stretch and quality loss during the actual resize operation, the Lizely resize guide covers the resampling and aspect-ratio math in detail.

Frequently asked questions

Should I send retina/HiDPI images to every recipient?

Only if your list is dominated by Apple Mail iOS/macOS. For a mixed Outlook+Gmail+Apple Mail audience, a single 2x master is more reliable than a 3x variant delivered to a recipient who will downsample it anyway. Test with your own client distribution.

What’s the right JPEG quality for email?

Around 78–82 for hero and lifestyle photos, 85 for inline icons and avatars. Going higher adds bytes without visible gain in the inbox, because Outlook and Gmail both recompress during transit. Going below 70 introduces banding that is visible in flat-colored product shots.

Can I use WebP in transactional email?

Only if every client on your recipient list supports it. That excludes Outlook desktop and older Outlook for Mac. For mixed lists stick with JPEG/PNG; for pure Apple Mail + Gmail iOS audiences, WebP is fine and saves 25–30% on file size.

What’s the single biggest mistake engineers make resizing for email?

Fixing the rendered width but forgetting width and height attributes on the <img> tag. Most clients don’t compute aspect ratio from the image itself, so a missing attribute pair causes the layout to reflow, the next image to load shifted, and the entire grid to land wrong. Always declare both attributes, with the natural pixel dimensions of the variant you’re sending.


This article was drafted with AI assistance and reviewed for technical accuracy before publishing.

Top comments (0)