Countdown block
A live-ticking deadline timer for launches, sales and closing dates — rendered server-side as an animated GIF, the one technique that keeps actually counting down across every major email client, Outlook included.
How it works
No email client runs CSS animations or JavaScript reliably enough to animate a clock from scratch, so the countdown block doesn't try — it embeds a plain <img> pointing at a server-rendered animated GIF. On each fetch, MailInApp computes the time remaining until the configured deadline and encodes a fresh "DD:HH:MM:SS"-style digital-clock image from scratch (a from-scratch GIF89a encoder, not a wrapped library), one second per frame for sixty frames, then freezes on the last frame — so the image ticks visibly for a full minute once opened, then holds. Because the image is regenerated from the real deadline at fetch time rather than pre-rendered once at send time, it's accurate no matter when — or how many times — a recipient opens the email. The endpoint that serves it sends no-cache headers specifically so inbox image proxies (Gmail's included) refetch on every open instead of serving a stale cached frame from the first recipient who opened it.
The image URL itself is HMAC-signed (the deadline timestamp and color are baked into the signature) so it can't be used as a free-standing GIF-countdown renderer by anyone who isn't MailInApp — the endpoint is public, like the interactions and open-tracking endpoints, but only serves what it's been asked to sign.
There's no mail-vs-live-view divergence the way carousel or accordion have: both contexts embed the identical image endpoint, just with an absolute URL in mail (an email has no page origin to resolve a relative path against) and an origin-relative one on the live view. There's also no separate "fallback tier" beyond the image itself — a client that can't animate GIFs still shows the first frame, a meaningful and accurate snapshot of the time remaining rather than a placeholder, which is what "a meaningful first frame" means in practice. The block's alt text and the email's plain-text part both carry the same remaining time in words (e.g. "Offer ends in 2d 4h"), so the deadline still reads even with images off entirely.
Once the deadline passes, the block stops rendering the GIF and switches to plain ended-state text instead — no more image request, no stale "00:00:00:00" hanging around.
Configurable fields:
- Label — text shown above the ticking image, e.g. "Offer ends in".
- Ends at — the deadline, picked as a date and time.
- Color — the digit/text color, used both in the rendered GIF and the ended-state text.
- Font size (px) — the label's font size while counting down.
- Font size once ended (px) — the font size of the "This offer has ended" message shown after the deadline passes.
A countdown is pure content, like an image or text block — there's nothing to tap or submit, so it never generates an interaction event and never appears in the responses dashboard, the CSV export, or a project webhook.
Examples
Subject
Our biggest sale of the year starts now
A flash-sale email with a 24-hour deadline is the canonical use — the countdown visibly ticking down is what makes urgency legible at a glance, and it keeps being accurate whether the recipient opens it the minute it lands or two days later after the sale's already over, at which point it correctly shows the ended state instead of a frozen lie. A limited-inventory product drop can pair a countdown with a product block so both the clock and the stock count communicate urgency together — see Ecommerce & product drops. An event-registration reminder can count down to the registration deadline (not the event itself — that's what add-to-calendar is for) to push fence-sitters to act before the window closes.
What the static fallback looks like
<div style="margin:12px 0">
<p style="margin:0 0 6px;font-size:16px;font-weight:700;color:#111827">Offer ends in</p>
<img
src="https://mailinapp.com/api/countdown?t=1753401600000&c=111827&s=9f2a...&"
width="207" height="34"
alt="Offer ends in 2d 4h"
style="display:block;max-width:100%;height:auto"
>
</div>
There's no separate "fallback markup" beyond this — every client renders the same <img> tag; what differs is only whether that client animates GIFs (most do) or freezes on the first frame (a handful of legacy clients), and both cases show an accurate remaining time either way.