The Spec

Open-Time Ad Serving, Explained

The ad auction runs when a subscriber opens the email — not when the publisher hits send. This is the architecture underneath every MailAdx ad tag, and the reason email ad serving can't simply copy how web display works.

Why email can't serve ads like the web does

A web ad server has a script running in the browser. It can check the current time, call an ad exchange, render whichever creative wins, and fire a tracking pixel — all after the page has already loaded. None of that is available inside an email client. Gmail, Outlook, Apple Mail, and every other major mail client strip <script> tags on arrival, as a baseline anti-phishing and anti-tracking measure. Whatever an email ad server decides, it has to decide using only what a mail client will reliably do on its own: fetch images and follow links.

That single constraint is the entire reason open-time serving exists. If you can't run code in the inbox, the only moment you get to make a decision is when the client requests something from your server — and the only thing every client requests automatically is the image referenced by an <img> tag.

How the decision actually happens

A publisher places one image tag in their newsletter template, once, pointing at a dynamic URL rather than a static image file:

<img
  src="https://mailadx.com/api/v1/serving/display?pub=YOUR_PUB&pk=header&eh={{EMAIL_SHA256}}"
  width="728" height="90" alt="" />

{{EMAIL_SHA256}} is a merge tag the sending ESP fills in per-subscriber before the send goes out — it's a one-way hash of the subscriber's email address, never the address itself. The image URL is identical for every recipient; only the hash varies. Nothing subscriber-specific is decided at send time.

When a subscriber opens the email and their mail client renders it, the client requests that image URL exactly like it would request any other image. That HTTP request is the entire signal the ad server gets, and it's enough: at that moment, the server knows which placement this is (pk=header), which publisher it belongs to (pub=), and which hashed subscriber is opening (eh=). From there it runs the waterfall — checking direct-sold campaigns first, then programmatic demand, then house ads — selects a winner, and returns that creative as the image response. On MailAdx this whole decision completes in under 5ms. The subscriber never sees a delay; they just see an ad that was chosen for this specific open, not baked in at send time.

Send-time vs. open-time: what actually changes

The alternative — and the model most legacy email ad tools still use — is send-time serving. The ad (or the choice of which ad) is decided once, when the campaign is triggered, and every recipient's copy of the email is identical from that point forward. The practical differences compound quickly:

  • Billing. Send-time models often count or bill against the full recipient list, because there's no later signal to distinguish who actually opened. Open-time serving only counts an impression when the image is actually fetched — an unopened email produces no impression and no charge.
  • Timing drift. A newsletter sent Monday and opened Thursday shows whatever won the open-time auction on Thursday — not whatever was true on Monday. Budgets that exhausted midweek stop showing. A creative fixed on Tuesday appears starting with the next open. Send-time serving has none of this; Monday's decision is permanent the moment the email leaves the outbox.
  • Frequency capping. Capping how often one subscriber sees the same sponsor only works if you know, at decision time, how many times they've already seen it. Open-time serving evaluates the cap against the hashed identifier on every open. Send-time serving can only cap at the batch level, because it has no visibility into individual opens after the fact.
  • Measurement under mail-privacy features. Apple Mail Privacy Protection pre-fetches images for every recipient shortly after send, whether or not a human ever opens the email, and some corporate gateways do similar prefetching. A naive open-time implementation would double-count these as real opens. A correctly built one distinguishes MPP/gateway prefetch patterns from genuine subscriber opens before counting an impression — this is a serving-layer problem either way, and it exists regardless of which model you use; open-time serving is simply the model where getting it right actually matters, because billing depends on it.

Why this is also a privacy architecture, not just a timing one

Because the entire signal is a single HTTP image request with no JavaScript execution, there is no browser storage API in play — nothing sets a cookie, because nothing runs client-side code capable of setting one. Instead, targeting and frequency capping run off the hashed identifier passed as a query parameter. That hash is one-directional: the ad server can match it against other events carrying the same hash, but it cannot recover the original email address from it. This is what makes open-time serving naturally GDPR/CCPA-compatible without additional consent-management tooling bolted on — there's no third-party cookie to disclose, because there isn't one.

The integration pattern, across every ESP

Every ESP that supports a custom HTML block or a merge-tag system can carry this pattern, because the requirements are minimal: the platform needs to (1) let the publisher paste a static block of HTML into a template, and (2) substitute a per-subscriber merge field into that HTML before sending. That's the entire integration surface. It's why the same image tag works, with only the merge-tag syntax changed, across 18 ESP integrations — none of them need a dedicated API integration, a webhook, or a JavaScript SDK for open-time serving to work. Only the token syntax for the hashed-email merge field changes:

ESP / patternHashed-email merge tag
Generic (curly-brace){{EMAIL_SHA256}}
Mailchimp*|EMAIL_SHA256|*
Klaviyo (Liquid){{ person.email_sha256 | default:'' }}
Generic (percent-delimited)%%EMAIL_SHA256%%

The hash itself — SHA-256 of the lowercased email address — is computed once per subscriber, before the send, and stored as a custom field or profile property in the ESP. It never touches MailAdx's servers in reversible form; only the one-way hash is passed in the URL. The same pattern also carries a second, unique-per-send token (Mailchimp's *|UNIQID|*, Klaviyo's {{ message_id }}, or a generic campaign ID), which the ad server uses to distinguish this send from the next one for pacing and reporting — without it, every open across every send would look identical to the server.

What runs inside the auction itself

Open-time serving describes when the decision happens; it says nothing yet about which demand wins. Inside MailAdx, the decision at open time evaluates demand sources in priority order — direct-sold campaigns the publisher negotiated themselves, then internal DSP demand from advertisers self-serving on the platform, then OpenRTB-compatible programmatic demand, with house ads as the final fallback so a placement never returns genuinely empty. Every tier checks flight dates, floor CPM, and frequency caps against the hashed subscriber before it's allowed to bid, and the whole evaluation — across every tier — is what completes in under 5ms.

This is also why open-time serving and direct-sold deals aren't in tension with each other, despite direct-sold sounding like the opposite of a real-time system. A publisher's own negotiated sponsor still gets first priority in the waterfall; open-time serving just means that priority is enforced at the moment of each individual open — including frequency capping across sends — rather than baked into a single send-time snapshot that can't react to anything that happens afterward.

Who actually needs this, and who doesn't

Open-time serving matters most to a newsletter that already runs paid placements — direct-sold, programmatic, or both — and needs the economics and the reporting to hold up under scrutiny from an advertiser who's paying real money for real attention. If a newsletter has no ad inventory yet, the architecture is moot; the value only shows up once there's a placement, a sponsor, and a report that sponsor expects to see. For an advertiser, the relevant question isn't the architecture directly — it's whether the impression count they're billed for reflects opens that actually happened. Open-time serving is the mechanism that makes that true by construction, rather than by an estimate applied after the fact.

What open-time serving doesn't solve on its own

It's worth being precise about scope. Open-time serving is a decisioning architecture — it determines when and how an ad decision gets made. It doesn't by itself guarantee demand (a publisher still needs advertisers, direct-sold or programmatic, to actually fill a placement), and it doesn't by itself produce a delivery report — that requires the serving layer to log every decision, including the no-fill outcomes, not just the ones that resulted in an impression. An ad server built on open-time decisioning is a necessary foundation for accurate, verifiable delivery reporting; it isn't a substitute for actually logging and exposing that data.

Implementation checklist

If you're evaluating whether an ad server actually implements open-time serving — your own, or a vendor's — these are the properties worth checking directly, rather than taking a vendor's word for it:

  • The ad tag is an <img> (or equivalent passive-fetch) reference, not a script tag — confirm it renders identically with images-only mode enabled in the mail client, since that's how most subscribers actually read email.
  • The URL contains a per-subscriber hashed identifier, not a raw email address or a static placement ID with no subscriber component — a static ID means the same creative shows to everyone regardless of who opens.
  • A second, unique-per-send token is present alongside the hash, so the server can tell this send apart from the next one for pacing and reporting.
  • The vendor can show you a decision log with an explicit no-fill outcome, not just logged impressions — if every recorded event is a fill, the denominator for any fill rate they report is wrong by construction.
  • Budget or creative changes made mid-campaign are reflected in opens that happen afterward, without requiring a new send.

Frequently asked questions

What is open-time ad serving?
Open-time ad serving is a method of delivering ads in email where the ad auction runs at the moment a subscriber opens the email — not when the publisher hits send. The publisher embeds a single dynamic image tag in the newsletter template. When a subscriber's mail client requests that image, the ad server runs a real-time auction and returns the winning creative as the image response.
Why can't email ads work like web ads?
Mail clients strip JavaScript for security — Gmail, Outlook, and Apple Mail all block scripts in HTML email. Web ad servers assume they can run a script to decide, target, and track. Email ad servers can't. The only thing every mail client reliably fetches is an image, so open-time serving uses the image request itself as the decision trigger.
Is open-time serving the same as real-time bidding (RTB)?
They can compose, but they're not the same thing. RTB describes how a winning bid is chosen among competing demand sources. Open-time serving describes when that decision happens — at the moment of open, versus at send time. An open-time ad server can run an internal waterfall, direct-sold priority, or an OpenRTB-compatible auction; the timing is the distinguishing property, not the auction mechanism.
Does open-time serving use cookies?
No. Because the request is a plain image fetch with no JavaScript, there's no browser storage API available to set a cookie in the first place. Targeting and frequency capping instead use a hashed identifier (typically SHA-256 of the subscriber's email) supplied as a merge tag by the sending ESP.
What happens if a subscriber never opens the email?
Nothing — and that's the point. If the image is never requested, no auction runs, no impression is recorded, and no advertiser is charged. Send-time and pixel-estimated models bill or count against the full recipient list regardless of whether anyone reads it; open-time serving only counts what actually happened.
Can a campaign change after the email has been sent?
Yes — this is one of open-time serving's practical advantages. Because the decision happens at open, not at send, a publisher or advertiser can pause a campaign, swap a creative, or exhaust a budget after the email has already left the outbox, and every open from that point forward reflects the change. A send-time or embedded-image model locks in whatever was decided the moment the email went out.

Related: the short-form glossary definition of open-time ad serving, the MailAdx ad server product page, and how this compares to marketplace models like Paved.

Run an ad server built on open-time serving

One ad tag, frequency capping at open time, and a delivery report that reflects what actually happened — not what was sent.

No credit card required
Setup in 30 minutes
Dedicated onboarding