How I Automated a Daily Email Digest Using Prompt Triggers
1. Starting with Notion databases and AI summaries in theory
The idea sounded simple enough when I scribbled it on a sticky note: scrape all the action items from three Notion boards, summarize them with an AI model, then send the results to my inbox every morning before I open Slack. The sticky note is now under my coffee mug. Reality: Notion doesn’t natively trigger when you want it to, and Zapier’s Notion integration likes to forget which row is new.
First version used a daily schedule in Zapier to pull every row updated in the last 24 hours. That kind of worked, until I realized it was also picking up archived tasks, moved Kanban cards, and anything I’d edited just to change a tag. This made the OpenAI prompt useless — too much noise feeding into the model. I’d either over-summarize junk or completely miss that someone added a major update at 11:59 PM the night before.
The Notion API structure doesn’t make it easy to detect semantic edits either — all changes look the same at the Zap level. I tried using the last_edited_time
property but even typing a space and removing it re-triggers the timestamp.
Quick fix that half-worked
I added a filter: only grab rows where a specific “Needs Summary” checkbox was toggled. Now, teammates had to deliberately flag rows. This cut down on noise but added manual work — and half the time people forgot to check it. That’s when I started thinking about prompt triggers over fixed filters.
2. Prompt-specific logic using Google Sheets as a buffer zone
When the Notion filters got too flaky, I detoured through Google Sheets. Basically:
- Zap 1: Nightly scrape of Notion pages into a sheet, regardless of flags
- Zap 2: For each row, run three GPT-4 prompts and return outputs into adjacent columns (summary, urgency score, sentiment)
- Zap 3: Select rows where summary exists AND urgency score > 7 → compile body of the digest email
Using Sheets as an isolated staging area actually calmed everything down. I could inspect raw GPT outputs, tweak prompt params (temperature, system prompt contexts), and re-run logic without hammering the Notion API.
But I ran into a weird bug where Zapier thought blank cells were “not set”, even though the GPT output clearly existed. The filter step would silently skip these rows. Turned out the issue was with Google Sheet formatting — if the cell had been formatted as ‘Date’ previously, it ignored raw string inputs.
Now I pre-format all columns that hold AI output as plain text before the zap ever touches them. That bug cost me about an hour and three test runs with no result.
3. GPT prompt tweaks based on internal link context detection
One of the Notion columns I was pulling was “Notes”, which often had sentences like, “See Doc: REDACT Pricing” or “Follow-up with Linda about QBR items”. These references only make sense within our tiny team context, and GPT-4 kept summarizing with, “User should reference REDACT Pricing” — not helpful.
So I added a pre-processing step. Anything in the notes that matched ‘Doc:’ or ‘Follow-up with’ got passed through a mini prompt that just asked:
Take this line as internal communication. Is it actionable or just context? Return only if actionable.
That cleaned it up. GPT-4 only kept items that were marked as decisions or assignments. And here’s the weird part: if I added invisible zero-width spaces around ‘Doc:’, the string stopped getting flagged as actionable. GPT tokenization definitely didn’t like that. Probably an encoding mismatch from Notion’s export to plain text.
4. Constructing a readable email body block by block with conditionals
Once I narrowed down meaningful summaries, I had to build the email text. Zapier’s Gmail module lets you inject HTML, but if you try anything fancy — like two-line summaries in bullet format with links — Google pre-spams it.
So no formatting, minimal decoration. Here’s the structure I ended up using:
## Summary for [Board Name]
- [High urgency?] [Short AI summary]
- [Medium priority] [Short summary]
Every section header was conditional: If at least one row existed from that board, build the block. Otherwise skip. I learned that if you try inserting an empty header (e.g., “## Summary for Finance”) with no bullets underneath, Gmail truncates your email preview.
Also, blank lines at the top kill previews too. No leading newlines allowed. Gmail decided the whole message was blank once because the first thing was a newline followed by a Markdown comment.
5. Handling model drift across GPT versions and token budgets
I originally used GPT-3.5-turbo for summarizing tasks but after about two weeks, the tone shifted. Summaries got weirdly enthusiastic — “This exciting opportunity awaits follow-up!” From meeting reports.
I switched to GPT-4 and immediately hit a token wall. The prompt plus daily task data started bumping past the 8K limit. Even though the payload was under 5K characters, tokens blow up fast — especially when JSON metadata sneak in.
Unintuitive fix that did help
I stripped all JSON properties and re-passed as clean markdown:
**Task**: Email Linda
**Context**: Quarterly biz review needs prep
**Due**: Tomorrow
Model stuck closer to plaintext outputs, and hallucinations dropped. Also, the token count stabilized — markdown apparently compresses better inside OpenAI’s tokenizer. I would never have guessed this without dumping usage logs and counting tokens by hand using the OpenAI tokenizer estimator.
6. Undocumented edge cases with Gmail throttling and Zap loops
The first time this ran successfully with 30+ items in the digest, Gmail blocked it. Not delayed, not marked as spam — totally dropped. No error returned, Zapier zap completed unexpectedly “fine”.
I had to re-enable “Send As” from a delegated inbox, even though I was technically under Gmail’s limit. According to one tucked-away Gmail setting, if you send multiple similar emails programmatically from the same source within a 30-minute window, Google will clamp down — even internally.
Another failure I missed for three days: the digest zap was re-triggering off its own write action into Sheets. So I was getting earlier versions double-sent with overlapping summaries. Fixed this by adding a time window condition: only process Notion rows timestamped earlier than the current zap trigger timestamp.
7. Testing strategy when live data keeps changing under you
Every staging output had a different result depending on when I ran the test. At one point, just toggling a column in Notion made five summaries shift from high priority to medium, because GPT reweighted everything contextually. This made reproducible tests nearly impossible. I had to snapshot a frozen sheet, run the zap over that, and only then did outputs stabilize.
Also, beware of hidden characters in Notion checkboxes. I had a task where someone pasted a checkbox inside a bullet list — not the native checkbox property. Zapier didn’t recognize it. Visually it looked identical, but in API output it’s pure text. That non-native box threw off my priority filter silently for three days.
8. Real output metrics and how team reactions altered structure
After a few weeks, people stopped ignoring the digest. The summary block with key actions worked — but only when I bolded the people’s names at the start of each task. That turned out to be the key factor. Quote from our head of ops: “I scroll fast, give me just my name with a verb.”
So now the AI summaries are templated to output format like: “Linda: Needs finalize draft by noon.” If it’s missing a person, I fallback to a generic “[Someone] needs to…” but that’s rare. GPT-4 is decent at pulling who’s responsible when there’s a clear verb-object structure.
Also added a little footer that says “Reply with ‘done’ on an item to remove it tomorrow.” That part isn’t automated — yet. But people started doing it, so it might be next week’s Zap.