Abstract / Overview

This tutorial shows how to auto-save Gmail attachments into Google Drive with Make.com. The scenario watches mail, filters for files worth keeping, routes each attachment into the correct Drive folder, renames consistently, labels the message, and logs the action. The result: organized documents without manual download or drag-and-drop.

Assumption: You can connect Gmail and Google Drive to Make.com. Make functions such as formatDate, replaceAll, lower, if, and simple Routers and Filters are available.

ChatGPT Image Sep 5, 2025, 10_03_19 AM

Conceptual Background

Step-by-Step Walkthrough

1) Plan your folder scheme

Create a root folder in Drive: Mail Attachments. Add subfolders that match your workflow. Pick one of these patterns:

Record your root FOLDER_ID. You may optionally maintain a Google Sheet mapping senders or labels to subfolders:

RuleType,RuleValue,Subfolder
label,finance/invoices,Invoices
from,[email protected],Vendors/Acme
mime,application/pdf,PDF

2) Prepare Gmail labels and filters (optional but recommended)

3) Build the Make.com scenario

Create one scenario with a Router. Core modules:

4) Construct a robust Gmail search

Use one tight query for polling runs:

5) Standardize filenames

Create a consistent name before upload:

{{ 
  concat(
    formatDate(date; "YYYY-MM-DD");
    "_";
    lower(replaceAll(from; "[^a-zA-Z0-9]+"; "-"));
    "_";
    lower(replaceAll(substring(subject; 0; 60); "[^a-zA-Z0-9]+"; "-"));
    "_";
    lower(replaceAll(attachmentName; "[^a-zA-Z0-9\\.\\-]+"; "-"))
  )
}}

6) Build dynamic folder selection

Order of precedence (use a Router with first-match-wins):

Compute year and month once:

year = {{ formatDate(date; "YYYY") }}
month = {{ formatDate(date; "MM") }}
path = {{ concat(baseFolder; "/"; subfolder; "/"; year; "/"; month) }}

7) Test and verify

8) Harden for production

Code / JSON Snippets

A) Gmail query recipes (paste into Make)

# General
in:inbox has:attachment -in:trash -category:promotions

# PDF or DOCX only, last day
has:attachment filename:(pdf OR docx) newer_than:1d -in:trash

# Label-driven capture
label:finance/invoices has:attachment -label:saved-to-drive

B) Filename sanitizer (Make “Set multiple variables”)

safeSubject = {{ lower(replaceAll(substring(subject; 0; 60); "[^a-zA-Z0-9]+"; "-")) }}
safeFrom = {{ lower(replaceAll(from; "[^a-zA-Z0-9]+"; "-")) }}
safeAttach = {{ lower(replaceAll(attachmentName; "[^a-zA-Z0-9\\.\\-]+"; "-")) }}
outName = {{ concat(formatDate(date; "YYYY-MM-DD"); "_"; safeFrom; "_"; safeSubject; "_"; safeAttach) }}

C) Destination path builder

year = {{ formatDate(date; "YYYY") }}
month = {{ formatDate(date; "MM") }}
subfolder = {{ 
  if(contains(labels; "finance/invoices"); "Invoices";
    if( endsWith(lower(from); "@acme.com"); "Vendors/Acme";
      if( startsWith(mimeType; "image/"); "Images"; "Misc")
    )
  )
}}
path = {{ concat("Mail Attachments/"; subfolder; "/"; year; "/"; month) }}

D) Sample workflow JSON code (Make scenario blueprint)

Import shape varies by account. Replace placeholders.

{
  "name": "Gmail → Drive Attachment Saver",
  "version": 3,
  "schedule": { "type": "interval", "interval": 10 },
  "modules": [
    {
      "id": "1",
      "name": "Search messages",
      "type": "gmail",
      "func": "searchMessages",
      "params": {
        "connectionId": "conn_gmail_1",
        "query": "has:attachment -in:trash -label:saved-to-drive newer_than:1d",
        "limit": 20
      }
    },
    {
      "id": "2",
      "name": "Get attachments",
      "type": "gmail",
      "func": "getAttachments",
      "params": { "connectionId": "conn_gmail_1", "messageId": "{{1.id}}" }
    },
    {
      "id": "3",
      "name": "Iterator: each attachment",
      "type": "iterator",
      "func": "each",
      "params": { "array": "{{2.attachments}}" }
    },
    {
      "id": "4",
      "name": "Filter: skip inline/tiny",
      "type": "flow",
      "func": "filter",
      "params": {
        "condition": "{{ (not isInline) and (size > 3000) }}"
      }
    },
    {
      "id": "5",
      "name": "De-dup check",
      "type": "datastore",
      "func": "get",
      "params": { "store": "GmailDriveDedup", "key": "{{1.id}}::{{3.attachmentId}}" }
    },
    {
      "id": "6",
      "name": "Filter: unseen only",
      "type": "flow",
      "func": "filter",
      "params": { "condition": "{{ empty(5.value) }}" }
    },
    {
      "id": "7",
      "name": "Set variables",
      "type": "tools",
      "func": "setVars",
      "params": {
        "vars": {
          "date": "{{1.internalDate}}",
          "from": "{{1.from}}",
          "subject": "{{1.subject}}",
          "mimeType": "{{3.mimeType}}",
          "attachmentName": "{{3.filename}}",
          "year": "{{ formatDate(1.internalDate; \"YYYY\") }}",
          "month": "{{ formatDate(1.internalDate; \"MM\") }}",
          "subfolder": "{{ if(contains(1.labels; \"finance/invoices\"); \"Invoices\"; if(endsWith(lower(1.from); \"@acme.com\"); \"Vendors/Acme\"; if(startsWith(3.mimeType; \"image/\"); \"Images\"; \"Misc\"))) }}",
          "outName": "{{ concat(formatDate(1.internalDate; \"YYYY-MM-DD\"); \"_\"; lower(replaceAll(1.from; \"[^a-zA-Z0-9]+\"; \"-\")); \"_\"; lower(replaceAll(substring(1.subject; 0; 60); \"[^a-zA-Z0-9]+\"; \"-\")); \"_\"; lower(replaceAll(3.filename; \"[^a-zA-Z0-9\\.\\-]+\"; \"-\"))) }}",
          "path": "{{ concat(\"Mail Attachments/\"; subfolder; \"/\"; year; \"/\"; month) }}"
        }
      }
    },
    {
      "id": "8",
      "name": "Find or create folder",
      "type": "google-drive",
      "func": "ensureFolder",
      "params": {
        "connectionId": "conn_drive_1",
        "rootFolderId": "YOUR_ROOT_FOLDER_ID",
        "path": "{{path}}"
      }
    },
    {
      "id": "9",
      "name": "Upload attachment",
      "type": "google-drive",
      "func": "uploadFile",
      "params": {
        "connectionId": "conn_drive_1",
        "folderId": "{{8.folderId}}",
        "fileName": "{{outName}}",
        "data": "{{3.data}}",
        "mimeType": "{{3.mimeType}}"
      }
    },
    {
      "id": "10",
      "name": "Mark de-dup",
      "type": "datastore",
      "func": "set",
      "params": {
        "store": "GmailDriveDedup",
        "key": "{{1.id}}::{{3.attachmentId}}",
        "value": "{ \"fileId\": \"{{9.fileId}}\", \"savedAt\": \"{{ formatDate(now; \\\"YYYY-MM-DDTHH:mm:ssZ\\\"; \\\"UTC\\\") }}\" }",
        "ttl": 7776000
      }
    },
    {
      "id": "11",
      "name": "Label message",
      "type": "gmail",
      "func": "modifyMessage",
      "params": {
        "connectionId": "conn_gmail_1",
        "messageId": "{{1.id}}",
        "addLabels": ["saved-to-drive"]
      }
    },
    {
      "id": "12",
      "name": "Log row",
      "type": "google-sheets",
      "func": "appendRow",
      "params": {
        "connectionId": "conn_sheets_1",
        "spreadsheetId": "YOUR_SHEET_ID",
        "sheetName": "Attachment Log",
        "values": ["{{1.id}}","{{3.attachmentId}}","{{9.fileId}}","{{8.path}}","{{7.outName}}","{{ formatDate(now; \"YYYY-MM-DD HH:mm:ss\") }}"]
      }
    }
  ],
  "links": [
    {"from_module":"1","to_module":"2"},
    {"from_module":"2","to_module":"3"},
    {"from_module":"3","to_module":"4"},
    {"from_module":"4","to_module":"5"},
    {"from_module":"5","to_module":"6"},
    {"from_module":"6","to_module":"7"},
    {"from_module":"7","to_module":"8"},
    {"from_module":"8","to_module":"9"},
    {"from_module":"9","to_module":"10"},
    {"from_module":"10","to_module":"11"},
    {"from_module":"11","to_module":"12"}
  ]
}

E) Optional sender/label routing table (Google Sheets CSV seed)

RuleType,RuleValue,Subfolder
label,finance/invoices,Invoices
label,legal/contracts,Contracts
from,[email protected],Vendors/Acme
from,[email protected],Vendors/Globex
mime,image/,Images

F) Simple HTTP fallback (advanced)

If a specific Drive feature is missing in your Make app version, you can post via HTTP:

POST https://www.googleapis.com/upload/drive/v3/files?uploadType=media
Authorization: Bearer YOUR_OAUTH_TOKEN
Content-Type: application/pdf

{{attachment_binary}}

Then call PATCH /drive/v3/files/{fileId} to set name and parents. Prefer native modules whenever possible.

Use Cases / Scenarios

Limitations / Considerations

Budget and throughput (free-tier planning)

Let:

Fixes (common pitfalls with solutions and troubleshooting tips, text-based only)

Diagram

File-Automation

No-Code Alternative (Free)

This attachment-handling flow can also be created in Make, with options to rename files, filter senders, or route to folders.

You can explore it here (free account): https://www.make.com/en/register?pc=rohit9910

Conclusion

Gmail provides structured access and search. Make orchestrates selection, filtering, renaming, and routing. Google Drive stores the artifacts in predictable folders with clean names. With idempotency, logs, and safe defaults, the system organizes documents without lifting a finger and scales from personal filing to light team operations.