Files
N8N-Automations/email-to-ai-task/Email to AI Task (Vikunja).json
monoadmin 65a75ef45c Upload files to "email-to-ai-task"
I've created a comprehensive README for your Email to Vikunja workflow. It covers the entire workflow from email monitoring through task creation and notification, including all the key transformations and integrations involved. The README explains what each node does, how they connect, what credentials you'll need, and how to configure it for your specific setup.
2026-01-08 01:04:19 -08:00

208 lines
7.8 KiB
JSON

{
"name": "Email to AI Task (Vikunja)",
"nodes": [
{
"parameters": {
"values": {
"string": [
{
"name": "prompt",
"value": "=You are a task extraction assistant.\n\nReturn ONLY valid JSON with these fields:\n{\n \"title\": string,\n \"summary\": string,\n \"priority\": number (1-5),\n \"due_date\": string | null,\n \"labels\": string[]\n}\n\nEmail subject: {{$json.subject}}\nEmail body: {{$json.textPlain}}"
}
]
},
"options": {
"dotNotation": false
}
},
"name": "Build AI Prompt",
"type": "n8n-nodes-base.set",
"typeVersion": 1,
"position": [
1456,
368
],
"id": "1d09bb19-658b-4310-b4ae-a4633b90aa16"
},
{
"parameters": {
"method": "POST",
"url": "http://api.chat.pathcore.org/api/generate",
"sendBody": true,
"contentType": "raw",
"body": "={{ JSON.stringify({ model: \"mistral\", prompt: $json.prompt, stream: false }) }}\n",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
1664,
368
],
"id": "d067d32f-1d08-456a-a51a-c5bb2ab7e82d",
"name": "HTTP Request"
},
{
"parameters": {
"method": "PUT",
"url": "https://tasks.pathcore.org/api/v1/projects/1/tasks",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"title\": \"{{ $json.title }}\",\n \"description\": \"{{ $json.description }}\",\n \"project_id\": 1,\n \"priority\": {{ $json.priority }},\n \"due_date\": \"{{ $json.due_date }}\"\n}\n",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.3,
"position": [
2064,
368
],
"id": "0d3330f1-f828-48ad-b5ba-18daabc80c4e",
"name": "HTTP Request1",
"credentials": {
"httpHeaderAuth": {
"id": "ao2U85ZTTchihcSC",
"name": "Vikunja API"
}
}
},
{
"parameters": {
"downloadAttachments": true,
"options": {
"forceReconnect": 1,
"trackLastMessageId": true
}
},
"type": "n8n-nodes-base.emailReadImap",
"typeVersion": 2.1,
"position": [
1248,
368
],
"id": "a0c694fa-9757-416b-967d-0bdf995241e7",
"name": "Email Trigger (IMAP)",
"credentials": {
"imap": {
"id": "uen9pTUrJDRJFvlu",
"name": "IMAP account"
}
}
},
{
"parameters": {
"jsCode": "let text = $json.response || \"\";\n\n// Extract JSON block from Ollama response\nlet match = text.match(/\\{[\\s\\S]*\\}/);\nif (!match) {\n return [{\n title: \"Manual review required\",\n description: text,\n priority: 3,\n due_date: null,\n labels: [\"ai-error\"]\n }];\n}\n\nlet data = JSON.parse(match[0]);\n\n// Convert due_date to ISO 8601 with time (YYYY-MM-DDTHH:mm:ssZ)\nlet formattedDate = null;\nif (data.due_date === null || data.due_date === undefined || data.due_date === \"\") {\n // If no due_date, set to tomorrow\n let tomorrow = new Date();\n tomorrow.setDate(tomorrow.getDate() + 1);\n formattedDate = tomorrow.toISOString();\n} else if (data.due_date) {\n let dateStr = data.due_date.toLowerCase().trim();\n \n if (dateStr.includes(\"end of month\") || dateStr.includes(\"end of the month\")) {\n let today = new Date();\n let lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);\n formattedDate = lastDay.toISOString();\n } else if (dateStr.includes(\"end of week\")) {\n let today = new Date();\n let daysUntilFriday = (5 - today.getDay() + 7) % 7 || 7;\n let friday = new Date(today);\n friday.setDate(friday.getDate() + daysUntilFriday);\n formattedDate = friday.toISOString();\n } else if (dateStr.includes(\"today\")) {\n formattedDate = new Date().toISOString();\n } else if (dateStr.includes(\"tomorrow\")) {\n let tomorrow = new Date();\n tomorrow.setDate(tomorrow.getDate() + 1);\n formattedDate = tomorrow.toISOString();\n } else if (dateStr.includes(\"next week\")) {\n let nextWeek = new Date();\n nextWeek.setDate(nextWeek.getDate() + 7);\n formattedDate = nextWeek.toISOString();\n } else {\n // Try parsing as ISO date or other formats\n let parsed = new Date(data.due_date);\n if (!isNaN(parsed.getTime())) {\n formattedDate = parsed.toISOString();\n }\n }\n}\n\n// Ensure labels is always an array\nlet labels = data.labels || [];\nif (!Array.isArray(labels)) {\n labels = [labels];\n}\n\nreturn [{\n title: data.title || \"New Task\",\n description: data.summary || \"\",\n priority: data.priority || 3,\n due_date: formattedDate,\n labels: labels\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1856,
368
],
"id": "c85d2e04-8a51-4c49-a7e5-c8f7b36e366b",
"name": "Code in JavaScript"
},
{
"parameters": {
"authentication": "oAuth2",
"select": "channel",
"channelId": {
"__rl": true,
"value": "C0A7DBLUT5K",
"mode": "list",
"cachedResultName": "vijunka-tasks"
},
"text": "=🆕 New Vikunja Task Created ID: {{ $json.id }} Identifier: {{ $json.identifier }} Project ID: {{ $json.project_id }} Bucket ID: {{ $json.bucket_id }} Description: {{ $json.description }} Priority: {{ $json.priority }} Percent Done: {{ $json.percent_done }}% Done: {{ $json.done }} Done At: {{ $json.done_at }} Start Date: {{ $json.start_date }} Due Date: {{ $json.due_date }} End Date: {{ $json.end_date }} Repeat Mode: {{ $json.repeat_mode }} Favorite: {{ $json.is_favorite }} Assignees: {{ ($json.assignees || []).map(a => a.username).join(\", \") }} Labels: {{ ($json.labels || []).map(l => l.name).join(\", \") }} Created By: {{ $json.created_by?.username }} Created: {{ $json.created }} Updated: {{ $json.updated }}",
"otherOptions": {
"includeLinkToWorkflow": false
}
},
"type": "n8n-nodes-base.slack",
"typeVersion": 2.4,
"position": [
2272,
368
],
"id": "cb9715a4-40c4-4de3-8f7e-d46c602dd730",
"name": "Send a message",
"webhookId": "7f5f138d-a956-489a-812f-0a915925dfd1",
"credentials": {
"slackOAuth2Api": {
"id": "zntCoaowWYuBIKAY",
"name": "Slack account"
}
}
}
],
"pinData": {},
"connections": {
"Build AI Prompt": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request": {
"main": [
[
{
"node": "Code in JavaScript",
"type": "main",
"index": 0
}
]
]
},
"Email Trigger (IMAP)": {
"main": [
[
{
"node": "Build AI Prompt",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "HTTP Request1",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request1": {
"main": [
[
{
"node": "Send a message",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1"
},
"versionId": "67aafb11-9cbf-486a-b779-6f4dcebe7269",
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "3f831ca7bfd296051ccce9f0b1bd3c7aab7da4cca2818b7ffc69b89b3b2840d2"
},
"id": "wm6gwcPOLRiBwpdZ",
"tags": []
}