{
  "name": "Save starred Gmail emails as Markdown notes in Obsidian (via Google Drive)",
  "nodes": [
    {
      "id": "f5000s01-0000-4000-8000-000000000001",
      "name": "Sticky Note \u2014 read me first",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -800,
        -80
      ],
      "parameters": {
        "width": 700,
        "height": 940,
        "content": "## Save the emails that matter as notes in your Obsidian vault \u2014 automatically, once a day\n\n### How it works\nStar (or label) an email in Gmail and this workflow turns it into a clean Markdown note in your Obsidian vault. Once a day it finds every starred email you haven't saved yet and writes each one as a note \u2014 a YAML frontmatter block (title, from, date, tags) followed by the full body \u2014 into a Google Drive folder. Point that folder at your vault's Drive-synced location and the notes just appear in Obsidian. The moment a note is written, the email is labelled `obsidian-saved`, so it is never captured twice, even on manual re-runs.\n\nNo Obsidian plugin and no AI key needed \u2014 it writes plain `.md` files, so it runs 100% free on n8n Cloud.\n\n### Setup\n1. Connect **Gmail** and **Google Drive** (one-click Google sign-in on n8n Cloud).\n2. In Gmail, create a label called `obsidian-saved` \u2014 it is the \"already captured\" marker.\n3. In **\ud83d\udcc1 Save note to vault**, pick the Drive folder your Obsidian vault syncs from (e.g. an `Inbox` folder inside the vault).\n4. In **\ud83c\udff7\ufe0f Mark email saved**, select that same `obsidian-saved` label.\n5. (Optional) In **\u2699\ufe0f Your settings**, change which emails to capture (default: starred) or the tag added to each note.\n6. Activate. It runs once a day at 7am.\n\n### Honest notes\nThis reads the emails you star and writes files to your Drive \u2014 run it once with a single starred test email before trusting it with your whole inbox. Built with retries and an idempotent `obsidian-saved` label, so a crash mid-run can't create duplicate notes tomorrow. It captures the plain-text body of the email; attachments and rich HTML formatting are not carried into the note."
      },
      "typeVersion": 1
    },
    {
      "id": "f5000s02-0000-4000-8000-000000000002",
      "name": "Sticky Note \u2014 section 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -60,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 940,
        "content": "## 1. Find emails to save\nRuns daily at 7am. Pulls every email that matches your capture rule (default: starred) and isn't already labelled `obsidian-saved` \u2014 so each run only ever sees what's new."
      },
      "typeVersion": 1
    },
    {
      "id": "f5000s03-0000-4000-8000-000000000003",
      "name": "Sticky Note \u2014 section 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        520,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 460,
        "height": 940,
        "content": "## 2. Build the note\nTurns each email into a Markdown file: a YAML frontmatter block (title, from, date, tags) followed by the body. Filenames are date-prefixed and cleaned of the characters Obsidian and your OS dislike, so every note drops cleanly into the vault."
      },
      "typeVersion": 1
    },
    {
      "id": "f5000s04-0000-4000-8000-000000000004",
      "name": "Sticky Note \u2014 section 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1000,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 500,
        "height": 940,
        "content": "## 3. Save + mark done\nWrites the note into your vault's Google Drive folder, then immediately labels the email `obsidian-saved`. That label is the guard that makes re-runs safe: a captured email is skipped forever after, so you never get a duplicate note."
      },
      "typeVersion": 1
    },
    {
      "id": "f5000001-0000-4000-8000-00000000000a",
      "name": "Every day at 7am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        320
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "days",
              "triggerAtHour": 7
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f5000002-0000-4000-8000-00000000000b",
      "name": "\u2699\ufe0f Your settings",
      "type": "n8n-nodes-base.set",
      "position": [
        180,
        320
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "s1",
              "name": "searchQuery",
              "type": "string",
              "value": "is:starred -label:obsidian-saved"
            },
            {
              "id": "s2",
              "name": "noteTag",
              "type": "string",
              "value": "email"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f5000003-0000-4000-8000-00000000000c",
      "name": "Find starred emails",
      "type": "n8n-nodes-base.gmail",
      "maxTries": 3,
      "position": [
        360,
        320
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "q": "={{ $('\u2699\ufe0f Your settings').first().json.searchQuery }}"
        },
        "options": {},
        "operation": "getAll",
        "returnAll": true
      },
      "retryOnFail": true,
      "typeVersion": 2.1,
      "waitBetweenTries": 5000
    },
    {
      "id": "f5000004-0000-4000-8000-00000000000d",
      "name": "Build the note",
      "type": "n8n-nodes-base.code",
      "position": [
        540,
        320
      ],
      "parameters": {
        "jsCode": "// Turn each starred email into a Markdown note for your Obsidian vault.\n// Field names vary a little between Gmail node versions, so we read defensively.\nconst cfg = $('\u2699\ufe0f Your settings').first().json;\nconst pad = (n) => String(n).padStart(2, '0');\n\n// Strip the characters Obsidian and common filesystems reject in a filename.\nconst slug = (s) => String(s || 'note')\n  .replace(/[\\\\/:*?\"<>|#^\\[\\]]/g, ' ')\n  .replace(/\\s+/g, ' ')\n  .trim()\n  .slice(0, 80) || 'note';\n\nconst esc = (s) => String(s == null ? '' : s).replaceAll('\"', \"'\");\nconst notes = [];\n\nfor (const item of $input.all()) {\n  const m = item.json;\n  const subject = m.subject || m.Subject || '(no subject)';\n  const from = m.from || m.From || m.sender || '';\n  const rawDate = m.date || m.Date || m.internalDate || '';\n  const body = m.text || m.textPlain || m.textAsHtml || m.body || m.snippet || '';\n\n  // Build a safe date prefix; fall back to today if the header is unparseable.\n  let d = new Date(rawDate);\n  if (isNaN(d.getTime())) d = new Date();\n  const stamp = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;\n\n  const filename = `${stamp} ${slug(subject)}.md`;\n\n  const frontmatter = [\n    '---',\n    `title: \"${esc(subject)}\"`,\n    `from: \"${esc(from)}\"`,\n    `date: ${stamp}`,\n    'source: gmail',\n    `tags: [${cfg.noteTag || 'email'}]`,\n    '---',\n    '',\n  ].join('\\n');\n\n  const markdown = `${frontmatter}# ${subject}\\n\\n**From:** ${from}  \\n**Date:** ${stamp}\\n\\n${body}\\n`;\n\n  notes.push({\n    json: {\n      message_id: m.id,\n      filename,\n      markdown,\n    },\n  });\n}\n\nreturn notes;"
      },
      "typeVersion": 2
    },
    {
      "id": "f5000005-0000-4000-8000-00000000000e",
      "name": "One email at a time",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        720,
        320
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "f5000006-0000-4000-8000-00000000000f",
      "name": "Save note to vault",
      "type": "n8n-nodes-base.googleDrive",
      "maxTries": 3,
      "position": [
        1060,
        336
      ],
      "parameters": {
        "name": "={{ $json.filename }}",
        "content": "={{ $json.markdown }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "operation": "createFromText"
      },
      "retryOnFail": true,
      "typeVersion": 3,
      "waitBetweenTries": 5000
    },
    {
      "id": "f5000007-0000-4000-8000-000000000010",
      "name": "Mark email saved",
      "type": "n8n-nodes-base.gmail",
      "maxTries": 3,
      "position": [
        1260,
        336
      ],
      "parameters": {
        "labelIds": [],
        "messageId": "={{ $('One email at a time').item.json.message_id }}",
        "operation": "addLabels"
      },
      "retryOnFail": true,
      "typeVersion": 2.1,
      "waitBetweenTries": 5000
    }
  ],
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Build the note": {
      "main": [
        [
          {
            "node": "One email at a time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every day at 7am": {
      "main": [
        [
          {
            "node": "\u2699\ufe0f Your settings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark email saved": {
      "main": [
        [
          {
            "node": "One email at a time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save note to vault": {
      "main": [
        [
          {
            "node": "Mark email saved",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find starred emails": {
      "main": [
        [
          {
            "node": "Build the note",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "One email at a time": {
      "main": [
        [],
        [
          {
            "node": "Save note to vault",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u2699\ufe0f Your settings": {
      "main": [
        [
          {
            "node": "Find starred emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}