Short answer: host images in HTML email by default; attach them inline when the message must remain self-contained, then test both paths with the same asset and receiving mailbox.
I run a one-person SaaS that sends a preview after a user asks it to generate a short promo video. The email has a thumbnail, a moderation result, and a link to the rendered clip. My constraint is boring but real: every extra byte competes with the copy, the call to action, and the time I have left to ship the next feature.
The choice is not a simple visual preference. It changes MIME structure, cache behavior, privacy, failure modes, and what a mailbox can inspect before it decides where the message belongs.
Size wins.
How do hosted images and attached HTML email assets change deliverability and size?
A hosted image is referenced from HTML with an HTTPS URL. The message carries the URL, not the binary image. An attached image uses a MIME part, usually referenced with a cid: URL from the HTML, so the binary travels with the message. A data URL embeds the bytes directly in the HTML part. Those are three different delivery contracts, even when the reader sees the same thumbnail.
For rough sizing, base64 expands binary data by about one third before MIME line wrapping and headers. A 120 KB JPEG can therefore become roughly 160 KB in an inline representation, before the rest of the message. A hosted reference may add only a few dozen characters to the HTML, but it creates a second request when the mailbox chooses to load remote content. The exact result depends on encoding, headers, and the image format.
That second request is useful. A hosted asset can be resized or replaced without resending the message, and a cache can serve the same thumbnail to many recipients. It also means the image may be blocked, delayed, logged by a proxy, or fetched from a different network than the mail itself. Inline data survives remote-image blocking, but it makes every copy of the message heavier and harder to change.
Here is the small decision function I use before wiring a template. It treats the image as an asset with a policy, not as decoration bolted onto HTML.
type ImagePolicy = "hosted" | "cid" | "data";
interface EmailImageInput {
bytes: number;
mustRenderOffline: boolean;
mayContainPrivateData: boolean;
needsPostSendReplacement: boolean;
}
export function chooseImagePolicy(input: EmailImageInput): ImagePolicy {
if (input.mayContainPrivateData) return "cid";
if (input.mustRenderOffline) return "cid";
if (input.needsPostSendReplacement) return "hosted";
if (input.bytes <= 12_000) return "data";
return "hosted";
}
The 12,000-byte cutoff is a team policy, not a standard. I picked it because a tiny logo and a one-pixel tracking decision have a different cost profile from a video thumbnail. Your mileage may vary. Measure the encoded message, not just the source file.
What actually affects deliverability beyond image size?
Mailbox systems judge a message as a whole. Authentication alignment, sender reputation, complaint rate, HTML quality, text alternatives, and recipient interaction all matter. An image strategy cannot rescue a message that fails those basics.
Remote images add an observable fetch. Some clients proxy that fetch, some ask the reader, and some never make it. That variability affects open measurement and can make a moderation badge look missing even though the message itself arrived. Inline images avoid that particular fetch, but they still do not guarantee display: clients can suppress images, sanitize HTML, or enforce their own attachment rules.
I once treated a thumbnail as harmless because the source file was only 90 KB. The sent message was much larger after base64 encoding and MIME boundaries, and a long text-heavy template crossed a clipping threshold in one mailbox. The fix was not a clever compression flag. I compared the raw JPEG, the encoded MIME part, and the complete message after template assembly. Then I moved the preview to a hosted asset, kept an accessible text summary in the HTML, and measured the complete message with a test mailbox. That extra pass also caught a missing alt value in a second template, which would have made the moderation result opaque with images disabled.
That is the operational lesson: count bytes at the wire boundary, then inspect the rendered result in more than one client. A source image number alone is not a deliverability test.
A practical comparison for a promo-video SaaS
| Choice | Size behavior | Main strength | Main risk |
|---|---|---|---|
| Hosted HTTPS image | Small message; image fetched later | Easy replacement and caching | Remote images may be blocked or delayed |
MIME cid attachment |
Binary travels with the message; MIME overhead applies | Works without a second network request | Larger messages and more template plumbing |
| HTML data URL | Binary and markup share one part; base64 expands bytes | Self-contained tiny assets | Quickly inflates HTML and is inconsistently supported |
For a generated-video notification, I host the thumbnail, keep the moderation decision as real text, and include a descriptive alt value. The email should still make sense when images are disabled. If the thumbnail contains sensitive user material, I would attach it with a content ID or omit it, depending on the retention policy.
The catch is that hosting is not suitable when the recipient must inspect the message in a disconnected archive, or when policy forbids a later fetch to a third-party origin. In those cases, use a content ID attachment and accept the message-size cost. Stick with a hosted image when replacement, caching, and a small message matter more than offline rendering.
What I would change at scale
At higher volume, I would add three checks to the build pipeline. First, render each template with images blocked and verify that the moderation status, title, and action still read correctly. Second, record the encoded message size and the largest individual MIME part. Third, run a matrix of real mailbox clients, because standards describe message syntax, not every UI decision.
I would also make asset URLs immutable by content hash, then expire old thumbnails according to the product's retention rule. That keeps cache behavior predictable without silently changing what a recipient sees. For inline attachments, I would deduplicate repeated images inside one message and reject oversized assets before queueing.
There is no universal winner. The right boundary is the one that preserves the information a reader needs, keeps the message inspectable, and leaves enough operational room to fix a bad asset without asking every recipient to open a new email.
Top comments (0)