initial commit

This commit is contained in:
Florian Krebs
2026-05-04 20:49:45 +00:00
parent 7d205a68e4
commit 18d2360ad9
14 changed files with 1811 additions and 3 deletions
@@ -0,0 +1,193 @@
{
"name": "Phase 2.1: Email Butler - Nextcloud Mail Digest & Summarization",
"description": "Reads private emails from Nextcloud Mail, summarizes daily digest, posts to Memos",
"nodes": [
{
"parameters": {
"triggerType": "on",
"cronExpression": "0 7 * * *"
},
"name": "Daily Trigger (7 AM)",
"type": "n8n-nodes-base.cronTrigger",
"typeVersion": 1,
"position": [50, 50]
},
{
"parameters": {
"method": "GET",
"url": "={{ $env.NC_HOST }}/remote.php/dav/calendars/{{ $env.NC_USERNAME }}/personal/",
"authentication": "basicAuth",
"basicAuth": {
"user": "={{ $env.NC_USERNAME }}",
"password": "={{ $env.NC_APP_PASSWORD }}"
},
"responseFormat": "json"
},
"name": "Discover Nextcloud Mail Account",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [250, 50],
"onError": "continueErrorOutput"
},
{
"parameters": {
"method": "GET",
"url": "={{ $env.NC_HOST }}/ocs/v2.php/apps/mail/api/v1/accounts",
"authentication": "basicAuth",
"basicAuth": {
"user": "={{ $env.NC_USERNAME }}",
"password": "={{ $env.NC_APP_PASSWORD }}"
},
"responseFormat": "json",
"headers": {
"OCS-APIREQUEST": "true"
}
},
"name": "Fetch Mail Accounts from Nextcloud",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [450, 50],
"onError": "continueErrorOutput"
},
{
"parameters": {
"jsCode": "// Extract mail account IDs\nconst accounts = $input.item.json.ocs?.data || [];\nif (!Array.isArray(accounts) || accounts.length === 0) {\n throw new Error('No mail accounts found in Nextcloud');\n}\n\n// Find personal account (first private account)\nconst personalAccount = accounts.find(a => a.name?.toLowerCase().includes('privat') || a.name?.toLowerCase().includes('personal')) || accounts[0];\n\nreturn {\n account_id: personalAccount.id,\n account_name: personalAccount.name,\n email: personalAccount.email,\n total_accounts: accounts.length\n};"
},
"name": "Extract Personal Mail Account",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [650, 50]
},
{
"parameters": {
"method": "GET",
"url": "={{ $env.NC_HOST }}/ocs/v2.php/apps/mail/api/v1/accounts/{{ $node['Extract Personal Mail Account'].json.account_id }}/mailboxes",
"authentication": "basicAuth",
"basicAuth": {
"user": "={{ $env.NC_USERNAME }}",
"password": "={{ $env.NC_APP_PASSWORD }}"
},
"responseFormat": "json",
"headers": {
"OCS-APIREQUEST": "true"
}
},
"name": "Fetch Mailboxes",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [850, 50],
"onError": "continueErrorOutput"
},
{
"parameters": {
"jsCode": "// Get INBOX mailbox ID\nconst mailboxes = $input.item.json.ocs?.data || [];\nconst inbox = mailboxes.find(m => m.name === 'INBOX');\nif (!inbox) {\n throw new Error('INBOX not found');\n}\nreturn { mailbox_id: inbox.id };"
},
"name": "Get INBOX ID",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [1050, 50]
},
{
"parameters": {
"method": "GET",
"url": "={{ $env.NC_HOST }}/ocs/v2.php/apps/mail/api/v1/accounts/{{ $node['Extract Personal Mail Account'].json.account_id }}/mailboxes/{{ $node['Get INBOX ID'].json.mailbox_id }}/messages",
"authentication": "basicAuth",
"basicAuth": {
"user": "={{ $env.NC_USERNAME }}",
"password": "={{ $env.NC_APP_PASSWORD }}"
},
"responseFormat": "json",
"headers": {
"OCS-APIREQUEST": "true"
},
"qs": "from={{ $now.subtract(1, 'day').format('YYYY-MM-DD') }}&limit=20"
},
"name": "Fetch Today's Messages",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [1250, 50],
"onError": "continueErrorOutput"
},
{
"parameters": {
"jsCode": "// Prepare email list for summarization\nconst messages = $input.item.json.ocs?.data || [];\nconst emails = messages.map(msg => ({\n from: msg.from?.join(', ') || 'Unknown',\n subject: msg.subject || '(No Subject)',\n preview: msg.preview?.substring(0, 200) || msg.plainTextBody?.substring(0, 200) || '(No preview)',\n date: msg.dateInt ? new Date(msg.dateInt * 1000).toLocaleDateString('de-DE') : 'Unknown'\n}));\n\nconst emailList = emails.map((e, i) => `${i+1}. **${e.subject}** (von ${e.from})\\n ${e.preview}`).join('\\n\\n');\n\nreturn {\n total_emails: emails.length,\n email_list: emailList,\n emails_json: emails\n};"
},
"name": "Prepare Email Summary",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [1450, 50]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.SAIA_HOST }}/v1/chat/completions",
"authentication": "headerAuth",
"headerAuth": {
"Authorization": "Bearer {{ $env.SAIA_API_KEY }}"
},
"sendBody": true,
"bodyParametersUi": "json",
"body": "{\n \"model\": \"gpt-3.5-turbo\",\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"Write a concise 3-5 line daily email digest summarizing key points and action items.\"\n },\n {\n \"role\": \"user\",\n \"content\": \"Summarize these {{ $node['Prepare Email Summary'].json.total_emails }} emails:\\n\\n{{ $node['Prepare Email Summary'].json.email_list }}\"\n }\n ],\n \"temperature\": 0.7,\n \"max_tokens\": 300\n}"
},
"name": "SAIA: Summarize Emails",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [1650, 50]
},
{
"parameters": {
"jsCode": "const summary = $input.item.json.choices?.[0]?.message?.content || 'No emails today';\nconst timestamp = new Date().toLocaleTimeString('de-DE', {timeZone: 'Europe/Berlin'});\nreturn {\n summary,\n timestamp,\n email_count: $node['Prepare Email Summary'].json.total_emails\n};"
},
"name": "Extract Summary",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [1850, 50]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.MEMOS_HOST }}/api/v1/memos",
"authentication": "headerAuth",
"headerAuth": {
"Authorization": "Bearer {{ $env.MEMOS_API_KEY }}"
},
"sendBody": true,
"bodyParametersUi": "json",
"body": "{\n \"content\": \"📧 **Email Digest** ({{ $node['Extract Summary'].json.email_count }} Mails)\\n\\n{{ $node['Extract Summary'].json.summary }}\\n\\n_Generated at {{ $node['Extract Summary'].json.timestamp }}_\",\n \"visibility\": \"PRIVATE\"\n}"
},
"name": "Post Digest to Memos",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 3,
"position": [2050, 50]
}
],
"connections": {
"Daily Trigger (7 AM)": {
"main": [[{ "node": "Fetch Mail Accounts from Nextcloud", "type": "main", "index": 0 }]]
},
"Fetch Mail Accounts from Nextcloud": {
"main": [[{ "node": "Extract Personal Mail Account", "type": "main", "index": 0 }]]
},
"Extract Personal Mail Account": {
"main": [[{ "node": "Fetch Mailboxes", "type": "main", "index": 0 }]]
},
"Fetch Mailboxes": {
"main": [[{ "node": "Get INBOX ID", "type": "main", "index": 0 }]]
},
"Get INBOX ID": {
"main": [[{ "node": "Fetch Today's Messages", "type": "main", "index": 0 }]]
},
"Fetch Today's Messages": {
"main": [[{ "node": "Prepare Email Summary", "type": "main", "index": 0 }]]
},
"Prepare Email Summary": {
"main": [[{ "node": "SAIA: Summarize Emails", "type": "main", "index": 0 }]]
},
"SAIA: Summarize Emails": {
"main": [[{ "node": "Extract Summary", "type": "main", "index": 0 }]]
},
"Extract Summary": {
"main": [[{ "node": "Post Digest to Memos", "type": "main", "index": 0 }]]
}
}
}