Slack, Gmail, Google Sheets and Drive: the four nodes most office requests are made of
Ask around an office for a week and the automation requests keep naming the same four services. A Slack message when a customer signs up. A Gmail thank-you when a form comes in. A row in Google Sheets every night. A customer's upload filed into its own folder on Google Drive. This article covers the operation you will actually use from each node, the credential each one needs, the trap each one hides — and then wires all four into a single workflow that runs end to end.
The services the requests keep naming
Part 5 laid out the node families and Part 6 had you build a workflow by hand. Back at a desk, though, nobody asks for a node family. They ask for something like this:
Slack for notifications, Gmail for mail, Google Sheets for records, Google Drive for storage. Between them these four have close to a monopoly on the everyday tools of a small or mid-sized office — the source guide puts around 90% of office automation on top of them, and reckons that learning their nodes covers roughly 80% of the internal requests you will be handed.
The services left over are not a separate problem. Notion, Airtable and Zoom work much the same way, and anything without a node at all you can call yourself with the HTTP Request node, which is Part 9's subject.
Every SaaS node asks the same three questions
Open the Slack node and you get three dropdown menus at the top. Open Gmail, Google Sheets, Google Drive, or a node you have never seen before, and there they are again. This is the common language n8n gave all of its SaaS nodes, and it is the single most useful thing in this article.
| Dropdown level | What it is asking | Slack example | Gmail example |
|---|---|---|---|
| 1. Credential (the account) | Which account do you want to connect with? | Your personal Slack workspace, or the company workspace | Your Gmail, or the company Gmail |
| 2. Resource (the category) | Which kind of thing in this service do you want to work on? | Message, Channel, User | Message, Draft, Label |
| 3. Operation (the action) | What do you want to do to that category? | Send, Update, Delete, Get | Send, Get Many, Reply, Delete |
It is a hardware shop with three signs over the counter. The first asks whose account is paying. The second asks which aisle you want — paint, timber, fixings. The third asks what you want done with it: cut, mixed, delivered. Change the aisle and the third sign changes completely, because nobody gets timber mixed. That is exactly what happens when you change Resource in an n8n node, and it is not a fault.
flowchart TD A["Open any SaaS node"] --> B["1 · Credential
which account is this acting as"] B --> C["2 · Resource
which kind of thing in that service"] C --> D["3 · Operation
what to do to that thing"] D --> E["Every field below here is redrawn
to fit the Resource and Operation you chose"]
The notification workhorse, and the file it will not carry
Slack is the node people reach for most when the point is to tell somebody something. Sales numbers, build results, incoming orders — it is the fastest way to put a line in front of a team.
In n8n v1 the Slack node's full Resource list has seven entries: Channel, File, Message, Reaction, Star, User, User Group. Day to day you will live inside a handful of pairings.
| Resource | Operation | When to use it |
|---|---|---|
| Message | Send | Post a message to a channel or someone's DM — the most common thing this node does |
| Message | Get Many | Pull recent messages from a channel to search or analyze them |
| Message | Update | Edit a message you already sent, for example changing “In progress” to “Done” |
| User | Get | Look up a Slack user ID from an email address, so you can @ that person in a message |
| Channel | Create | Open a dedicated channel automatically for every new customer |
| File | Upload | Send a binary file to a channel |
| Reaction | Add | Put an emoji reaction on a message — a check mark once something is handled, say |
Two ways to do the credential
The node's Authentication dropdown offers two, called Access Token and OAuth2, and the same Slack node can switch between them whenever you like.
| Option | Setup effort | When to choose it |
|---|---|---|
| Slack API (Access Token) | Medium. You create an App in Slack first, then take the Bot User OAuth Token (xoxb-…) or the User OAuth Token (xoxp-…) and paste it into the Access Token field |
You administer the workspace and want messages to go out under a fixed bot identity (xoxb-), or as a real person (xoxp-) |
| Slack OAuth2 API | Low. One click opens the authorization page and you sign in with your account | You are an ordinary member of the workspace and want to post “as yourself” |
What you can type into the Text field
The Text field on Message → Send is not plain text. Slack has its own markdown, and it is not quite the markdown you are used to.
| What you type | How it renders |
|---|---|
*important* | Bold — Slack uses one asterisk, not two |
_italic_ | Italic |
~strikethrough~ | Strikethrough |
`code` | Inline code style |
<@U01ABC2DEF> | @-mention a user, by user ID rather than by email |
<#C01XYZ> | Link to a channel |
<!channel> | Notify the whole channel. It buzzes every phone in it, so use this sparingly |
The file it will not carry
This one surprises people. Message → Send does not take binary attachments. If you need to put a file in a channel, that is a second node: File → Upload, with the channel in Channel and data in Input Data Field Name, matching the binary property the node before it produced. The upload itself produces a message with the file on it. Text and a file at the same time means chaining the two nodes.
flowchart LR
A["Something happened upstream"] --> B{"What do you need
to put in the channel"}
B -->|"words only"| C["Slack node
Message → Send"]
B -->|"a file only"| D["Slack node
File → Upload"]
B -->|"both"| E["Slack node
Message → Send"]
E --> F["then a second Slack node
File → Upload"]
C --> G["It appears in the channel"]
D --> G
F --> G
#general, the channel name with the hash, or C01XYZ123, the channel ID you get by right-clicking the Slack channel and copying the link. When a channel has been renamed, or its name contains non-Latin characters, only the ID works.Sending, fetching, and the quota that ends the day
The Gmail node sends mail and fetches mail: marketing thank-you notes, support replies, sales watching for a customer's answer.
| Resource | Operation | When to use it |
|---|---|---|
| Message | Send | Send a new email — the most common |
| Message | Reply | Reply to an existing email, keeping the thread |
| Message | Get Many | Fetch mail from the inbox; pair it with Search to find a particular sender or subject |
| Message | Add Label | Label an email automatically to file it. Note that Add Label hangs off Message |
| Draft | Create | Create a draft so a person confirms it before it goes out — the shape of a review workflow |
| Label | Create | Create a new label. The Label resource has only Create, Delete, Get and Get Many — it has no Add of its own |
One credential type, and what it is doing
The Gmail node supports Google OAuth2 and nothing else. The first time you set it up, a Google authorization page opens, you sign in and agree to read and write access for Gmail. It takes well under a minute. What is worth understanding is what you now hold.
An OAuth grant is two pieces of paper, not one. The access token is a day pass: it works for an hour and then it is waste paper. The refresh token is the membership card, and it does not expire — n8n keeps it and uses it to collect a fresh day pass every hour without telling you. Which is why the only things that ever break this are the things that cancel a membership: revoking n8n by hand, or changing the password on an account with two-step verification.
stateDiagram-v2 [*] --> Authorized : you agree on the Google consent screen Authorized --> Working : n8n stores the refresh token Working --> Working : the access token expires each hour and n8n quietly swaps in a new one Working --> Blocked : you revoke n8n in Google account settings, or change the password with two-step on Blocked --> Authorized : reauthorize on the Credentials page
What Send can do
- Plain text or HTML. Switch with the Email Type dropdown. With HTML you can paste a complete HTML document and design a styled email.
- To, CC, BCC and Reply-To. All four recipient fields take several addresses, comma-separated.
- Attachments. The Binary Data toggle, with the property name matching the file the node before it produced.
- A subject built from an expression. The subject line can be assembled at run time —
Order #{{ $json.order_id }} confirmed, for instance. Expression syntax is Part 10's subject.
Fetching mail uses Gmail's own search syntax
Under Message → Get Many there is a Filters block, and inside it a field called Search. It is not called Filter, so do not go hunting for that word. Whatever you would type into the search bar of Gmail on the web works here unchanged.
| Search value | What it means |
|---|---|
is:unread | Unread only |
from: followed by an address | Only what that one sender sent |
subject:quote | Subject contains “quote” |
has:attachment | Has an attachment |
newer_than:1d | Mail from the last day |
from:@customer.com is:unread | Combined — unread mail from a customer domain |
The trigger is a different node
To start a workflow when mail arrives you need Gmail Trigger, which is a separate node from Gmail. It polls rather than listening: the Poll Times dropdown offers Every Minute, Every Hour, Every Day and so on, and by default it pulls 10 messages at a time, which Options → Limit takes up to 50. Every Minute gets you close to instant, but polling that often on a large account will get you rate-limited by the Google API.
The office database, matched by header name
For a great many small and mid-sized companies, Google Sheets is the database. The CRM is a Sheet. The stock list is a Sheet. The event sign-up list is a Sheet. Learning this node is learning how to let n8n read and write the office's actual data.
| Resource | Operation | When to use it |
|---|---|---|
| Sheet Within Document | Append Row | Add a row. The most common by a distance — a new customer into Sheets, an event logged |
| Sheet Within Document | Append or Update Row | Update the row if the key you name already exists, append it if it does not. An upsert |
| Sheet Within Document | Get Row(s) | Read the whole sheet, or the rows matching a condition. It is not called Read |
| Sheet Within Document | Update Row | Find a row with Column to Match On and change it |
| Sheet Within Document | Delete Rows or Columns | Delete the rows or columns you name. Rarely needed, and destructive |
| Sheet Within Document | Clear | Empty the contents of a range but keep the column structure |
Two credential choices, and they suit different people
Google OAuth2
Individuals and small teams. Quick to set up, and you authorize with your own Google account. The automation is tied to you, which is fine right up until you leave.
Service Account
The recommendation for companies. Create a machine account that is not a real person, then share the Sheets it needs with that machine email address. People leaving does not break the automation.
Append Row, field by field
-
Step 1
Pick the Document
The dropdown lists every Google Sheets file on the account, so usually you just pick one. You can also paste a URL, or a Sheet ID.
-
Step 2
Pick the Sheet, meaning the tab
One Sheets file can hold several tabs. Pick the right one now rather than wondering later why the rows are landing somewhere you are not looking.
-
Step 3
Set Mapping Column Mode to manual
The Mapping Column Mode dropdown has three options: Map Automatically, which fills the row on its own as long as the keys in the upstream JSON match the Sheets headers exactly; Map Each Column Manually, where you write an expression into each box yourself; and Nothing. When you are not certain the names line up, go manual. In automatic mode a single key with a different name leaves that column silently empty.
-
Step 4
Fill in an expression per column
n8n lists every header in the Sheet — say Name, Email and Signed up at — with an input box for each. You drop an expression into each box:
{{ $json.name }}{{ $json.email }}{{ $now }}
Update, and the one field that decides everything
The Update operation hinges on Column to Match On, where you choose which column acts as the key for finding the row. Take a customer status sheet keyed on Email. Upstream sends an object with two fields:
| Field | Value |
|---|---|
email | The customer's address — the key the row is found by |
status | "paid" |
The Sheets node looks for the row whose Email column holds that address, and sets its status column to "paid". If no row matches, nothing happens — and, importantly, nothing errors either.
Sheets matches column headers as exact strings, and that is stricter than it sounds. “Email ” with a trailing space and “Email” are two different columns to it. It is the difference between a parcel addressed to Flat 3 and one addressed to Flat 3 with an extra space after it. A person delivering by hand would not notice. A sorting machine puts the second one in a different bin.
Files in, files out, and a field that refuses names
The Drive node stores files and fetches them: filing a customer upload, putting a daily backup CSV in the cloud, downloading an attachment so the next node can use it.
| Resource | Operation | When to use it |
|---|---|---|
| File | Upload | Store the previous node's binary in Drive |
| File | Download | Fetch a file's contents by file ID. It hands binary to the next node |
| File | Copy | Copy it into another folder |
| File | Move | Move the file to a different folder |
| File | Share | Grant a sharing permission, for example read access for one email address |
| File | Create from Text | Create a file straight from a string — saving JSON as a .txt, say |
| File/Folder | Search | Find files or folders by file name or MIME type. Search belongs to the combined File/Folder resource, not to File |
| Folder | Create / Delete / Share | Folders have their own operations too |
| Shared Drive | Create / Get / Get Many / Update / Delete | Work on the shared drive itself, rather than on the files inside it |
The credential is Google OAuth2, the same as Gmail. If you already made a Gmail credential, the Drive node lets you pick that same one without authorizing again.
Upload needs three things
| Field | What to enter |
|---|---|
| Input Data Field Name | The binary property name the node before it produced — usually data |
| File Name | What it should be called once stored. An expression can build this dynamically |
| Parent (Drive + Folder) | Which drive and folder to store it in. This is a Resource Locator field, with three modes |
The Parent field has three modes and no fourth
From n8n v1 on, the Drive and Folder fields on the Google Drive node are both Resource Locator fields: one field, three modes you switch between.
| Mode | What to enter |
|---|---|
| From list | A dropdown of every folder and drive on your account. Click one |
| By URL | Paste the folder URL, of the shape https://drive.google.com/drive/folders/1aBcDeFg…, and n8n pulls the ID out of it |
| By ID | Paste the folder ID directly — the string that comes after folders/ |
All three get you to the same folder. What you cannot type is the folder's name — a name will not do, and anything that is not an ID, a URL or a pick from the list is rejected. That feels unhelpful until you think about a courier: “the blue house on the corner” is how a person finds a place, and a postcode is how a system finds it. Two folders can both be called Invoices. Only one has that ID.
Download needs only a File ID
The file ID usually arrives from the node before it — a Drive Search, or a trigger. You can also read it off a share link yourself: in a link of the shape drive.google.com/file/d/1xxx/view, the string in the middle is the file ID. The download hands binary downstream, ready for a Slack node to attach or a Gmail node to send.
One form entry, four services, one line
Here is the scenario, and it is a real one. A customer fills in a Google Form and uploads a file with it. You want to send them a thank-you email automatically, attach the file they uploaded, and tell the sales channel on Slack that a new customer has arrived.
flowchart LR A["Google Sheets Trigger
Row Added"] --> B["Google Drive
File → Download"] B --> C["Gmail
Message → Send"] C --> D["Slack
Message → Send"] A -.->|"Name, Email, Subject"| C A -.->|"Name, Email, Subject"| D B -.->|"binary in data"| C
-
Step 1
Trigger on a new row
Drop in a Google Sheets Trigger. Most Google Forms write their responses into a Sheet automatically, so a new response is a new row. Set Trigger On to Row Added, and use the Resource Locator to point Document and Sheet at the Sheet holding the form responses. Every Minute is fine for Poll Times.
-
Step 2
Fetch the file the customer uploaded
If the form has a file-upload question, that row holds a share link to a Drive file rather than the file itself. Add a
Google Drive → File → Downloadnode and pull the file ID out of the URL from the previous step:{{ $json["Attachment"].split("id=")[1] }}When this step finishes it emits binary, which everything downstream can use as an attachment.
-
Step 3
Email the person who filled in the form
Add a
Gmail → Message → Sendnode. In To, refer back to the Email column of the form:{{ $('Google Sheets Trigger').item.json["Email"] }}In Subject, put:
Thank you for your submission - Hello {{ $('Google Sheets Trigger').item.json["Name"] }}Write your thank-you text into Message. Then expand
Options → Attachmentsand putdatain Property Name (Binary) — that is what sends the file downloaded in step 2 along with the email. -
Step 4
Tell the sales channel
Add a
Slack → Message → Sendnode. Pick#new-formsas the Channel, or better, its channel ID. Build the Text with an expression:*New form submission!*\nName: {{ $('Google Sheets Trigger').item.json["Name"] }}\nEmail: {{ $('Google Sheets Trigger').item.json["Email"] }}\nSubject: {{ $('Google Sheets Trigger').item.json["Subject"] }}\nThank-you email sent automatically :white_check_mark: -
Step 5
Save, then test it once by hand
Save with
Ctrl + Sat the top right. Go and fill in the Google Form yourself with some fake data, come back to n8n and press Execute Workflow. Once all four nodes have turned green with a check, look in the mailbox to see whether the email arrived, and in Slack to see whether the notification landed. Green nodes are a claim, not a confirmation. -
Step 6
Turn on the Active toggle
Once the test is clean, flip Active at the top right. From that moment, every form submission runs this workflow without you.
The same node, several accounts
On the Credentials page in the left-hand menu you can create several credentials of the same kind — a Slack personal workspace, a Slack company workspace, a Slack customer A workspace. The Credential dropdown on each Slack node then picks which one that node uses.
That means one workflow can hold two Slack nodes talking to different workspaces: internal notices to the company workspace, customer replies to the customer's. Gmail, Sheets and Drive work the same way. Name them so the dropdown is readable — Slack - Personal and Slack - Company beats two entries both called Slack. Naming, sharing and revoking credentials properly is Part 10.
Ten symptoms, and where each one actually lives
Almost everything that goes wrong with these four nodes is one of ten things. Place the symptom before you start changing settings.
flowchart TD A["Every node went green,
but nothing arrived"] --> B{"Which node was the
last real action"} B -->|"Slack"| C{"Did you give it a channel name
or a channel ID"} C -->|"name"| C1["Switch to the channel ID, and check
the bot has been added to that channel"] C -->|"ID"| C2["Read the node output for
invalid_auth or not_authed"] B -->|"Gmail"| D["Insufficient Permission means the grant
is missing a scope. Delete the credential
and authorize again, ticking every box"] B -->|"Sheets"| E{"Append, or Update"} E -->|"Append"| E1["Compare the header row
character for character"] E -->|"Update"| E2["Column to Match On found nothing.
Usually a number against a string"] B -->|"Drive"| F["Check the Parent mode, and whether
Include Shared Drives is ticked"]
| Symptom | Cause | How to fix it |
|---|---|---|
The Slack node returns 401 invalid_auth or not_authed |
The bot token has expired, or the bot was never invited into the channel you are posting to | Go back to the Slack workspace and add the bot to the channel: right-click the channel → View channel details → Integrations → Add app. If the token has expired, generate a new one and paste it back into the credential |
| Slack says the message was sent, but it is nowhere in the channel | It went to your own DM or to the wrong channel — you typed general instead of #general |
Put the channel ID (C01XYZ) in the Channel field instead of the name. That goes wrong least often. Copy the ID from the bottom of the channel details page |
The Gmail node returns Insufficient Permission |
The OAuth grant did not include the send scope — you ticked read only, for instance | Go to the credentials page, delete this Gmail OAuth credential and authorize again, this time ticking every checkbox on the consent screen |
| Gmail sends a lot of mail in one day and then suddenly stops | You went past Google's daily sending quota — 500 a day on an ordinary account | Wait 24 hours, or move to a Google Workspace account (2000 a day). For sustained bulk sending, switch to a dedicated sending service such as SendGrid or Postmark |
| The Sheets Append runs fine, but the row is missing some of its columns | A column name was mistyped while mapping, or the header in Sheets has a leading or trailing space. Capitalization has to match too | Go back to Sheets and check every cell in the header row for spaces. The column names in the n8n node have to match Sheets exactly, capitalization included |
| Sheets Update cannot find the row: no error, but nothing changed | The column chosen in Column to Match has no matching value — usually a type problem, with Sheets holding the number 123 and you sending the string "123" |
Add a type conversion to the expression, {{ String($json.id) }}, or go the other way and set that Sheets column to plain text first |
| Drive Upload succeeds, but the file lands in the root of My Drive | The Parent field is in the wrong mode — left on By ID with a folder URL pasted in, or on By URL with a bare ID | Switching the Resource Locator to From list and picking from the dropdown is safest. Otherwise use By URL and paste the full drive.google.com/drive/folders/… address; the ID mode takes an ID and nothing else |
| The Drive node cannot see the files on a shared drive | Include Shared Drives is not ticked on the Google OAuth2 credential | Go back to the credential settings, tick that option and save, then return to the node and refresh the Document or Folder dropdown |
| There is clearly new mail, but the Gmail Trigger does not fire | Poll Times is on Every Hour or Every Day, so the wait is too long — or the Filters block (Sender, Label IDs, Read Status, Search) filtered the new mail out | Clear the Filters and set Poll Times to Every Minute to test. Once you are sure the trigger reacts, add the filters back one at a time |
The run looks like a success, but a downstream node reads undefined |
The field names the SaaS node emits are not the ones you assumed — a Sheets column name with a full-width space in it, or Gmail's field being subject rather than Subject |
Press Execute Node on the upstream node to see what the JSON actually looks like, and write the expression with its real field names |
One thing separates these nodes from the ones that only shuffle data around: their steps are letters in a postbox, not drafts on a desk. A Gmail that has gone out cannot be recalled. A Slack message that has been posted cannot be unposted. So put the checks and the log row before the irreversible step, not after it — write to Sheets, then send the mail — and when something does go wrong, the log is what tells you how far it got.
Do I have to use the official nodes? Can I write the API call myself?
I have two Slack workspaces, a personal one and the company one. What do I do?
Slack - Personal and Slack - Company. Each Slack node then lets you pick which one it uses. One workflow can hold several Slack nodes on different workspaces, which is genuinely useful: notifying the customer's Slack and your internal Slack in one pass.How many emails can Gmail send in a day?
How many rows can Google Sheets read at once? Does a huge sheet break it?
A1:D1000, then A1001:D2000), or, if the data really is large, move to Airtable, Notion or an actual database with the Postgres or MySQL nodes.Will Drive Upload struggle with a large file, say a video of a few hundred MB?
How long does an OAuth grant last? Will it expire and need reconnecting?
When the Sheets node writes, does the column order get scrambled?
If the four nodes run one after another, can they interfere with each other?
Where to go from here
Four nodes down. Now the one that covers everything else.
Part 9 takes on the HTTP Request node: how to call a service that has no node of its own, assemble the headers and payload yourself, and read back what comes out — the escape hatch behind every integration in this article.
Open the full guidePart 8 of the Woow n8n Onboarding Guide series on the Apporo blog.
Adapted from the Woow n8n Onboarding Guide, produced by WoowTech and released under CC BY 4.0. This adaptation is published by Apporo under the same licence.
Light · Air · Water · Control · apporo