EmailTimer.App

When the image service is down, what your recipients see

By Danish Mohammed, founder. 8 min read

When part of the EmailTimer.App image service fails, a recipient sees a picture, not a broken image icon. Every request for an image address answers HTTP 200 with a valid image: the live countdown when it can, and otherwise one of three stand-ins. The one gap is a total outage of the server itself, and the edge Worker that closes it is deployed but not yet routed.

This is the reliability chapter of choosing a dynamic image and countdown timer vendor for an enterprise email programme. It is written for the person who has to answer “what does our campaign look like if you go down”, and it describes the code as it stood on 23 September 2026.

The rule behind it is short. An email has already been delivered when its image is fetched, and nothing can recall it, so an error status is a broken image for good. The service is built so that nothing it controls ever sends one.

The four pictures an image address can return

These are real renders from the product’s own engine, the same sale design in each state, plus the card the image service keeps on disk for failures.

A live countdown for a sale reading 01 days, 11 hours, 59 minutes, 00 seconds, above a Shop the sale button
Live. The countdown, drawn at the moment of the fetch.
The same sale design after its deadline, with every unit at 00
Expired. The same design at zero, cached for longer because it will not change again.
A flat light grey card at 600 by 200 pixels with nothing drawn on it
Template fallback. The design could not be drawn for this recipient, and it has no fallback image of its own.
A white card on light grey reading image unavailable, with emailtimer.app beneath it
Service card. Any request the service cannot tie to a usable template, or cannot serve in time.
The four pictures an image address can return
Picture Served when Shared caches keep it Counts as an open
Live countdown Everything worked 30 seconds Yes
Expired frame The deadline has passed 7 days Yes
Template fallback This recipient’s image cannot be drawn, such as a missing per-recipient deadline 30 seconds Yes
Service card Bad signature, unknown template, suspended workspace, a rate or concurrency ceiling, a render past 5 seconds, or any exception 30 seconds No

Where each one is set, and how to give a template a fallback image of your own, is on what a timer shows when it is not counting down. This page is about what happens around them during an incident.

The card has two layers under it. If its file were missing from a deployment, the service draws a plain grey card of the same size without fonts or native code, and if even that fails, it sends a one-pixel grey PNG written out byte by byte in the source.

What an outage looks like today

Today every image request goes through Cloudflare’s proxy straight to one server, which runs the image service beside Postgres, Redis and the rest of the product. The edge Worker described below is deployed but not routed, so it answers none of that traffic yet.

Most failures stay inside the rule, because the image service is still running and answering:

  • A template that will not load, or an exception. The service card, and a real render on the next fetch once it is fixed.
  • A spike past the service’s ceilings. The card, immediately, rather than a place in a queue. What breaks at five million sends has the ceilings.
  • A lost signing key cache in Redis. Every image in that workspace becomes the card, because no signature can be checked. A sweep rewrites the keys from Postgres within five minutes.
  • A worker process that dies. The service runs several, one fewer than the machine’s cores by default, and a dead one is replaced. A deploy drains requests in flight first.
  • Postgres down. Nothing changes for recipients. The image service holds no database credentials and does not read Postgres on the render path.

The case outside the rule is the server itself being unreachable. Then nothing of ours is answering. Cloudflare can serve a copy its cache still holds, for as long as the headers allowed it to keep one: 30 seconds for a live countdown, a week for an expired timer or a static personalized image. Past that, Cloudflare answers with an error of its own, and a mail client draws an error as a broken image or as nothing. We would rather say that plainly than let the words “always 200” cover a case they do not.

What changes when the edge route is live

The Worker is written, tested and deployed on Cloudflare. It goes in front of the image service when its route is switched on, and from then on every open reaches it first.

How a picture is chosen for one image request Top row, the edge Worker once its route is live: it serves a fresh copy from its cache; failing that, it asks the image service and waits up to 10 seconds; failing that, it serves its last-known-good copy, kept a day by default and 30 days at most; failing that, a transparent 1 by 1 pixel. Bottom row, the image service: if the address is signed, the template known and the limits not reached, and the deadline is still ahead, and the image can be drawn for this recipient, it serves the live countdown. Otherwise it serves the service card, the expired frame or the template fallback respectively. At the edge Worker, once its route is live Tried in this order. The first that works is served. A forged or unsigned address goes straight to the pixel. Fresh copy in the edge cache Kept as the headers allow Ask the image service Gives up after 10 seconds, or on an error answer Last-known-good copy The last real render, kept a day by default, 30 at most Transparent 1x1 pixel HTTP 200. The layout keeps its space, nothing is drawn no no no Inside the image service, which every request reaches today Signed, known, and within the limits Checked before any render Deadline still ahead A count-up timer never reaches this check Drawable for this recipient A deadline it can read Live countdown Shared caches keep it for 30 seconds yes yes yes no no no Service card Not counted as an open Expired frame Shared caches: a week Template fallback Your image, or a grey card
Drawn from apps/edge/src/index.ts and apps/img/src/app.ts. The top row is not in the request path until the Worker's route is live.

Three things change for a recipient once it is.

Most opens stop reaching the server at all. The Worker keeps each render in Cloudflare’s cache under the exact signed query, so a repeat of the same image is answered at the edge.

An outage serves the last real image instead of an error. Every successful render is also kept as a last-known-good copy: a day by default, up to 30 days where the service allows it, as it does for static personalized images. When the service errors or takes more than ten seconds, the Worker serves that copy. A stale countdown is wrong by however long the outage lasts, and still better than a hole in the email.

Many expired timers stop depending on the server. Where the signed address carries its own deadline, as a per-recipient deadline or a send time does, the Worker can see that it has passed and rewrites every such request for the template to one canonical address. That one render is served from the edge cache for everybody, outage or not. A deadline set inside the template is not in the address, so those requests still go to the service.

With neither copy, the Worker answers with a transparent one-pixel PNG at HTTP 200, a different stand-in from the service card: the mail client sizes it from the width and height on your <img> tag and draws nothing, so the space holds. The same pixel answers a forged or unsigned address, which never reaches the server.

What a mail client’s own cache does with any of this

The service tells every cache how long it may keep each picture. The code asks private caches to keep a live countdown, the service card and a template fallback for zero seconds, so a recipient who opened during an incident gets a real render on the next open. An expired frame is the exception, at a day, because it will not change again.

What we measured on the live hostname is not quite that. Read on 24 September 2026 (UTC), the service card came back from img.emailtimer.app with max-age=14400, four hours, where the service sends zero. A Cloudflare zone setting, Browser Cache TTL, raises a lifetime the origin sets lower than its own. Until that setting is changed to respect the origin, a client that honours the header can show the card for up to four hours after the service has recovered. It is written here because it is true today.

Beyond the headers, each client keeps copies its own way, and nobody can purge them. Gmail fetches through Google’s image proxy, which publishes no cache lifetime (the Gmail page). Apple Mail with Mail Privacy Protection fetches at delivery rather than at open, so what Apple fetched during an outage is what a recipient may see later (the Apple Mail page). Outlook for Windows draws the first frame, and a stand-in is a still picture already.

What to put in the email so an outage costs less

Put the deadline in the body text as well as in the image, because text needs nothing from us. Set width and height on the <img> so any stand-in, including the edge pixel, keeps the layout. Write alt text that says the offer, such as “Sale ends Friday at midnight”, rather than “countdown timer”. Countdown timer not showing covers the reasons an image fails that have nothing to do with the service.

Nothing alerts us automatically yet: no uptime monitor, and no alert on the rate of service cards. An uptime check would stay green anyway, because every failure is a 200, which is why the service counts each card by its reason. The status page says what is watched and how an incident reaches you.

A security reviewer will ask the same question from the other side, and what a security review asks an email image service has the documents behind these answers. If you are weighing this against the vendor you use today, the matching question is what their addresses return once the contract ends, which moving off an incumbent without breaking mail already sent answers for each of them. The plan limits behind the countdown are on pricing.

Questions and answers

Does a recipient ever see a broken image icon?

Not from anything the image service sends. It can happen today in one case: the whole server is unreachable and Cloudflare holds no copy, so Cloudflare’s own error reaches the mail client. Once the edge Worker’s route is live, that case becomes the last real render or a transparent pixel.

Is a stand-in counted against our plan?

The service card is not counted. The expired frame and a template fallback are, because each is a rendered response for a real template. How opens are counted has the full rule.

Sources

Related

Put a countdown in the campaign you are writing now

The free plan covers 5,000 opens a month with no card. Starter is $19 a month for 250,000.