ZIPPY DOCS

Broadcasts

Email a saved segment from Zippy — consent enforced in the send path, one-click unsubscribe on every message, and an app-open rate on the broadcast itself, because every link in it is a Zippy link.

Broadcasts

Email capture gives you a list. Segments tell you which slice of it you actually want. Broadcasts is the part where you send them something — and then find out how many people it sprang into a real app.

That last part is the bit no other email tool can do. Every link in a broadcast is a Zippy link, so the broadcast reports its own app-open rate, not just "someone clicked something in an inbox."

Broadcasts are Hero and up, behind the broadcasts feature flag. Unsubscribing is every plan, always — see Unsubscribe.

Send one

  1. Broadcasts → New broadcast in the sidebar. (Or, faster: open Audience → Segments and hit Broadcast to them on the segment you want — that opens the composer already aimed at it.)

  2. Write a subject and a body.

  3. Pick a link for the call-to-action. This is one of your own Zippy links, chosen from a list — you can't type a URL (that's deliberate, see below).

  4. Pick a saved segment, or leave it blank to reach your whole consented list.

  5. Hit Preview recipients. You get the real number:

    { "consented": 412, "contactsOnFile": 486, "segmentLinks": 3 }

    consented is who will actually receive it — after consent and unsubscribes are applied. contactsOnFile is everyone on record. The gap between them is people who unsubscribed or who have no consent on file, and you should expect one.

  6. Send. The request returns immediately; the sending happens in the background.

Who actually receives it

A contact is a recipient only if both are true:

  • They gave explicit consent. Zippy stores the exact wording each person agreed to when they signed up (that's the consent_text from email capture). No consent on file, no email — on any plan, for any reason.
  • They haven't unsubscribed. One unsubscribe is permanent and applies to every future broadcast.

This is enforced in the send path, not in the compose screen. Recipients are worked out on the server from your own contacts table — there is no to or recipients field anywhere in the API, on any endpoint. That's not a check somebody remembered to write; it's the shape of the thing. There's no request you could craft that names an address.

It's also re-checked at the last moment, per person, immediately before their email goes out. So if someone unsubscribes while a broadcast is still going out, they're skipped — even though their row was already queued.

Segments and the honest ceiling

A segment is a filter over your click and app-open data. That data has no names in it — Zippy deliberately doesn't store person-level click identity. Your contacts, on the other hand, are rows keyed by the link they signed up from.

So when you aim a broadcast at a segment, the join is by link: the people who joined your list from the links this segment matched. For the headline case — a segment of "app-opened" on your last drop — that's exactly the set you want.

What it is not is a guarantee that each individual recipient personally app-opened. We're not going to pretend otherwise, and the dashboard doesn't either. Per-person attribution would mean identity-joining click data to contacts, which we don't collect on purpose.

If your analytics can't be reached, a segmented send is refused, not widened. Falling back to "everyone" during an outage would put a mailing in inboxes that you can't recall.

You can't type a raw URL into a broadcast. If you paste one, the compose screen refuses it:

{ "error": "raw_link_in_broadcast", "offending": "mybrand.com/sale" }

A scheme isn't required to count as one — mail clients auto-link bare hosts, so mybrand.com/sale is refused exactly like https://…. Ordinary prose is fine ("it drops at 3 p.m.").

The reason is the whole product: a raw link opens in whatever browser the mail app hands it to, springs no native app, and reports nothing back. A Zippy link opens the real app and tells you it did. Which is why your broadcast gets an app-open number at the end and a Mailchimp campaign never will.

This is the same guard the Instagram DM automations use, for the same reason.

Unsubscribe is never gated

Every broadcast carries a working one-click unsubscribe:

  • a link in the footer, next to the exact consent wording that person agreed to
  • List-Unsubscribe and List-Unsubscribe-Post headers, so Gmail and Apple Mail show their own native Unsubscribe button and the recipient never has to open anything

It takes effect immediately, applies to every future broadcast, and needs no account, no login and no plan. Same principle as deletion: we're not willing to sell someone's ability to get out.

Sending is asynchronous and resumable

Hitting Send doesn't sit and wait on a mail provider. It writes one row per recipient and returns; a background job sends them in batches.

That design is what makes a half-finished broadcast safe. Each recipient row is unique per (broadcast, contact) at the database level, and a row is claimed before the email goes out. So if a send dies halfway:

  • Retry it. The people who already received it aren't queued any more, so they're not re-sent. Nobody gets a second copy.
  • The ones that never went are picked up and sent.

There's no separate "resume" button, because retrying is resuming.

Reading the results

Broadcasts → (a broadcast) → Results shows:

Sentthe email provider accepted it
Failedthe provider rejected it — retry to try again
Skippedwe refused to send it, with the reason
App-openshow many taps on your link sprang the real app

Two honest notes:

  • We don't show "delivered." Zippy doesn't consume delivery webhooks from the mail provider, so we can't see whether a message landed in an inbox. "Sent" means accepted, and we'd rather label it accurately than dress it up.
  • App-open figures are sampled. They come from the same analytics pipeline as the rest of your app-open data, which extrapolates from samples — a trend and a rate, not a per-tap tally. It's labelled as sampled everywhere it appears.

Skips are never silent. Every skipped recipient carries a reason in plain language — "they unsubscribed", "no consent on file", "you hit your hourly send limit."

Instagram DMs: why there's no DM blast

There isn't one, and there isn't going to be one. If you call the DM endpoint you get a refusal that explains itself.

Meta's 24-hour messaging window governs an ongoing conversation — your DM automations already reply inside it, which is legitimate and works today. Re-engaging people outside that window needs message tags, one-time notifications, or paid messaging. We audited that surface for the Instagram Login flow your account is connected under and couldn't verify the encoding, so we fail closed.

That's not caution theatre. Blasting a list of followers is how creators get their Instagram accounts restricted, and we can't give that back to you. Email the same segment instead — same people, and you get the app-open rate, which the DM never would have told you.

Limits

  • 5,000 recipients per broadcast, 1,000 sends per hour per workspace. Hit the hourly limit and the rest are requeued, not dropped — the send resumes on its own.
  • 200 broadcasts per workspace.
  • Drafts are editable; a broadcast that's already sending isn't. Half your list would already be holding the old copy.

Notes

  • Hero and up, behind the broadcasts flag. Unsubscribing and deleting a contact are every plan, always.
  • A downgraded workspace can still read its send history and delete broadcasts — the gate is on sending, never on getting your data out.
  • Sending never touches your links. Permanence is unaffected by anything on this page.

FAQ

How do I email everyone who opened the app from my last drop?

Save a segment filtered to the app-open outcome on that link (segments), then compose a broadcast and pick that segment. The preview shows you the real consented recipient count before you commit. Note the ceiling above: the join is by link, not by individual.

No. There's no setting, no plan, and no API parameter that allows it. Consent is checked when the recipient list is built and again immediately before each individual email goes out.

What happens if someone unsubscribes while my broadcast is sending?

They're skipped. The check runs per recipient at the moment of sending, against their current status — not against a snapshot taken when you hit send.

Does Zippy tell me if a broadcast was delivered?

No, and we say so rather than guessing. "Sent" means the email provider accepted the message. We don't consume delivery webhooks, so there's no delivered number to show you.

Can I send an Instagram DM to a saved segment?

No. Re-engaging people outside Meta's 24-hour window requires messaging permissions we can't verify for your connection, so Zippy fails closed rather than risk getting your account restricted. Your DM automations still reply inside the window, which is the part that's actually permitted.

What happens if a broadcast fails halfway through?

Retry it. Recipients who already got it aren't re-sent — that's guaranteed by a database constraint, not by a retry counter — and the ones who didn't are picked up and sent.

Read more