Summary
Every day at a set time, this workflow fetches yesterday’s newsletters from Gmail, summarizes each email into concise topics with an LLM, merges all topics, renders a clean HTML digest, and emails it to your inbox.
What this workflow does
- Triggers on a daily schedule (default 16:00, server time)
- Fetches Gmail messages since yesterday using a custom search query with optional sender filters
- Retrieves and decodes each email’s HTML, subject, sender name, and date
- Prompts an LLM (GPT‑4.1‑mini) to produce a consistent JSON summary of topics per email
- Merges topics from all emails into a single list
- Renders a styled HTML email with enumerated items
- Sends the HTML digest to a specified recipient via Gmail
Apps and credentials
- Gmail OAuth2: Gmail account (read and send)
- OpenAI: OpenAi account
Typical use cases
- Daily/weekly newsletter rollups delivered as one email
- Curated digests from specific media or authors
- Team briefings that are easy to read and forward
How it works (node-by-node)
- Schedule Trigger
- Fires at the configured hour (default 16:00).
- Get many messages (Gmail → getAll, returnAll: true)
- Uses a filter like:
=(from:@.com) OR (from:@.com) OR (from:@.com -"____") after:{{ $now.minus({ days: 1 }).toFormat('yyyy/MM/dd') }}
- Returns a list of message IDs from the past day.
- Loop Over Items (Split in Batches)
- Iterates through each message ID.
- Get a message (Gmail → get)
- Retrieves the full message/payload for the current email.
- Get message data (Code)
- Extracts HTML from Gmail’s MIME parts.
- Normalizes the sender to just the display name.
- Formats the date as DD.MM.YYYY.
- Passes html, subject, from, date forward.
- Clean (Code)
- Converts DD.MM.YYYY → MM.DD (for prompt brevity).
- Passes html, subject, from, date to the LLM.
- Message a model (OpenAI, model: gpt‑4.1‑mini, JSON output)
- Prompt instructs:
- Produce JSON: { "topics": [ { "title", "descr", "subject", "from", "date" } ] }
- Split multi-news blocks into separate topics
- Combine or ignore specific blocks for particular senders (placeholders ____)
- Keep subject untranslated; other values in ____ language
- Injects subject/from/date/html from the current email
- Loop Over Items (continues)
- Processes all emails for the time window.
- Merge (Code)
- Flattens the topics arrays from all processed emails into one combined topics list.
- Create template (Code)
- Builds a complete HTML email:
- Enumerated items with title, one-line description
- Original subject and “from — date”
- Safely escapes HTML and preserves line breaks
- Inline, email-friendly styles
- Send a message (Gmail → send)
- Sends the final HTML to your recipient with a custom subject.
Node map
Node |
Type |
Purpose |
Schedule Trigger |
Trigger |
Run at a specific time each day |
Get many messages |
Gmail (getAll) |
Search emails since yesterday with filters |
Loop Over Items |
Split in Batches |
Iterate messages one-by-one |
Get a message |
Gmail (get) |
Fetch full message payload |
Get message data |
Code |
Extract HTML/subject/from/date; normalize sender and date |
Clean |
Code |
Reformat date and forward fields to LLM |
Message a model |
OpenAI |
Summarize email into JSON topics |
Merge |
Code |
Merge topics from all emails |
Create template |
Code |
Render a styled HTML email digest |
Send a message |
Gmail (send) |
Deliver the digest email |
Before you start
- Connect Gmail OAuth2 in n8n (ensure it has both read and send permissions)
- Add your OpenAI API key
- Import the provided workflow JSON into n8n
Setup instructions
- Schedule
- Schedule Trigger node:
- Set your preferred hour (server time). Default is 16:00.
- Gmail
- Get many messages:
- Adjust filters.q to your senders/labels and window:
- Example: =(from:news@publisher.com) OR (from:briefs@media.com -"promo") after:{{ $now.minus({ days: 1 }).toFormat('yyyy/MM/dd') }}
- You can use label: or category: to narrow scope.
- Send a message:
- sendTo = your email
- subject = your subject line
- message = set to {{ $json.htmlBody }} (already produced by Create template)
- The HTML body uses inline styles for broad email client support.
- OpenAI
- Message a model:
- Model: gpt‑4.1‑mini (swap to gpt‑4o‑mini or your preferred)
- Update prompt placeholders:
- ____ language → your target language
- ____ sender rules → special cases (combine blocks, ignore sections)
How to use
- The workflow runs daily at the scheduled time, compiling a digest from yesterday’s emails.
- You’ll receive one HTML email with all topics neatly listed.
- Adjust the time window or filters to change what gets included.
Customization ideas
- Time window control:
- after: {{ $now.minus({ days: X }) }} and/or add before:
- Filter by labels:
- q = label:Newsletters after:{{ $now.minus({ days: 1 }).toFormat('yyyy/MM/dd') }}
- Language:
- Set the ____ language in the LLM prompt
- Template:
- Edit “Create template” to add a header, footer, hero section, logo/branding
- Include links parsed from HTML (add an HTML parser step in “Get message data”)
- Subject line:
- Make dynamic, e.g., “Digest for {{ $now.toFormat('dd.MM.yyyy') }}”
- Sender:
- Use a dedicated Gmail account or alias for deliverability and separation
Limits and notes
- Gmail size limit for outgoing emails is ~25 MB; large digests may need pruning
- LLM usage incurs cost and latency proportional to email size and count
- HTML rendering varies across clients; inline styles are used for compatibility
- Schedule uses the n8n server’s timezone; adjust if your server runs in a different TZ
Privacy and safety
- Emails are sent to OpenAI for summarization—ensure this aligns with your data policies
- Limit the Gmail search scope to only the newsletters you want processed
- Avoid including sensitive emails in the search window
Sample output (email body)
- Title 1
- One-sentence description
- Original Subject
- → Sender — DD.MM.YYYY
- Title 2
- One-sentence description
- Original Subject
- → Sender — DD.MM.YYYY
Tips and troubleshooting
- No emails found? Check filters.q and the time window (after:)
- Model returns empty JSON? Simplify the prompt or try another model
- Odd characters in output? The template escapes HTML and preserves line breaks; verify your input encoding
- Delivery issues? Use a verified sender, set a clear subject, and avoid spammy keywords
Tags
- gmail, openai, llm, newsletters, digest, summarization, email, automation
Changelog
- v1: Initial release with scheduled time window, sender filters, LLM summarization, topic merging, and HTML email template rendering