From 299ffaeb953e3f8aa674b142927a4ae361e5be67 Mon Sep 17 00:00:00 2001 From: admin-valentin Date: Wed, 26 Aug 2026 15:49:19 +0000 Subject: [PATCH] feat(n8n): gmail-bridge.json workflow for CEO OS automation --- n8n-workflows/gmail-bridge.json | 265 ++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 n8n-workflows/gmail-bridge.json diff --git a/n8n-workflows/gmail-bridge.json b/n8n-workflows/gmail-bridge.json new file mode 100644 index 0000000..f7a75f8 --- /dev/null +++ b/n8n-workflows/gmail-bridge.json @@ -0,0 +1,265 @@ +{ + "name": "CEO OS — Gmail Bridge", + "nodes": [ + { + "id": "n3-trigger", + "name": "New Important Email", + "type": "n8n-nodes-base.gmailTrigger", + "typeVersion": 1, + "position": [ + 0, + 300 + ], + "parameters": { + "filters": { + "labelIds": [ + "INBOX", + "IMPORTANT" + ] + }, + "pollTimes": { + "item": [ + { + "mode": "everyMinutes", + "value": 15 + } + ] + } + } + }, + { + "id": "n3-filter", + "name": "Skip Auto-Generated", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 220, + 300 + ], + "parameters": { + "jsCode": "const email = $input.first().json;\nconst skipPatterns = ['noreply', 'no-reply', 'donotreply', 'unsubscribe', 'newsletter', 'automated'];\nconst from = (email.from || '').toLowerCase();\nconst subject = (email.subject || '').toLowerCase();\n\nconst isAuto = skipPatterns.some(p => from.includes(p) || subject.includes(p));\nif (isAuto) return []; // Drop auto-generated emails\n\nreturn [{ json: {\n emailId: email.id,\n from: email.from,\n subject: email.subject,\n snippet: email.snippet || email.body?.slice(0, 500),\n date: email.date,\n api: $env['CEO_OS_API_URL'] ?? 'https://boardmind.dev/api',\n tenantId: $env['CEO_OS_TENANT_ID'],\n serviceKey: $env['CEO_OS_SERVICE_KEY'],\n}}];" + } + }, + { + "id": "n3-classify", + "name": "Classify Email with AI", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4, + "position": [ + 440, + 300 + ], + "parameters": { + "url": "={{$json.api}}/v1/ai/ask", + "method": "POST", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + { + "name": "X-Service-Key", + "value": "={{$json.serviceKey}}" + }, + { + "name": "Content-Type", + "value": "application/json" + } + ] + }, + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={\"messages\": [{\"role\": \"user\", \"content\": \"Clasifică emailul următor. Răspunde DOAR cu JSON: {\\\"action\\\": \\\"action_required|info_only|skip\\\", \\\"priority\\\": \\\"high|medium|low\\\", \\\"taskTitle\\\": \\\"titlu task dacă e action_required, altfel null\\\", \\\"summary\\\": \\\"1 propoziție rezumat\\\"}\\n\\nDe la: {{$json.from}}\\nSubiect: {{$json.subject}}\\nConținut: {{$json.snippet}}\"}], \"context\": \"{\\\"emailClassification\\\": true}\"}" + } + }, + { + "id": "n3-parse", + "name": "Parse Classification", + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 660, + 300 + ], + "parameters": { + "jsCode": "const reply = $input.first().json.reply || '';\nlet classification = { action: 'info_only', priority: 'low', taskTitle: null, summary: reply };\ntry {\n const jsonMatch = reply.match(/\\{[^}]+\\}/s);\n if (jsonMatch) classification = JSON.parse(jsonMatch[0]);\n} catch {}\n\nconst prev = $('Skip Auto-Generated').first().json;\nreturn [{ json: { ...prev, ...classification }}];" + } + }, + { + "id": "n3-check-action", + "name": "Action Required?", + "type": "n8n-nodes-base.if", + "typeVersion": 2, + "position": [ + 880, + 300 + ], + "parameters": { + "conditions": { + "options": { + "caseSensitive": false, + "leftValue": "", + "typeValidation": "strict" + }, + "conditions": [ + { + "id": "c1", + "leftValue": "={{$json.action}}", + "rightValue": "action_required", + "operator": { + "type": "string", + "operation": "equals" + } + } + ], + "combinator": "and" + } + } + }, + { + "id": "n3-create-task", + "name": "Create Task", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4, + "position": [ + 1100, + 200 + ], + "parameters": { + "url": "={{$json.api}}/v1/tasks", + "method": "POST", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + { + "name": "X-Service-Key", + "value": "={{$json.serviceKey}}" + }, + { + "name": "Content-Type", + "value": "application/json" + } + ] + }, + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={\"tenantId\": \"{{$json.tenantId}}\", \"title\": \"{{$json.taskTitle || $json.subject}}\", \"description\": \"📧 Email de la {{$json.from}}\\n\\n{{$json.summary}}\", \"tags\": [\"email\", \"{{$json.priority}}\"], \"priority\": \"{{$json.priority}}\"}" + } + }, + { + "id": "n3-log-obs", + "name": "Log Email Observation", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4, + "position": [ + 1100, + 400 + ], + "parameters": { + "url": "={{$json.api}}/v1/observations", + "method": "POST", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + { + "name": "X-Service-Key", + "value": "={{$json.serviceKey}}" + }, + { + "name": "Content-Type", + "value": "application/json" + } + ] + }, + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={\"tenantId\": \"{{$json.tenantId}}\", \"metric\": \"email-received\", \"value\": \"{{$json.subject}}\", \"unit\": \"{{$json.action}}\", \"subjectType\": \"communication\", \"source\": \"{{$json.from}}\", \"confidence\": 0.9}" + } + } + ], + "connections": { + "New Important Email": { + "main": [ + [ + { + "node": "Skip Auto-Generated", + "type": "main", + "index": 0 + } + ] + ] + }, + "Skip Auto-Generated": { + "main": [ + [ + { + "node": "Classify Email with AI", + "type": "main", + "index": 0 + } + ] + ] + }, + "Classify Email with AI": { + "main": [ + [ + { + "node": "Parse Classification", + "type": "main", + "index": 0 + } + ] + ] + }, + "Parse Classification": { + "main": [ + [ + { + "node": "Action Required?", + "type": "main", + "index": 0 + } + ] + ] + }, + "Action Required?": { + "main": [ + [ + { + "node": "Create Task", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "Log Email Observation", + "type": "main", + "index": 0 + } + ] + ] + }, + "Create Task": { + "main": [ + [ + { + "node": "Log Email Observation", + "type": "main", + "index": 0 + } + ] + ] + } + }, + "active": false, + "settings": { + "executionOrder": "v1" + }, + "tags": [ + { + "name": "ceo-os" + }, + { + "name": "gmail" + } + ] +} \ No newline at end of file