{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "a98f6394-ea87-4ca2-94e9-de0113cf812d",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -752,
        816
      ],
      "parameters": {
        "color": 4,
        "width": 524,
        "height": 1092,
        "content": "## Daily Morning Intelligence Brief \u2014 Gmail + Calendar + GPT-4o-mini + Telegram\n\nFor founders, executives, and busy professionals who want their full day context delivered to Telegram before they open a single app. Every weekday at 8AM this workflow automatically fetches unread emails from the last 24 hours and today and tomorrow's calendar events in parallel, merges the data, sends it to GPT-4o-mini which filters out promotions and noise, and delivers one clean structured brief to Telegram. You wake up with urgent emails, your schedule, tomorrow's preparation, and one recommended focus \u2014 all in one message.\n\n## How it works\n- **1. Schedule \u2014 Every Weekday 8AM** triggers the workflow automatically Monday to Friday\n- **2. Set \u2014 Config Values** stores your Telegram chat ID, Gmail address, name, and timezone\n- **3. Gmail \u2014 Fetch Unread Emails** fetches all unread inbox emails from the last 24 hours in parallel\n- **4. Google Calendar \u2014 Fetch Today and Tomorrow** fetches primary calendar events for today and tomorrow in parallel\n- **5. Code \u2014 Merge Emails and Calendar** reads both parallel branches, formats emails with sender and preview, separates events into today and tomorrow, and builds clean text for GPT\n- **6. AI Agent \u2014 Write Morning Brief** uses GPT-4o-mini to write a 4-section brief: urgent emails only (promotions filtered), today's schedule, tomorrow preparation with tips, and one focus recommendation\n- **8. Code \u2014 Prepare Telegram Message** adds a timezone-aware timestamp footer and a fallback message if GPT fails\n- **9. Telegram \u2014 Send Morning Brief** delivers the formatted brief with Markdown to your Telegram chat\n\n## Set up steps\n1. In **2. Set \u2014 Config Values** \u2014 replace PASTE_YOUR_TELEGRAM_CHAT_ID_HERE, PASTE_YOUR_GMAIL_ADDRESS_HERE, PASTE_YOUR_NAME_OR_COMPANY_HERE, and set your timezone (examples: Asia/Kolkata, America/New_York, Europe/London)\n2. In **3. Gmail \u2014 Fetch Unread Emails** \u2014 connect your Gmail OAuth2 credential\n3. In **4. Google Calendar \u2014 Fetch Today and Tomorrow** \u2014 connect your Google Calendar OAuth2 credential\n4. In **7. OpenAI \u2014 GPT-4o-mini Model** \u2014 connect your OpenAI credential\n5. In **9. Telegram \u2014 Send Morning Brief** \u2014 connect your Telegram Bot API credential\n6. Before first run \u2014 open Telegram, find your bot, and send /start to activate it\n7. Get your Telegram Chat ID by messaging @userinfobot on Telegram"
      },
      "typeVersion": 1
    },
    {
      "id": "7d20de47-a135-4f54-8f11-21cf9993ebc1",
      "name": "Section \u2014 Schedule and Config",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -160,
        1120
      ],
      "parameters": {
        "color": 5,
        "width": 468,
        "height": 356,
        "content": "## Schedule and Config\nWorkflow triggers automatically every weekday at 8AM. Config stores your Telegram chat ID, Gmail address, name, timezone, and all date variables used across the workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "b87e4d35-22b1-4f38-97d2-11a1777d4274",
      "name": "Section \u2014 Parallel Data Fetch",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        416,
        880
      ],
      "parameters": {
        "color": 6,
        "width": 324,
        "height": 852,
        "content": "## Parallel Data Fetch\nGmail and Google Calendar are fetched simultaneously to save time. Gmail gets unread inbox emails from the last 24 hours. Calendar gets all events for today and tomorrow from the primary calendar."
      },
      "typeVersion": 1
    },
    {
      "id": "50a2a0dd-6e77-43f4-87fb-6f7d75c30ed8",
      "name": "Section \u2014 Data Merge and AI Brief Writing",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        864,
        1088
      ],
      "parameters": {
        "color": 6,
        "width": 596,
        "height": 580,
        "content": "## Data Merge and AI Brief Writing\nThe Code node reads both parallel branches using .all() and formats emails and events into clean text. GPT-4o-mini writes a structured 4-section brief: urgent emails, today's schedule, tomorrow preparation, and one focus recommendation. Promotions and notifications are filtered out."
      },
      "typeVersion": 1
    },
    {
      "id": "334046db-d5e2-4152-b74b-4bfd46c1688c",
      "name": "Section \u2014 Telegram Delivery",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1536,
        1104
      ],
      "parameters": {
        "color": 4,
        "width": 580,
        "height": 404,
        "content": "## Telegram Delivery\nAdds a timezone-aware timestamp footer and a fallback message if GPT fails. Sends the complete formatted brief to your Telegram chat with Markdown rendering."
      },
      "typeVersion": 1
    },
    {
      "id": "465fbadf-3c07-4703-9d93-0b81406473a7",
      "name": "1. Schedule \u2014 Every Weekday 8AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -96,
        1264
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * 1-5"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "3671ecad-99b5-43cc-8d88-cebbd6b44175",
      "name": "2. Set \u2014 Config Values",
      "type": "n8n-nodes-base.set",
      "position": [
        144,
        1264
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-001",
              "name": "telegramChatId",
              "type": "string",
              "value": "PASTE_YOUR_TELEGRAM_CHAT_ID_HERE"
            },
            {
              "id": "cfg-002",
              "name": "gmailUserId",
              "type": "string",
              "value": "PASTE_YOUR_GMAIL_ADDRESS_HERE"
            },
            {
              "id": "cfg-003",
              "name": "companyName",
              "type": "string",
              "value": "PASTE_YOUR_NAME_OR_COMPANY_HERE"
            },
            {
              "id": "cfg-004",
              "name": "timezone",
              "type": "string",
              "value": "Asia/Kolkata"
            },
            {
              "id": "cfg-005",
              "name": "todayFormatted",
              "type": "string",
              "value": "={{ $now.toFormat('cccc, dd MMMM yyyy') }}"
            },
            {
              "id": "cfg-006",
              "name": "todayISO",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            },
            {
              "id": "cfg-007",
              "name": "tomorrowISO",
              "type": "string",
              "value": "={{ $now.plus({days: 1}).toISO() }}"
            },
            {
              "id": "cfg-008",
              "name": "dayAfterTomorrowISO",
              "type": "string",
              "value": "={{ $now.plus({days: 2}).startOf('day').toISO() }}"
            },
            {
              "id": "cfg-009",
              "name": "yesterdayISO",
              "type": "string",
              "value": "={{ $now.minus({days: 1}).toISO() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "cdc47741-beda-4e78-8cc8-7820429336a6",
      "name": "3. Gmail \u2014 Fetch Unread Emails",
      "type": "n8n-nodes-base.gmail",
      "position": [
        512,
        1088
      ],
      "parameters": {
        "filters": {
          "labelIds": [
            "INBOX",
            "UNREAD"
          ],
          "readStatus": "unread",
          "receivedAfter": "={{ $json.yesterdayISO }}"
        },
        "operation": "getAll"
      },
      "typeVersion": 2.1
    },
    {
      "id": "82baeb6b-eaca-469a-b784-f279ced44a6b",
      "name": "4. Google Calendar \u2014 Fetch Today and Tomorrow",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        512,
        1408
      ],
      "parameters": {
        "options": {},
        "calendar": {
          "__rl": true,
          "mode": "id",
          "value": "primary"
        },
        "operation": "getAll"
      },
      "typeVersion": 1.3
    },
    {
      "id": "b4553e33-6150-42bd-af13-e623f894e404",
      "name": "5. Code \u2014 Merge Emails and Calendar",
      "type": "n8n-nodes-base.code",
      "position": [
        912,
        1280
      ],
      "parameters": {
        "jsCode": "// Collect emails and calendar events from parallel branches\nconst config = $('2. Set \u2014 Config Values').item.json;\n\n// Process emails\nlet emailItems = [];\ntry {\n  const gmailItems = $('3. Gmail \u2014 Fetch Unread Emails').all();\n  emailItems = gmailItems.map(item => {\n    const msg = item.json;\n    return {\n      from: msg.from || 'Unknown sender',\n      subject: msg.subject || 'No subject',\n      date: msg.date || '',\n      snippet: (msg.snippet || '').substring(0, 200)\n    };\n  });\n} catch (e) {\n  emailItems = [];\n}\n\n// Process calendar events\nlet calendarItems = [];\ntry {\n  const calItems = $('4. Google Calendar \u2014 Fetch Today and Tomorrow').all();\n  calendarItems = calItems.map(item => {\n    const event = item.json;\n    const startTime = event.start?.dateTime || event.start?.date || '';\n    const endTime = event.end?.dateTime || event.end?.date || '';\n    let timeDisplay = 'All day';\n    if (event.start?.dateTime) {\n      const start = new Date(event.start.dateTime);\n      const end = new Date(event.end?.dateTime || event.start.dateTime);\n      timeDisplay =\n        start.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' }) +\n        ' to ' +\n        end.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' });\n    }\n    const eventDate = new Date(startTime);\n    const today = new Date();\n    const isToday = eventDate.toDateString() === today.toDateString();\n    const tomorrow = new Date(today);\n    tomorrow.setDate(today.getDate() + 1);\n    const isTomorrow = eventDate.toDateString() === tomorrow.toDateString();\n    return {\n      title: event.summary || 'Untitled event',\n      time: timeDisplay,\n      location: event.location || '',\n      attendees: (event.attendees || []).length,\n      isToday,\n      isTomorrow\n    };\n  });\n} catch (e) {\n  calendarItems = [];\n}\n\nconst todayEvents = calendarItems.filter(e => e.isToday);\nconst tomorrowEvents = calendarItems.filter(e => e.isTomorrow);\n\n// Format emails for GPT\nlet emailText = 'No unread emails in the last 24 hours.';\nif (emailItems.length > 0) {\n  emailText = emailItems.slice(0, 20).map((e, i) =>\n    (i + 1) + '. From: ' + e.from + '\\n   Subject: ' + e.subject + '\\n   Preview: ' + e.snippet\n  ).join('\\n\\n');\n}\n\n// Format today events for GPT\nlet todayText = 'No events scheduled for today.';\nif (todayEvents.length > 0) {\n  todayText = todayEvents.map((e, i) =>\n    (i + 1) + '. ' + e.title + ' \u2014 ' + e.time +\n    (e.location ? ' \u2014 ' + e.location : '') +\n    (e.attendees > 0 ? ' (' + e.attendees + ' attendees)' : '')\n  ).join('\\n');\n}\n\n// Format tomorrow events for GPT\nlet tomorrowText = 'No events scheduled for tomorrow.';\nif (tomorrowEvents.length > 0) {\n  tomorrowText = tomorrowEvents.map((e, i) =>\n    (i + 1) + '. ' + e.title + ' \u2014 ' + e.time +\n    (e.location ? ' \u2014 ' + e.location : '') +\n    (e.attendees > 0 ? ' (' + e.attendees + ' attendees)' : '')\n  ).join('\\n');\n}\n\nreturn [{\n  json: {\n    emailText,\n    todayText,\n    tomorrowText,\n    totalEmails: emailItems.length,\n    totalTodayEvents: todayEvents.length,\n    totalTomorrowEvents: tomorrowEvents.length,\n    todayFormatted: config.todayFormatted,\n    companyName: config.companyName,\n    telegramChatId: config.telegramChatId\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "77b38857-9919-451e-9665-ff7fd022adbf",
      "name": "6. AI Agent \u2014 Write Morning Brief",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1152,
        1280
      ],
      "parameters": {
        "text": "=You are a smart personal assistant creating a morning brief for {{ $json.companyName }}.\n\nToday is {{ $json.todayFormatted }}.\n\nUNREAD EMAILS (last 24 hours) \u2014 {{ $json.totalEmails }} total:\n{{ $json.emailText }}\n\nTODAY'S CALENDAR \u2014 {{ $json.totalTodayEvents }} events:\n{{ $json.todayText }}\n\nTOMORROW'S CALENDAR \u2014 {{ $json.totalTomorrowEvents }} events:\n{{ $json.tomorrowText }}\n\nWrite a clean morning brief for Telegram. Use plain text only. No HTML.\nYou may use basic Telegram markdown: *bold* for headings, and dashes for lists.\n\nStructure it exactly like this:\n\nGood morning [name]! Here is your brief for [today's date].\n\n*URGENT EMAILS*\nList only emails that need a reply or action today. Skip newsletters, promotions, automated notifications, and receipts. For each urgent email write one line: who sent it and what action is needed. If no urgent emails write: No urgent emails today.\n\n*TODAY'S SCHEDULE*\nList all events for today with their time. If no events write: No meetings today \u2014 a free day.\n\n*PREPARE FOR TOMORROW*\nList tomorrow's events so the user can prepare. If tomorrow has meetings with more than 2 attendees, add one preparation tip. If no events write: Nothing scheduled for tomorrow.\n\n*ONE FOCUS FOR TODAY*\nBased on the emails and calendar, write one sentence recommending the most important thing to focus on today.\n\nKeep the entire brief under 300 words. Be direct and clear.",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 1.7
    },
    {
      "id": "dcfc7f3f-2e4a-4f1c-ac82-d0c8f0160014",
      "name": "7. OpenAI \u2014 GPT-4o-mini Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1152,
        1488
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {
          "maxTokens": 600,
          "temperature": 0.4
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ac24f86a-bb32-43cd-b45e-0a95adccb45f",
      "name": "8. Code \u2014 Prepare Telegram Message",
      "type": "n8n-nodes-base.code",
      "position": [
        1648,
        1280
      ],
      "parameters": {
        "jsCode": "// Get the brief text from GPT output\nconst briefText = $input.first().json.output || 'Good morning! Your brief could not be generated today. Please check your credentials.';\nconst config = $('2. Set \u2014 Config Values').item.json;\n\n// Add a timestamp footer\nconst timeNow = new Date().toLocaleTimeString('en-GB', {\n  hour: '2-digit',\n  minute: '2-digit',\n  timeZone: config.timezone || 'UTC'\n});\n\nconst fullMessage = briefText + '\\n\\n_Brief generated at ' + timeNow + ' \u2014 powered by n8n_';\n\nreturn [{\n  json: {\n    telegramMessage: fullMessage,\n    telegramChatId: config.telegramChatId\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "545aceff-2baa-4aaf-b17a-f1dce5519b51",
      "name": "9. Telegram \u2014 Send Morning Brief",
      "type": "n8n-nodes-base.telegram",
      "position": [
        1872,
        1280
      ],
      "parameters": {
        "text": "={{ $json.telegramMessage }}",
        "chatId": "={{ $json.telegramChatId }}",
        "additionalFields": {
          "parse_mode": "Markdown",
          "appendAttribution": false
        }
      },
      "typeVersion": 1.2
    }
  ],
  "connections": {
    "2. Set \u2014 Config Values": {
      "main": [
        [
          {
            "node": "3. Gmail \u2014 Fetch Unread Emails",
            "type": "main",
            "index": 0
          },
          {
            "node": "4. Google Calendar \u2014 Fetch Today and Tomorrow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7. OpenAI \u2014 GPT-4o-mini Model": {
      "ai_languageModel": [
        [
          {
            "node": "6. AI Agent \u2014 Write Morning Brief",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "3. Gmail \u2014 Fetch Unread Emails": {
      "main": [
        [
          {
            "node": "5. Code \u2014 Merge Emails and Calendar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1. Schedule \u2014 Every Weekday 8AM": {
      "main": [
        [
          {
            "node": "2. Set \u2014 Config Values",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6. AI Agent \u2014 Write Morning Brief": {
      "main": [
        [
          {
            "node": "8. Code \u2014 Prepare Telegram Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8. Code \u2014 Prepare Telegram Message": {
      "main": [
        [
          {
            "node": "9. Telegram \u2014 Send Morning Brief",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5. Code \u2014 Merge Emails and Calendar": {
      "main": [
        [
          {
            "node": "6. AI Agent \u2014 Write Morning Brief",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4. Google Calendar \u2014 Fetch Today and Tomorrow": {
      "main": [
        [
          {
            "node": "5. Code \u2014 Merge Emails and Calendar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}