Pre-stage overnight draft replies for review
Run an AI drafting pass overnight so the support team starts the day with replies queued, not blank threads.
Published Jan 13, 2026
The first hour of a support shift is the slowest one. Overnight mail has piled up, and every reply starts from a blank box — re-reading the question, working out the tone, typing the same kind of answer again. The thinking is small but the cold start is real, and it repeats for every thread.
This script moves that cold start to the small hours. While nobody is at a desk, it asks Claude to draft a reply to each new support email and saves it as a Gmail draft on the thread. At 9am the team opens the inbox to find replies already written — they read, tweak and send, rather than starting from nothing. Nothing is ever sent automatically; a human still approves every message.
What you’ll need
- A Gmail account that receives support mail, with a
supportlabel applied to the threads you want drafted — a filter on the inbound address is the easy way to do this. - An Anthropic API key saved as
ANTHROPIC_API_KEYin Script Properties — see Store API keys and secrets securely. - Nothing else to create. The script makes the
support/draftedmarker label itself the first time it runs.
The script
// The Anthropic API key, read once from Script Properties so it is
// never pasted into the code.
const ANTHROPIC_KEY = PropertiesService.getScriptProperties()
.getProperty('ANTHROPIC_API_KEY');
// Model and length budget for each drafted reply. Haiku is fast and
// cheap, which suits a short, friendly support answer.
const MODEL = 'claude-haiku-4-5-20251001';
const MAX_TOKENS = 400;
/**
* Finds new unread support threads, drafts a reply to each one with
* Claude, saves it as a Gmail draft, and marks the thread handled.
*/
function draftOvernightReplies() {
// 1. Pick up support threads that are unread and not yet drafted.
const threads = GmailApp.search(
'label:support is:unread -label:support/drafted'
);
if (!threads.length) return;
// 2. The marker label keeps already-drafted threads out of later runs.
const drafted = GmailApp.getUserLabelByName('support/drafted')
|| GmailApp.createLabel('support/drafted');
for (const thread of threads) {
// 3. Draft from the first message — the customer's original question.
const msg = thread.getMessages()[0];
const reply = draftWithClaude(msg.getSubject(), msg.getPlainBody());
// 4. If the API call failed, skip the thread and try again next run.
if (!reply) continue;
// 5. Save the reply as a draft on the thread — unsent, for review.
thread.createDraftReply(reply);
// 6. Mark the thread drafted so it is skipped from now on.
thread.addLabel(drafted);
}
}
/**
* Asks Claude to draft a support reply for one email. Returns the
* draft text, or null if the API call did not succeed.
*/
function draftWithClaude(subject, body) {
// Pin the persona, tone, length and sign-off so drafts are consistent.
const prompt = `You're a support engineer at Northwind Studios, a small ` +
`design and dev agency. Draft a helpful, friendly reply to this email. ` +
`Keep it under 120 words. Sign off as "— Northwind support".\n\n` +
`Subject: ${subject}\n\n${body}`;
const res = UrlFetchApp.fetch('https://api.anthropic.com/v1/messages', {
method: 'post',
contentType: 'application/json',
headers: { 'x-api-key': ANTHROPIC_KEY, 'anthropic-version': '2023-06-01' },
payload: JSON.stringify({
model: MODEL,
max_tokens: MAX_TOKENS,
messages: [{ role: 'user', content: prompt }],
}),
// muteHttpExceptions so a bad response is handled, not thrown.
muteHttpExceptions: true,
});
// A non-200 means no usable draft — return null so the caller skips it.
if (res.getResponseCode() !== 200) return null;
return JSON.parse(res.getContentText()).content[0].text.trim();
}
How it works
draftOvernightRepliessearches Gmail for threads labelledsupportthat are still unread and do not yet carrysupport/drafted. If there is nothing new, it stops immediately.- It looks up — or creates — the
support/draftedmarker label, which is how the script remembers which threads it has already handled. - For each thread it takes the first message, the customer’s original
question, and passes the subject and body to
draftWithClaude. draftWithClaudebuilds a prompt that fixes the persona, a friendly tone, a 120-word limit and the— Northwind supportsign-off, then calls Claude Haiku. If the API returns anything other than 200, it returnsnull.- Back in the loop, a
nullreply means the thread is skipped — left unread and unmarked so the next run picks it up again. - When a draft does come back,
createDraftReplysaves it on the thread as an ordinary, unsent Gmail draft, andsupport/draftedis applied so the thread never gets a second draft.
Example run
A customer emails the support address overnight:
Subject: Can’t export my project to PDF Body: Hi — when I click Export the page just spins and nothing downloads. I’m on Chrome. Help?
By 9am the thread carries a Gmail draft, ready to review:
Hi there,
Sorry the export is hanging for you. That spinner usually means the file is large or a browser extension is blocking the download. Could you try an incognito window, and let us know the project’s size? If it still fails, send us the project link and we’ll dig in straight away.
— Northwind support
The thread is now labelled support/drafted. The team member reads the draft,
adjusts anything that needs it, and hits send.
Trigger it
Run it once a night, before the team arrives:
- In the Apps Script editor, open Triggers (the clock icon).
- Click Add Trigger.
- Choose
draftOvernightReplies, event source Time-driven, type Day timer, and pick the 3am to 4am slot. - Set the script’s time zone (under Project Settings) to London so the run lands at 3am local time.
- Save and approve the authorisation prompt.
One overnight run is enough. If support volume is high you could also add a midday run, but keep the schedule sparse to control cost.
Watch out for
- Always review before sending. Drafts stay unsent until a person approves
them — never wire
createDraftReplyto an auto-send step. - The marker label is the memory. Removing
support/draftedfrom a thread makes the next run draft it again. Useful for a redo, risky if done in bulk. - One draft per thread, based on the first message only. A long back-and-forth is drafted from the original question, so a later twist in the conversation will not be reflected.
- Each thread is one API call. An overnight backlog of a few dozen emails is cheap on Haiku, but the cost rises with volume.
- A run that drafts many threads can approach the 6-minute execution limit. If the backlog is large, cap the number of threads handled per run and let the next run clear the rest.
- Claude drafts from the email text alone — it has no access to the customer’s account or order history, so it cannot confirm facts. The reviewer fills those in.
Related
Convert long email threads into a summary note
Collapse a thread's history into a Doc for handover — perfect for client transitions or vacation cover.
Updated Jun 6, 2026
Pull event RSVPs from emails into a Sheet
Parse yes/no replies to event invites and tally attendance automatically.
Updated Jun 2, 2026
Turn forwarded emails into project tasks
Forward to [email protected] and a row lands in the Projects sheet under the right client.
Updated May 30, 2026
Turn starred emails into a task list
Sync every starred thread into the Northwind Tasks sheet automatically.
Updated May 26, 2026
Alert when a label hits a backlog threshold
Warn the Northwind team in Slack when a Gmail label has more than N unread threads.
Updated Mar 31, 2026