This is the actual file I run, with my keys stripped out. Not a screenshot, not a tutorial you have to rebuild by hand — the thing itself.
What it does
- Every 15 minutes it checks Gmail for unread mail from the last day
- Skips anything it already handled
- Writes a 3–4 sentence reply in your voice — or a polite decline if it's a pitch
- Drops that draft into a private Discord channel — so it's on your phone
- Logs it to a Google Sheet so you can see what it's been saying
What you need
| Thing | Cost | Time |
|---|---|---|
| n8n (cloud trial or self-hosted) | free to start | 5 min |
| Gmail account | free | 2 min |
| Google AI Studio key | free tier, no card | 2 min |
| Discord webhook | free | 1 min |
| Google Sheet | free | 2 min |
Only three of those need a login stored in n8n. Discord is just a URL you paste in.
1 — Import the file
- Download the JSON above
- In n8n: Workflows → Import from File
- Pick the file. Six nodes appear, wired left to right
Every node shows a red warning triangle right now. That's correct — it's asking for the credentials you haven't made yet.
2 — Fill in the blanks
Gmail
Click Fetch new email → Credential → Create new → sign in with Google. n8n walks you through it.
The model key
Grab a free key at aistudio.google.com/apikey. No credit card, no prepaid balance. The free tier is capped per minute and per day, and this workflow — ten emails every fifteen minutes at most — does not come close.
In n8n, on the Draft the reply node, make a Header Auth credential:
| Name | Value |
|---|---|
| x-goog-api-key | your key, nothing else |
No Bearer, no quotes — just the key on its own.
{"reply": ..., "kind": ...}.
Discord
No credential, no bot, no permissions screen. One URL.
- Make a server for yourself if you don't have one (the + at the bottom of your server list → Create My Own)
- Make a channel called
#drafts - Channel name → Edit Channel → Integrations → Webhooks → New Webhook → Copy Webhook URL
- Paste it over
YOUR_DISCORD_WEBHOOK_URLin the Send draft to Discord node
Install Discord on your phone and the drafts arrive as notifications, same as any message.
Google Sheet
Make a sheet, name a tab DraftLog, and put these six headers in row 1:
messageId from subject kind draft sentAt
The ID is the long string in the sheet's URL between /d/ and /edit. Paste it over YOUR_SPREADSHEET_ID.
3 — Make it sound like you
Out of the box the drafts are clean and a bit flat. Open Draft the reply, find the system message, and paste two or three replies you actually wrote underneath it:
Match this person's writing. Real examples of how they reply: --- [paste a real reply you sent] --- [paste another one] --- Notice the length, the greeting, whether they use contractions, and how they end a message. Copy that. Do not improve on it.
Two real examples move it further than any amount of describing your tone in adjectives.
4 — Turn it on
Hit Execute workflow once. A draft should land in #drafts within a few seconds. If it does, flip the Active toggle top-right and close the tab.
When it goes wrong
Expected while you're testing. The memory of what it already handled only survives between runs when the workflow is Active. Manual runs in the editor don't count. Turn it on and it stops.
A working webhook answers 204 with an empty body. Green and blank output is success — check you're looking at the right channel. If you get a 401, the URL is wrong or the webhook was deleted; make a new one.
The message ran past Discord's 2,000 character limit. The node already trims to 1,900 — if you edited that line, put the .slice(0, 1900) back.
Header name has to be exactly x-goog-api-key, value is the bare key. If it returns model not found, the model name in the URL has moved on — open AI Studio, see what's current, and change that one word in the URL.
Free tier rate limit. It resets on its own. If you hit it constantly you're running the schedule far tighter than 15 minutes.
Gmail hands back different field names depending on the account, and yours aren't the ones mine had. Mine broke here first — the whole chain ran and delivered a message about nothing.
The Skip already drafted node already tries every shape I've seen, and it also prints what it found: click that node after a run and look at _debugKeys in the output. That's the exact list of field names your Gmail returned. Add whichever one holds the sender to the first(...) line for from, same for subject and body.
Check the schedule trigger is on 15 minutes, not 15 hours, and that Gmail actually has something unread from the last 24 hours. The filter also drops Promotions, Social and Updates on purpose.
Where this came from
I didn't drag these nodes around by hand. I described the flow to Claude Code, it wrote the JSON, I imported it and fixed what broke. Then I did it five more times for five other jobs.
That's the whole trick, and it's why I keep saying the moat is code: once a workflow is a text file, an AI can write it, you can version it, and you can hand it to someone else in one click. Like this one.
If it can go wrong, it will. Automate the reply and it goes wrong on a schedule you control.
Next: the 5 Illegal Claude Skills The prompts I used to get Claude building files like this one