{
  "name": "Safock template: AI email triage with Claude",
  "nodes": [
    {
      "parameters": {
        "content": "## AI email triage\nBy Safock (safock.com). Free to use and adapt.\n\n1. Connect Gmail in **New email** (it checks the inbox every minute).\n2. Create a Header Auth credential with `x-api-key: <your Anthropic key>` and select it in **Classify with Claude**. Any chat model API works if you change the URL and body.\n3. Connect Slack and set the channel in **Alert sales channel**.\n\nEach new email is classified as sales, support, billing or other, with a one-line summary. Sales emails and anything marked urgent post to Slack. Only the sender, subject and a short preview are sent to the model.",
        "height": 360,
        "width": 460
      },
      "id": "fdfeac17-369e-42dc-992f-7edd8a94ccb1",
      "name": "Setup notes",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -500,
        -140
      ]
    },
    {
      "parameters": {
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "simple": true,
        "filters": {
          "labelIds": [
            "INBOX"
          ]
        },
        "options": {}
      },
      "id": "4bb494ed-f222-4eaf-ab1e-1cc3a0a75c20",
      "name": "New email",
      "type": "n8n-nodes-base.gmailTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "anthropic-version",
              "value": "2023-06-01"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ model: 'claude-haiku-5-5', max_tokens: 300, messages: [{ role: 'user', content: 'Classify this business email. Reply with JSON only: {\"category\": \"sales\" | \"support\" | \"billing\" | \"other\", \"urgent\": true | false, \"summary\": \"one sentence\"}.\\n\\nFrom: ' + ($json.From || '') + '\\nSubject: ' + ($json.Subject || '') + '\\nPreview: ' + ($json.snippet || '') }] }) }}",
        "options": {}
      },
      "id": "2f2d688f-dff0-4b24-9c95-fb016a8eeb3c",
      "name": "Classify with Claude",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        220,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Read the model's JSON answer; fall back safely if it is malformed.\nconst text = $json.content?.[0]?.text ?? '';\nlet r = {};\ntry { r = JSON.parse((text.match(/\\{[\\s\\S]*\\}/) || ['{}'])[0]); } catch (e) { r = {}; }\nconst allowed = ['sales', 'support', 'billing', 'other'];\nconst email = $('New email').item.json;\nreturn {\n  json: {\n    category: allowed.includes(r.category) ? r.category : 'other',\n    urgent: r.urgent === true,\n    summary: String(r.summary || '').slice(0, 280),\n    from: email.From || email.from || '',\n    subject: email.Subject || email.subject || '',\n  },\n};"
      },
      "id": "da965e1b-d3ae-4243-8e94-4835040efaea",
      "name": "Read the answer",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "id": "8c48e4d8-def7-4630-89f3-76b7c0c10c9a",
              "leftValue": "={{ $json.category === 'sales' || $json.urgent }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "8f293840-5b25-4b60-bf22-7900915d2eb1",
      "name": "Sales or urgent?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        660,
        0
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "sales",
          "mode": "name"
        },
        "text": "={{ $json.urgent ? 'URGENT ' : '' }}{{ $json.category.toUpperCase() }} email from {{ $json.from }}\n*{{ $json.subject }}*\n{{ $json.summary }}",
        "otherOptions": {}
      },
      "id": "ee1f67c0-c900-4cd2-8d06-d802c977d462",
      "name": "Alert sales channel",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        880,
        -100
      ],
      "webhookId": "44ada99b-f2f8-4ddc-b4f4-7a45cc8e7a4c"
    }
  ],
  "connections": {
    "New email": {
      "main": [
        [
          {
            "node": "Classify with Claude",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Classify with Claude": {
      "main": [
        [
          {
            "node": "Read the answer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read the answer": {
      "main": [
        [
          {
            "node": "Sales or urgent?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sales or urgent?": {
      "main": [
        [
          {
            "node": "Alert sales channel",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {},
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}
