# iMessage campaign console with pre-flight checks and delivery board

> Build every text campaign in one screen: check who is actually reachable, see a realistic send plan, then watch delivery land row by row.

- Workflow type: app
- Services: LoopMessage, Google Sheets, HubSpot
- Categories: Marketing, Operations
- Published: 2026-08-31

## What it does

- Builds a campaign from a Google Sheets tab or a saved HubSpot contact segment, showing every recipient as a row with the merge fields it found and a live preview of the exact message that person will receive
- Runs a pre-flight check on every recipient before anything sends, colour coding them as subscribed, unsubscribed, or unknown, and holding brand new contacts in a separate opt-in queue with a plain first message that has no links, no prices, and no marketing copy
- Shows a realistic send plan with an estimated finish time instead of pretending a thousand texts go out at once, because texting rules space out messages to inactive and brand new contacts
- Flips to a delivery board after sending that groups every message into delivered, pending, and failed, explains each failure in plain language, offers one click resend on the recoverable ones, and writes results back to your source sheet
- Includes a write the variants button: describe the campaign in a sentence and a background agent drafts two or three message versions per segment for you to pick between and edit inline

## What you'll need

- A LoopMessage account with at least one approved sender
- A Google account with the spreadsheet holding your recipient list, or a HubSpot login if you would rather pull the list from a saved contact segment
- A phone number column in international format, for example +13231112233, plus any columns you want to merge into the message such as first name or renewal date
- Permission from your team to send marketing texts to the people on that list

## Prompt

Build me an iMessage campaign console that my marketing and lifecycle team opens every time we run a text campaign, so we stop sending from a script and hoping. It has two main screens: a campaign builder where I assemble and pre-flight the send, and a delivery board I watch afterwards. Campaigns persist, so I can build one, leave, and come back to it, and the delivery board of a past campaign stays readable.

Campaign builder, recipient source. At the top I name the campaign and pick where recipients come from. Option one is Google Sheets: I choose a spreadsheet and tab and the app reads the rows with Get Values, treating the first row as headers. Option two is HubSpot: I give it segment criteria and it pulls contacts with Search Contacts, requesting the properties I want to merge on. Either way the app normalises a phone column into international format like +13231112233, flags rows with a missing or malformed number as unsendable with the reason shown on the row, and lists every recipient as a row in a table.

Merge fields and live preview. The app detects the available merge fields from the sheet headers or the HubSpot properties and shows them as chips I can click into the message editor, for example {{first_name}} or {{renewal_date}}. Each recipient row shows a live preview of the exact message that person will receive with their values substituted. If a row is missing a value for a field used in the message, highlight it as a merge gap and let me either set a fallback value for the whole campaign or exclude that row.

Pre-flight column. Before anything can be sent, a Run pre-flight button checks every recipient with LoopMessage Check Contact Status and colour codes the row: green for subscribed, red for unsubscribed, amber for unknown. Use List Audience to pre-load who is already in our audience so pre-flight does not have to call one by one for people we obviously know, then fill the gaps with Check Contact Status. Unsubscribed rows are hard blocked and cannot be sent to under any circumstance. Show a pre-flight summary bar with the counts in each bucket. The Send button stays disabled until pre-flight has run against the current recipient list, and re-enabling requires a re-run if I change the source or the list.

Sender selection. A dropdown populated from LoopMessage List Senders lets me choose which sender the campaign goes out from, showing the sender name and status so I do not pick an inactive one.

The send plan is the most important part of this app, so make it prominent and honest. LoopMessage enforces throttles per contact, not per API key: a minimum of two minutes between outbound messages to an inactive contact, and fifteen minutes between conversation initiations to brand new contacts. Replies inside a five minute active conversation window are not throttled. So the builder must compute and display a realistic send plan before I commit: how many recipients are in the normal send queue, how many are in the opt-in queue, the pacing each queue will use, the number of batches, and an estimated completion time as a wall clock time, not a spinner that pretends a thousand texts go out at once. If the estimate runs past a sensible window, say so plainly and let me trim the list or split the campaign across days.

Opt-in first queue. LoopMessage will not deliver an outbound message to someone who has never messaged us until they accept an opt-in, so every recipient that came back unknown from pre-flight goes into a separate opt-in queue rather than the main campaign. That queue sends its own plain introduction message via Send Message, paced at the fifteen minute initiation interval. Enforce the content rules in the editor itself: the opt-in message must contain no links, no email addresses, no phone numbers, no currency amounts, no attachments, and no marketing copy, or the provider rejects it. Validate the draft live, highlight the offending text, and refuse to queue a non compliant opt-in message. Once someone accepts and shows up as subscribed on a later pre-flight, they become eligible for the main campaign.

Sending. Pressing Send starts the campaign in throttle aware batches through LoopMessage Send Message, one message per recipient with their merged text, using the chosen sender. Sends are queued and paced according to the plan rather than fired in a loop. Persist the queue and every returned message id, so closing the browser does not lose the campaign and reopening shows exactly where it got to. Give me a pause and a cancel that stop future batches without trying to unsend what already went.

Delivery board. Once sending starts the screen flips to a delivery board that polls Get Message Status for each message id and groups results into delivered, pending, and failed, with counts and a delivery rate at the top and a searchable table underneath. Send paths return immediately and delivery is asynchronous, so pending is a normal state and the board should keep polling on an interval and stop once everything has settled. Decode failure codes into plain language rather than showing numbers: 500 means the person opted out, 1010 means the send failed and a retry is recommended, 1020 means it was not delivered to the recipient, and 1030 means no delivery confirmation came back. Offer a one click resend on the recoverable failures, which is 1010 and 1030, and never offer resend on 500.

Write back to the source so the list stays the record of truth. When a campaign finishes, or on demand from a button, write results back to the originating Google Sheets tab with Update Values, filling status columns such as last campaign, sent at, delivery status, and failure reason against each row. Alternatively append a full send log to a separate tab with Append Values, one row per message with recipient, sender, message text, status, and decoded failure reason. Let me choose which of the two behaviours a campaign uses.

Add a write the variants background agent on the builder. I describe the campaign in a sentence, for example win back lapsed members before the season ends, and the agent drafts two or three message versions per segment. It reads the recipient list already loaded in the builder, notes the merge fields available, and writes variants that use them naturally and stay short enough to read well as a text. The drafts land back in the builder as selectable cards I can pick between and edit inline, and the live preview updates as I edit. When it drafts for the opt-in queue it must follow the stricter rules: a plain introduction with no links, no currency amounts, and no marketing copy. The agent only writes suggestions, it never sends.

Who uses it: marketing and lifecycle people, not engineers, so the whole thing should read like a campaign tool. The guardrails are the point. Nothing sends without pre-flight, opt-outs are never contacted, brand new contacts get the compliant introduction first, and the send plan tells the truth about how long a campaign really takes.

## How to customize

- Swap the recipient source between a spreadsheet tab and a HubSpot segment, or point it at a different tab per campaign
- Change the batch size and pacing used in the send plan, and set your own cut off for how long a campaign is allowed to run
- Adjust the write back: update status columns on the original list, or append every send to a separate campaign log tab
- Rewrite the tone guidance the drafting agent uses, or set how many variants it produces per segment

## FAQ

### Why does the app refuse to send to some people on my list?

Apple based messaging will not deliver a marketing text to someone who has never messaged your business until they accept an opt in. The console spots those contacts during pre-flight, holds them in a separate opt in queue, and sends them a plain introduction first. Anyone who has already unsubscribed is blocked outright.

### Why does it say my campaign will take hours?

Messaging rules space out sends per person: roughly two minutes between messages to a contact who has not replied recently, and about fifteen minutes between first time introductions to brand new contacts. The console does that maths up front and shows you an honest finish time rather than queueing everything and failing quietly.

### Can I use it with a spreadsheet instead of a CRM?

Yes. A Google Sheets tab with a phone number column is enough to run a full campaign, and results write straight back to that tab so the sheet stays the record of truth. HubSpot is an alternative source, not a requirement.

### What happens to messages that fail?

The delivery board groups them and translates the reason into plain language, such as this person opted out or this never reached them. Recoverable failures get a one click resend button. Opt outs never do, so nobody gets texted twice after asking you to stop.

### Does the drafting agent send anything on its own?

No. It only writes suggestions. You pick a variant, edit it inline, review the preview for each recipient, and press send yourself.

Use this prompt in General Input: https://www.generalinput.com/prompts/imessage-campaign-console-with-pre-flight-checks-and-delivery-board