Gmail + Google Sheets, approved LinkedIn posts
You finally sit down to post on LinkedIn… and you’re staring at a blank draft, three half-read articles, and a tab full of “save for later” links. Then you rush it. Or you overthink it. Or you just don’t post.
This is the mess marketing managers feel every week. Solo founders feel it too. And if you run an agency, “client approvals” makes it even worse. LinkedIn post approvals shouldn’t require a dozen back-and-forth messages, yet that’s what happens without a simple LinkedIn post approvals automation.
This workflow turns trending AI news into a draft, emails it for approval, logs every decision in Google Sheets, then publishes only when you say yes. You’ll see how it works, what you need, and where teams usually trip up.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Gmail + Google Sheets, approved LinkedIn posts
flowchart LR
subgraph sg0["Gmail Flow"]
direction LR
n3@{ icon: "mdi:play-circle", form: "rounded", label: "Gmail Trigger", pos: "b", h: 48 }
n4@{ icon: "mdi:message-outline", form: "rounded", label: "Gmail1", pos: "b", h: 48 }
n5@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields1", pos: "b", h: 48 }
n6@{ icon: "mdi:message-outline", form: "rounded", label: "confirmation", pos: "b", h: 48 }
n7@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model", pos: "b", h: 48 }
n8["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/merge.svg' width='40' height='40' /></div><br/>Merge"]
n9@{ icon: "mdi:robot", form: "rounded", label: "Structured Output Parser", pos: "b", h: 48 }
n10@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If", pos: "b", h: 48 }
n11@{ icon: "mdi:message-outline", form: "rounded", label: "Unread", pos: "b", h: 48 }
n15@{ icon: "mdi:swap-vertical", form: "rounded", label: "Capture Email Decision", pos: "b", h: 48 }
n16@{ icon: "mdi:database", form: "rounded", label: "Retrieve the message", pos: "b", h: 48 }
n17@{ icon: "mdi:robot", form: "rounded", label: "Generate Linkedin Posts", pos: "b", h: 48 }
n18@{ icon: "mdi:vector-polygon", form: "rounded", label: "Generate Vector Embeddings", pos: "b", h: 48 }
n19["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Publish LinkedIn Post"]
n20@{ icon: "mdi:cube-outline", form: "rounded", label: "RetrievePostExamples", pos: "b", h: 48 }
n21["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>ExtractLatestEmail2"]
n22["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>FormatLinkedInPayload"]
n23@{ icon: "mdi:swap-vertical", form: "rounded", label: "Set Linkedin Id", pos: "b", h: 48 }
n24["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/merge.svg' width='40' height='40' /></div><br/>Merge1"]
n10 --> n17
n8 --> n10
n4 --> n5
n24 --> n19
n11 --> n4
n5 --> n21
n6 --> n15
n3 --> n16
n3 --> n6
n23 --> n24
n7 -.-> n17
n21 --> n8
n16 --> n11
n20 -.-> n17
n22 --> n24
n15 --> n8
n17 --> n22
n9 -.-> n17
n18 -.-> n20
end
subgraph sg1["Schedule Flow"]
direction LR
n0@{ icon: "mdi:play-circle", form: "rounded", label: "Schedule Trigger", pos: "b", h: 48 }
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Split Articles"]
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>News API"]
n12@{ icon: "mdi:swap-vertical", form: "rounded", label: "Set Input Data (Topic/Compan..", pos: "b", h: 48 }
n13@{ icon: "mdi:message-outline", form: "rounded", label: "Send Email with News Articles", pos: "b", h: 48 }
n14@{ icon: "mdi:database", form: "rounded", label: "Log Email Activity", pos: "b", h: 48 }
n2 --> n1
n1 --> n13
n0 --> n12
n13 --> n14
n12 --> n2
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n3,n0 trigger
class n9,n17 ai
class n7 aiModel
class n20 ai
class n18 ai
class n10 decision
class n16,n14 database
class n19,n2 api
class n21,n22,n1 code
classDef customIcon fill:none,stroke:none
class n8,n19,n21,n22,n24,n1,n2 customIcon
The Problem: LinkedIn consistency dies in the approval loop
Most “we should post more on LinkedIn” plans collapse for boring reasons. Finding a relevant article takes longer than it should. Turning that article into a solid point of view takes even longer. Then comes approval: someone wants to tweak wording, someone else wants to “tone it down,” and by the time you’re aligned, the moment has passed. You end up with missed posting days, rushed content, or drafts stuck in someone’s inbox, quietly aging.
It adds up fast. Here’s where it usually breaks down in real life.
- You spend about 45 minutes reading, summarizing, and trying to sound “original” every time you want to post.
- Approvals happen in random places (email, Slack, DMs), so you can’t tell what’s actually approved.
- Without a log, you repeat ideas, reuse angles, or accidentally post something that was previously rejected.
- When you skip a week, restarting the habit feels weirdly hard, so consistency dies again.
The Solution: AI news drafts with Gmail approvals and a Sheets audit trail
This n8n workflow runs on a schedule and pulls trending AI news from NewsAPI based on topics you define. It then assembles a clean digest and emails it to you (or your team) through Gmail, with a simple approval/rejection flow that’s easy to act on. When an approval email comes back, the workflow reads that message, extracts the decision, and joins it with the original news context. If the decision is “Approve,” it uses GPT-4o-mini plus your Qdrant vector store (preloaded with examples of your best LinkedIn posts) to generate a draft in your style, builds a LinkedIn-ready payload, and posts via HTTP request to the LinkedIn API. Every interaction gets logged in Google Sheets, so you always know who approved what and when.
The workflow starts with a scheduled run and topic inputs, then NewsAPI fetches articles and Gmail sends the review email. After that, Gmail triggers watch for the approval message, Google Sheets acts as the system of record, and only approved items move through OpenAI + Qdrant to generate and publish.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you want 4 LinkedIn posts a week from AI news. Manually, you might spend about 30 minutes finding an article, 30 minutes writing a draft, and another 15 minutes chasing approval, so roughly 1.25 hours per post (about 5 hours weekly). With this workflow, you set topics once, skim the digest email in about 10 minutes, reply “Approve,” and the rest runs in the background. You’re usually down to under an hour of total human time per week, mostly reviewing, not producing.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Gmail to send digests and read approvals.
- Google Sheets to log decisions and unique IDs.
- NewsAPI key (get it from your NewsAPI dashboard).
- OpenAI API key (get it from the OpenAI API keys page).
- Qdrant URL/API key (get it from your Qdrant deployment settings).
- LinkedIn developer access to publish via the LinkedIn API.
Skill level: Intermediate. You’ll connect accounts, add API keys, and adjust a few IDs and email fields.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A scheduled trigger kicks things off. On the interval you choose, the workflow loads your topic inputs and starts the news pull.
News is fetched and turned into a digest. NewsAPI returns articles, then n8n assembles a readable summary and sends it via Gmail, while also recording a unique ID and initial log row in Google Sheets.
Approval is captured from your inbox. A Gmail trigger watches for the confirmation reply, reads the message content, extracts “Approve” or “Reject,” and merges it back with the original news context tied to that unique ID.
Approved items become LinkedIn posts. If the decision is approved, OpenAI generates embeddings, Qdrant retrieves your example posts for style guidance, GPT-4o-mini composes the final draft, and an HTTP request posts it to LinkedIn.
You can easily modify the topics and the tone to match your brand voice based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Scheduled Run Trigger
Set the schedule that initiates the news digest collection process.
- Add and open Scheduled Run Trigger.
- Define the schedule in Rule based on how often you want the news digest to run.
- Confirm the trigger is connected to Define Topic Inputs as shown in the workflow.
Step 2: Connect NewsAPI and Define Topics
Configure the keyword input and the NewsAPI request that fetches recent articles.
- Open Define Topic Inputs and set the keyword assignment to
ai. - Open NewsAPI Fetch and set URL to
=https://newsapi.org/v2/everything?q={{ encodeURIComponent($json.keyword) }}&sortBy=publishedAt&language=en&pageSize=5&from={{ new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0] }}. - Credential Required: Connect your httpQueryAuth credentials in NewsAPI Fetch.
Step 3: Assemble and Send the News Digest Email
Build the email body from NewsAPI results and deliver the digest via Gmail, then log the send in Google Sheets.
- Open Assemble Article Digest and keep the provided jsCode to format the HTML digest.
- Open Dispatch News Email and set Send To to
[YOUR_EMAIL], Subject toLatest Ai news, and Message to=Latest articles {{ $json.email_subject }}{{ $json.email_body }}. - Credential Required: Connect your gmailOAuth2 credentials in Dispatch News Email.
- Open Record Email Log, set Operation to
append, Document ID to[YOUR_ID], and Sheet Name to[YOUR_ID]. - Confirm the column mappings include Timestamp
={{ new Date().toISOString() }}, Message-ID={{ $json.id }}, and Recipient[YOUR_EMAIL]. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Record Email Log.
[YOUR_EMAIL] and [YOUR_ID] placeholders in Dispatch News Email and Record Email Log before testing.Step 4: Configure Inbox Monitoring and Approval Inputs
Watch for approval emails and enrich the workflow with the latest email content and decision data.
- Open Inbox Watch Trigger and set Sender to
[YOUR_EMAIL], Read Status tounread, and polling toeveryMinute. - Credential Required: Connect your gmailOAuth2 credentials in Inbox Watch Trigger.
- Inbox Watch Trigger outputs to both Get Sheet Message and Read Confirmation Mail in parallel.
- Open Get Sheet Message and set Document ID to
[YOUR_ID]and Sheet Name to[YOUR_ID]. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Get Sheet Message.
- Open Mark Email Read and set Message ID to
={{ $('Inbox Watch Trigger').item.json.id }}. - Credential Required: Connect your gmailOAuth2 credentials in Mark Email Read.
- Open Retrieve Email Detail and set Message ID to
={{ $json.id }}with Simple set tofalse. - Credential Required: Connect your gmailOAuth2 credentials in Retrieve Email Detail.
- Open Map Email Content and set content to
={{ $json.text }}. - Open Select Latest Email and keep jsCode as
return [$input.all().slice(-1)[0]];. - Open Read Confirmation Mail and set Message ID to
={{ $json.id }}. - Credential Required: Connect your gmailOAuth2 credentials in Read Confirmation Mail.
- Open Capture Approval Decision and set decision to
={{ $json.snippet }}.
Step 5: Merge Inputs and Gate Publishing
Combine email content and approval decision, then allow only complete data to proceed.
- Open Combine Inputs and set Mode to
combinewith Combine By set tocombineByPosition. - Open Decision Gate and confirm the two conditions check
= {{ $json.decision }}and={{ $json.content }}with Operation set tonotEmpty.
Step 6: Set Up AI LinkedIn Generation and Publishing
Generate a structured LinkedIn post with AI, build the API payload, and publish to LinkedIn.
- Open OpenAI Chat Engine and select the Model
gpt-4o-mini. - Credential Required: Connect your openAiApi credentials in OpenAI Chat Engine.
- Open Fetch Post Examples and set Mode to
retrieve-as-tool, Tool Name tolinkedin_posts, and Top K to10. - Credential Required: Connect your qdrantApi credentials in Fetch Post Examples.
- Open Create Vector Embeddings and note it provides embeddings to Fetch Post Examples for retrieval.
- Credential Required: Connect your openAiApi credentials in Create Vector Embeddings.
- Open Compose LinkedIn Post and keep the Text prompt with
{{ $json.content }}and{{ $json.decision }}references intact. - Confirm Parse Structured Output is connected as the output parser for Compose LinkedIn Post; credentials are handled by OpenAI Chat Engine.
- Open Build LinkedIn Payload and replace
[YOUR_ID]in the code with your LinkedIn profile ID. - Open Set LinkedIn Author and set author to
[YOUR_ID]. - Open Merge Publish Data and set Mode to
combinewith Combine By set tocombineAll. - Open Post to LinkedIn and keep URL as
https://api.linkedin.com/rest/postsand JSON Body as={ "author": "{{ $json.author }}", "commentary":"{{ $json.commentary }}", "visibility": "PUBLIC", "lifecycleState": "PUBLISHED", "distribution": { "feedDistribution": "MAIN_FEED", "targetEntities": [], "thirdPartyDistributionChannels": [] } }. - Credential Required: Connect your linkedInOAuth2Api credentials in Post to LinkedIn.
202503 in Post to LinkedIn.Step 7: Test and Activate Your Workflow
Run a manual test to validate data flow and then activate the workflow for production use.
- Click Execute Workflow to trigger Scheduled Run Trigger and confirm Dispatch News Email sends a digest to
[YOUR_EMAIL]. - Send an approval email that matches Inbox Watch Trigger filters and confirm Decision Gate routes to Compose LinkedIn Post.
- Check Record Email Log for a new row with a timestamp and message ID.
- Verify a successful LinkedIn post appears after Post to LinkedIn runs.
- Toggle the workflow to Active to enable scheduled and inbox-triggered automation.
Common Gotchas
- Gmail credentials can expire or need specific permissions. If things break, check the n8n Credentials screen and your connected Google account security settings first.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- LinkedIn API publishing can fail if your app permissions or author URN are wrong. Double-check your “Set LinkedIn Author” value and the LinkedIn developer app scopes before you blame the workflow.
Frequently Asked Questions
About 45 minutes if you already have the API keys and accounts.
No. You’ll mostly connect accounts and paste API keys. The only “technical” part is copying the right IDs (your Sheet ID, Qdrant URL, and LinkedIn author value) into the right fields.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in OpenAI API costs (often a few dollars a month at low volume) and any Qdrant hosting costs.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and you should. Most people edit the “Define Topic Inputs” node to change what NewsAPI pulls, then adjust the system message in the “AI Agent” and the prompt in “Compose LinkedIn Post” to match brand voice. You can also swap the Qdrant collection from “posts” to a client-specific collection if you manage multiple brands.
Usually it’s permissions. The Google account connected in n8n needs access to the exact spreadsheet ID you configured, and the sheet/tab name must match what the node expects. If it worked once and then stopped, re-authenticate the Google Sheets credential in n8n and confirm the spreadsheet wasn’t moved to a different Drive or restricted by an admin policy.
Dozens per week for most small teams, and more if your API limits allow it.
Often, yes, if you want the “real workflow” version instead of a couple of connected triggers. This setup uses multiple paths (scheduled run, inbox-trigger approvals, a decision gate, and a publish branch), and n8n handles that kind of logic without turning it into a pricing puzzle. It also plays nicely with self-hosting, which matters once you start generating drafts daily. Zapier or Make can still be fine if you only need a basic “generate draft then email it” flow with no vector store and no structured approval tracking. If you’re torn, Talk to an automation expert and get a quick recommendation.
You keep control of what gets posted, but you stop paying the “blank page tax” every week. Set it up once, then let the workflow do the repetitive work.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.