Zendesk can bulk-update 800 tickets. It can't send 800 different replies.
Mailroom can. One personalised reply per ticket, sent from your own Zendesk, driven from a Google Sheet — along with the internal notes, statuses and tags that go with a bad day. I install it in your account in two weeks.
Live in two weeks, or you don't pay.
Native bulk update stops exactly where the hard part starts.
Something upstream breaks — a delay, an outage, a pricing error, a cancelled batch — and a few hundred people need telling something specific to them, at once, on their own ticket. Zendesk will set a status, a field, a tag. It will not write to each customer. So somebody writes them by hand, and that is where it goes wrong.
It goes out from a personal inbox.
A CSV, sorted by hand, pasted into a mail merge that sends from somebody's own address. Every reply lands in that inbox instead of the ticket — so the thread is lost, and the next agent has no idea it happened.
Half your customers wait for a translation.
Or they get the English one. Whoever can translate is doing it between their own tickets, which is why the French batch goes out a day late and slightly differently worded.
Two weeks later nobody can say what you sent.
There is no record against the customer, so two agents work the same batch — and the post-incident question, what exactly did we tell them, has no answer.
Three steps, and the third one is the customer's ticket.
Everything below is a real recording against real tickets — the same sheet, the same menu and the same Zendesk API path your team would use on a Tuesday morning. Nothing here is a mockup.
Say what happened, in plain words.
Type the situation the way you would say it out loud. A draft comes back for every language on the sheet, written as a template — {{GuestName}}, {{BookingID}}, whichever merge fields you use. Approve it, edit a line, or ask for changes.
The composer only ever sees the situation — what happened, to what, over what dates. Names, addresses and references are filled in locally, row by row, at send time.
Send the batch. Close the tab.
The run keeps going without you — Apps Script is capped at six minutes, so work is chunked and driven by a trigger until it is done. The Status column fills in live, with a timestamp per row, and rows already marked Success are skipped if you run it again.
It arrives as a public reply on their ticket.
Not an email from a marketing tool. Zendesk sends it from the address the customer already knows, branded as you, and when they reply it threads straight back onto the same ticket. If the ticket was closed, the merge opens a fresh one, sends there, and writes the new id back onto the sheet.
Four operations. None of them know what you sell.
They work on tickets, fields and tags — so they are identical for a retailer, a lender, a SaaS company or a logistics operator. All four go in on day one, whatever else you pick.
One personalised public reply per ticket.
Merged from that customer's row and sent as the ticket, so replies thread back. Closed tickets get a fresh one, and the new id is written back to the sheet.
Write it once, get every language.
One description in, a draft per language out. What you approved and edited is remembered, so the next one starts from how your team actually writes.
Change the batch without emailing anyone.
The same internal note on 200 tickets, a status change, a tag for next quarter's reporting. None of it notifies a customer. Tagging 800 tickets costs 8 API calls.
One row per run, kept.
Who ran it, which case, how many tickets, what happened. It is what makes a bulk send defensible in a post-incident review, and every number on this page comes out of it.
Connected to your Zendesk in about ten minutes.
An OAuth client approved by your Zendesk admin, credentials into your own Script Properties, and the menu appears in your sheet. That is the whole connection — no marketplace app to install, no Zendesk approval process, nothing for your account manager to sign off.
It runs in your Google account.
Apps Script on your own Sheet, connected to your Zendesk with your own OAuth credentials. There is no server of mine anywhere in the path.
Any Zendesk with API access.
Standard ticket and Help Center APIs. Nothing to install from a marketplace, nothing to get approved, no per-seat licence.
Cancel and it keeps working.
MIT licensed and yours afterwards. The care plan is optional, and nothing switches off if you stop paying for it.
The whole thing, narrated, start to finish.
Twelve minutes: a customer writes in, the vendor confirms refunds, the batch is composed in two languages, sent, and the audit note lands back on the original ticket. If you would rather not book a call yet, watch this instead.
Your install contains what you bought. The rest is not reachable.
Sending the batch is only half of a bad day. The other half is whatever has to happen off the ticket — a warehouse to tell, compliance to log it with, a vendor to chase, account owners to warn — and that part is different in every business. So the menu, the sheet tabs, the sidebar panels and the credentials you are asked for are all generated from which modules you turn on. Switch them below.
-
Bulk personalised reply always on
One email per row, merged with that customer's own details and posted as a public reply on their ticket. When they reply, it lands back on the same ticket.
-
Notes, status and tags always on
Change hundreds of tickets at once without emailing anybody — add an internal note, set a status, add or remove a tag.
-
AI composer always on
Writes the email. Describe what happened in plain words and it drafts the message in every language on your sheet, for you to approve or edit.
needs an OpenRouter key -
Repeat guard
Checks whether these customers already got this batch and warns you before you send again. Turn it off if you would rather not run a Firebase project.
needs Firebase -
Third-party case routing
Groups the batch by whoever is responsible upstream — a supplier, a store, a carrier — and raises one case each, instead of one email per order.
-
Slack reply relay
Posts customer replies from the batch into a single Slack thread, so the people watching an incident stop refreshing a Zendesk view.
needs a Slack bot token -
Warehouse lookup
Paste reference numbers and it fetches the matching ticket ids and the rest of the row out of BigQuery, instead of exporting and VLOOKUP-ing by hand.
needs BigQuery
Turning one on later is a push, not a re-install.
Every file is installed either way. Apps Script runs one flat global scope, so a module nothing points at is inert — which is why switching one on costs a push, and why a module you did not buy cannot half-work.
Anything past the modules is quoted separately.
Pulling the batch straight from your CRM, a named approval step before anything sends, routing by segment, scheduled runs. On the call I will tell you which are a few days' work and which are not worth it.
One number to install it. One to keep it working.
Implementation
- Every core operation, in your Google account and your Zendesk, under your credentials
- Your ticket fields, tags, statuses and categories mapped to how you actually work
- Your brand in the customer email — logo, colour, support link, footer
- Your languages and merge fields loaded
- Your team trained on a real batch, not a slide deck
- First live run done together, second one done by them while I watch
Care plan
- Zendesk changes its API and Google changes Apps Script quotas — I keep it working through both
- Template changes, and email answered when something looks wrong
- Cancel any month, in one line, no exit call
- Everything keeps running if you do
Live means your team has sent a real batch to real customers from your own Zendesk. Not installed — used. Add-ons are scoped and quoted separately after the call, and never bundled into a number before I know what they are.
The ones that come up on every first call.
Does any of our customer data go to an AI model?
No. The composer writes templates, never per-customer emails. What comes back contains merge fields like {{GuestName}}, and the send fills those in locally, row by row.
What the model sees is the situation — what happened, to what, over what dates, what you are asking of the customer. No name, no email address, no reference number. Every prompt path in the code keeps that true, and you can read them.
Is this only for one kind of company?
No. The core operates on tickets, fields, tags and statuses — it has no idea what you sell, and nothing in it is written for a particular industry. A retailer, a lender, a SaaS company and a logistics operator all get the identical operations.
It was first built inside a support desk that needed vendors chased, so that piece exists and works. It is a module, not the product. Yours will be something else, and it gets scoped on the call.
Could this get our Zendesk account rate-limited?
No. Zendesk's ticket update cap is per account, shared with everything else you run, so every call here goes through a single function that stays under a fraction of it, honours Retry-After on a 429, and records what it spent.
A throttled row is returned to the queue unsent rather than dropped or retried blindly. Modules go through the same function — none of them get their own path to your API.
Who owns it afterwards?
You do. It is MIT licensed and it lives in your Google account, connected to your Zendesk with your own OAuth credentials. There is no server of mine in the path and no licence to renew. If you cancel the care plan, nothing switches off.
What happens if you disappear?
You keep everything. The code sits in your own Google account, the architecture is documented alongside it, and it ships with 473 assertions across 13 suites plus static checks that fail on a broken menu entry or a module reaching somewhere it should not. Any competent Apps Script developer can pick it up in an afternoon. That is deliberate — a tool only I can maintain is a liability I would not want either.
What do you need from us?
A Google Workspace account, about ten minutes of a Zendesk admin to approve an OAuth client, and roughly two hours of somebody who knows how your ticket workflow really works. That last one is the part that matters — about three hours of your team's time in total, and one of those is the training.
Bring one batch you sent by hand last month.
Twenty minutes. I will show you what it would have looked like through Mailroom, tell you which modules you'd actually need, and tell you honestly if it is not worth it for your volume. No deck.