Meeting link block
Join details for an online or hybrid event: a provider label, a Join URL, a start time, and how many minutes before the start the Join link should present as live. It's the block behind the "click here to join" moment of a webinar or remote meeting invite, built to stay accurate whether the recipient opens the email a week early or thirty seconds before the call starts.
How it works
The provider field (Zoom, Google Meet, Microsoft Teams, or Custom) is a label only — there's no OAuth or account connection to any of them, just a plain URL you paste in yourself. It exists to pick the Join button's copy ("Join on Zoom" vs. a generic "Join meeting" for Custom), nothing more.
Mailed HTML always renders the Join button as a real, clickable link, the same "static at send time" convention the countdown and product blocks use — an email can't be re-fetched as the meeting's start time approaches, so there's no way to gate it there. Next to the button, a status line and badge track the countdown: while startsAt is in the future, it reads "Starts in Xd Xh Xm" (or "Xh Xm" once under a day) alongside a small server-rendered GIF built with the same countdown-image technique the Countdown block uses, so the number keeps ticking correctly across opens even though it's baked into a static image at request time. Once the start time passes, the badge switches to "Live now" with no further countdown.
The hosted live view is the one place this block actually gates the Join control, because unlike a mailed email, the live view is fetched fresh on every visit. There, the Join button only appears once the render time is within opensMinutesBefore minutes of startsAt; before that window opens, the recipient sees an inert gray chip reading "Opens N minutes before start" (or "Not yet open" if opensMinutesBefore is 0) instead of a working link. This is computed synchronously from the block's own props against the current clock — no Firestore read, no stored response state — so it's cheap on every live-view render. A block with no startsAt set at all is always open, on both mail and the live view, since there's nothing to gate against.
The optional dial-in line, if filled in, renders as plain text next to the Join button on every tier — it's not itself a link, just a phone number for anyone joining by voice only.
Configurable fields:
- Provider — Zoom, Google Meet, Microsoft Teams, or Custom (label only).
- Join URL — where the button links.
- Starts at — the meeting's start time; also drives the "Starts in" badge and the live-view gate.
- Dial-in (optional) — a phone number rendered as plain text.
- Join link opens this many minutes before start — the live-view gate window (default 15; 0 means the link is only inert exactly up to the start instant).
- Background color, padding, border and border radius on the card.
- Status label color/size, and Join button color/background overrides.
There's nothing to answer on a Meeting link block — it's a piece of live-updating content, not a question — so it never appears in the responses dashboard or CSV export. The Join click itself is still tracked in the block-level click heatmap like any other link, via the generic click-tracking slot every plain link-bearing block shares.
Examples
Subject
Your seat is booked — join link inside
A webinar invite pairs a Meeting link block with a Countdown further up the email — the countdown builds urgency in the days before, the meeting-link badge takes over with a precise "Starts in" readout as the moment gets close. For a hybrid event, drop both a Meeting link and a Venue block into the same email so remote and in-person attendees each get the control that applies to them — the "Event" project purpose starts you off with exactly that pairing; see Events & webinars. Setting opensMinutesBefore to something like 10 or 15 keeps early clickers from joining a mostly-empty call and finding nothing happening yet.
What the static fallback looks like
<div style="margin:12px 0;background-color:transparent">
<p style="margin:0 0 6px;font-size:13px;font-weight:600;color:#111827">Starts in 2h 14m</p>
<img src="https://mailinapp.com/api/countdown?t=1753401600000&c=111827&s=9f2a..." width="220" height="40" alt="Starts in 2h 14m"
style="display:block;max-width:100%;height:auto;margin-bottom:8px" />
<a href="https://zoom.us/j/123456789"
style="display:inline-block;padding:10px 20px;background-color:#4f46e5;color:#ffffff;
border-radius:6px;text-decoration:none;font-size:14px;font-weight:600">
Join on Zoom
</a>
<p style="margin:8px 0 0;font-size:13px;color:#4b5563">Dial in: +1 415 555 0100</p>
</div>
This is the mailed tier: a live countdown badge, an always-clickable Join link straight to the meeting URL, and the plain-text dial-in line — no gating, since mail is static at send time.