{
  "name": "01 - Create Email Folders with GPT-5.6 Luna",
  "active": false,
  "versionId": "7d526a30-e599-4310-a19c-d3dba701e4f9",
  "nodes": [
    {
      "parameters": {
        "url": "https://graph.microsoft.com/v1.0/me/mailFolders/Inbox/messages?$top=250&$select=id,subject,bodyPreview,from&$orderby=receivedDateTime desc",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "microsoftOutlookOAuth2Api",
        "options": {}
      },
      "id": "analyze-fetch",
      "name": "Fetch Emails (Page 1)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        240,
        -448
      ]
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all().map(i => i.json);\nlet allEmails = [];\nfor (const item of items) {\n  if (item.value && Array.isArray(item.value)) {\n    allEmails = allEmails.concat(item.value);\n  }\n}\nif (allEmails.length === 0) {\n  try {\n    const p1 = $('Fetch Emails (Page 1)').all().map(i => i.json.value || []).flat();\n    const p2 = $('Fetch Emails (Page 2)').all().map(i => i.json.value || []).flat();\n    allEmails = [...p1, ...p2];\n  } catch(e) {}\n}\n\n// Super compact format to keep prompt small\nconst lines = allEmails.map((e, i) => {\n  const from = e.from?.emailAddress?.address || '';\n  const subj = e.subject || '';\n  return `${from} | ${subj}`;\n}).join('\\n');\n\nconst prompt = `Analyze these ${allEmails.length} emails and suggest 5-12 folder names to categorize them. Only suggest folders with 5+ emails. Don't include: Inbox, Drafts, Sent, Deleted, Junk, Archive, security alerts (exists already).\n\nJSON only: {\"folders\":[\"Name\",...], \"reasoning\":{\"Name\":\"~N emails about X\",...}}\n\n${lines}`;\n\nreturn [{ json: { prompt, emailCount: allEmails.length } }];\n"
      },
      "id": "analyze-summarize",
      "name": "Build Analysis Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        736,
        -368
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.replicate.com/v1/models/openai/gpt-5.6-luna/predictions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Prefer",
              "value": "wait=60"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ $json.replicateRequest }}",
        "options": {
          "timeout": 120000
        },
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "id": "analyze-classify",
      "name": "AI Suggests Folders",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        992,
        -368
      ]
    },
    {
      "parameters": {
        "jsCode": "function parseStructured(value) {\n  if (value && typeof value === 'object' && !Array.isArray(value)) {\n    if (value.json_output && typeof value.json_output === 'object') return value.json_output;\n    if (value.output?.json_output && typeof value.output.json_output === 'object') return value.output.json_output;\n    if (typeof value.text !== 'string' && typeof value.output?.text !== 'string') return value;\n  }\n  const source = typeof value?.text === 'string'\n    ? value.text\n    : typeof value?.output?.text === 'string'\n      ? value.output.text\n      : value;\n  const text = Array.isArray(source)\n    ? source.map(part => typeof part === 'string' ? part : JSON.stringify(part)).join('')\n    : String(source ?? '');\n  try { return JSON.parse(text); } catch {}\n  const match = text.match(/\\{[\\s\\S]*\\}/);\n  if (!match) return {};\n  try { return JSON.parse(match[0]); } catch { return {}; }\n}\nconst response = $input.first().json;\nconst parsed = parseStructured(response.output ?? response);\nlet folders = Array.isArray(parsed.folders) ? parsed.folders : [];\nfolders = folders.map(folder => String(folder || '').trim()).filter(Boolean).map(folder => folder.startsWith('_') ? folder : '_' + folder);\nif (!folders.some(folder => folder.toLowerCase() === '_unknown')) folders.push('_Unknown');\nfolders = [...new Set(folders)];\nif (folders.length <= 1) throw new Error('Replicate did not return usable folder suggestions');\nreturn folders.map(displayName => ({ json: { displayName } }));"
      },
      "id": "analyze-create",
      "name": "Split Folders",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1248,
        -368
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://graph.microsoft.com/v1.0/me/mailFolders",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "microsoftOutlookOAuth2Api",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ displayName: $json.displayName }) }}",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 500
            }
          }
        }
      },
      "id": "analyze-create-http",
      "name": "Create Folder",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1488,
        -368
      ]
    },
    {
      "parameters": {
        "url": "https://graph.microsoft.com/v1.0/me/mailFolders/Inbox/messages?$top=250&$skip=250&$select=id,subject,bodyPreview,from&$orderby=receivedDateTime desc",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "microsoftOutlookOAuth2Api",
        "options": {}
      },
      "id": "analyze-fetch-2",
      "name": "Fetch Emails (Page 2)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        240,
        -272
      ]
    },
    {
      "parameters": {
        "mode": "combine",
        "combineBy": "combineAll",
        "options": {}
      },
      "id": "analyze-merge-pages",
      "name": "Merge Pages",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.1,
      "position": [
        496,
        -368
      ]
    },
    {
      "parameters": {},
      "id": "analyze-trigger",
      "name": "Create folder categories",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        -16,
        -368
      ]
    },
    {
      "parameters": {
        "content": "## 1. Folder categories\n\n**Manual setup stage.** Samples recent inbox pages, asks Replicate `openai/gpt-5.6-luna` with **no reasoning** to propose useful categories, then creates the suggested Outlook folders. Run intentionally when the folder taxonomy needs refreshing.\n\n### Setup after import\n\n1. Select your own Microsoft Outlook OAuth2 credential on every Outlook and Microsoft Graph node.\n2. Create or select a Generic Bearer Auth credential containing your Replicate API token on the GPT-5.6 Luna HTTP Request node.\n3. Review the Settings node and placeholders before activating or running this workflow.",
        "height": 544,
        "width": 1824,
        "color": 4
      },
      "id": "stage-note-folder-categories",
      "name": "Stage 1 — Folder categories",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -112,
        -640
      ]
    },
    {
      "id": "analyze-classify-request-builder",
      "name": "Build AI Suggests Folders Request",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        768,
        -368
      ],
      "parameters": {
        "jsCode": "return $input.all().map(item => {\n  const data = item.json;\n  const prompt = data.prompt;\n  return {\n    ...item,\n    json: {\n      ...data,\n      replicateRequest: {\n        input: {\n          prompt,\n          reasoning_effort: \"none\",\n          verbosity: 'low',\n          max_completion_tokens: 2000,\n        },\n      },\n    },\n  };\n});"
      }
    }
  ],
  "connections": {
    "Build Analysis Prompt": {
      "main": [
        [
          {
            "node": "Build AI Suggests Folders Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Suggests Folders": {
      "main": [
        [
          {
            "node": "Split Folders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Folders": {
      "main": [
        [
          {
            "node": "Create Folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Emails (Page 1)": {
      "main": [
        [
          {
            "node": "Merge Pages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Emails (Page 2)": {
      "main": [
        [
          {
            "node": "Merge Pages",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge Pages": {
      "main": [
        [
          {
            "node": "Build Analysis Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create folder categories": {
      "main": [
        [
          {
            "node": "Fetch Emails (Page 1)",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Emails (Page 2)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build AI Suggests Folders Request": {
      "main": [
        [
          {
            "node": "AI Suggests Folders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}
