This workflow corresponds to n8n.io template #15335 — we link there as the canonical source.
This workflow follows the Chainllm → Google Sheets recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"meta": {
"templateCredsSetupCompleted": false
},
"name": "\ud83c\udf82 Birthday & Anniversary Reminder with AI Gift Ideas \u2014 Telegram",
"tags": [
{
"name": "ai"
},
{
"name": "telegram"
},
{
"name": "reminder"
},
{
"name": "personal"
}
],
"nodes": [
{
"id": "39fe07af-7b6c-413b-bc20-1e034d86d21a",
"name": "\u23f0 Daily 8 AM",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
64,
208
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * *"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "731b05eb-b80a-44b7-8baf-83f33adef83d",
"name": "\u25b6\ufe0f Manual Test",
"type": "n8n-nodes-base.manualTrigger",
"position": [
64,
400
],
"parameters": {},
"typeVersion": 1
},
{
"id": "2edf1594-3e7b-4f35-afe5-6537072f6696",
"name": "\ud83d\udcd6 Read People",
"type": "n8n-nodes-base.googleSheets",
"notes": "\ud83d\udc46 SETUP: Select your Google Sheet and make sure the tab is named 'People' with columns: name | birthday | relationship | interests",
"position": [
352,
304
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "name",
"value": "People"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": ""
}
},
"typeVersion": 4.5
},
{
"id": "e00171ba-b535-49a2-a0f3-6021367162cc",
"name": "\ud83d\udcc5 Check Dates",
"type": "n8n-nodes-base.code",
"position": [
608,
304
],
"parameters": {
"jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// CHECK FOR UPCOMING BIRTHDAYS\n// Finds birthdays happening today or within 7 days\n//\n// To change the reminder window, edit the\n// reminderDays variable below (default: 7)\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst reminderDays = 7;\nconst people = $input.all();\n\nconst today = new Date();\ntoday.setHours(0, 0, 0, 0);\n\nconst alerts = [];\n\nfor (const item of people) {\n const p = item.json;\n if (!p.name || !p.birthday) continue;\n\n let bday;\n try {\n bday = new Date(p.birthday);\n if (isNaN(bday.getTime())) continue;\n } catch { continue; }\n\n const thisYear = new Date(today.getFullYear(), bday.getMonth(), bday.getDate());\n const nextBday = thisYear < today\n ? new Date(today.getFullYear() + 1, bday.getMonth(), bday.getDate())\n : thisYear;\n\n const daysUntil = Math.round((nextBday - today) / (1000 * 60 * 60 * 24));\n\n if (daysUntil === 0) {\n alerts.push({\n name: p.name,\n type: 'today',\n days_until: 0,\n age: today.getFullYear() - bday.getFullYear(),\n relationship: p.relationship || 'Contact',\n interests: p.interests || '',\n date: nextBday.toISOString().split('T')[0],\n });\n } else if (daysUntil === reminderDays) {\n alerts.push({\n name: p.name,\n type: 'upcoming',\n days_until: daysUntil,\n age: nextBday.getFullYear() - bday.getFullYear(),\n relationship: p.relationship || 'Contact',\n interests: p.interests || '',\n date: nextBday.toISOString().split('T')[0],\n });\n }\n}\n\nif (alerts.length === 0) {\n return [{ json: { _skip: true } }];\n}\n\nreturn alerts.map(a => ({ json: a }));"
},
"typeVersion": 2
},
{
"id": "683c57b9-578f-4d3a-a4d2-d5ac857e2915",
"name": "\ud83c\udf81 Format Messages",
"type": "n8n-nodes-base.code",
"position": [
864,
304
],
"parameters": {
"jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// FORMAT HEADER + BUILD AI PROMPT\n// Creates the notification header and prepares\n// a personalized prompt for the AI model\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n const a = item.json;\n\n if (a._skip) continue;\n if (!a.name) continue;\n\n let header = '';\n\n if (a.type === 'today') {\n header += `\ud83c\udf82 TODAY \u2014 ${a.name} turns ${a.age}!\\n`;\n header += `\ud83d\udc64 ${a.relationship}\\n`;\n header += `\ud83d\udcc5 ${a.date}\\n`;\n } else {\n header += `\ud83d\udcc5 REMINDER \u2014 ${a.name}'s birthday in ${a.days_until} days\\n`;\n header += `\ud83c\udf82 Turning ${a.age} on ${a.date}\\n`;\n header += `\ud83d\udc64 ${a.relationship}\\n`;\n }\n\n if (a.interests) {\n header += `\ud83d\udca1 Interests: ${a.interests}\\n`;\n }\n\n const chatInput = `You are a thoughtful friend. Write a short, warm birthday message (3-4 lines max) for:\\n\\nName: ${a.name}\\nAge: ${a.age}\\nRelationship: ${a.relationship}\\nInterests: ${a.interests || 'not specified'}\\nEvent: ${a.type === 'today' ? 'Birthday is TODAY' : 'Birthday is coming up soon'}\\n\\nAlso suggest 3 personalized gift ideas based on their interests (one line each, with price estimate $20-100).\\n\\nFormat your response EXACTLY like this:\\n\\n\ud83d\udc8c MESSAGE:\\n[your warm message here]\\n\\n\ud83c\udf81 GIFT IDEAS:\\n1. [specific gift] ($XX)\\n2. [specific gift] ($XX)\\n3. [specific gift] ($XX)`;\n\n results.push({ json: {\n header: header,\n chatInput: chatInput,\n name: a.name,\n } });\n}\n\nif (results.length === 0) {\n return [];\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "d22c875c-432d-4a44-b2a9-68cb593ece52",
"name": "\ud83e\udd16 AI Personalize",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
1120,
304
],
"parameters": {
"batching": {}
},
"typeVersion": 1.9
},
{
"id": "8869ef4d-b0ed-401b-b973-020057f6808b",
"name": "Groq Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGroq",
"notes": "\ud83d\udc46 SETUP: Add your Groq API credential (free at console.groq.com)",
"position": [
1184,
528
],
"parameters": {
"model": "llama-3.1-8b-instant",
"options": {}
},
"typeVersion": 1
},
{
"id": "fabb1d2c-5b2d-4dd4-8323-1709a9f4ab2d",
"name": "\ud83d\udcdd Combine Message",
"type": "n8n-nodes-base.code",
"position": [
1392,
304
],
"parameters": {
"jsCode": "// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n// COMBINE HEADER + AI RESPONSE\n// Merges the formatted header with AI output\n// into one final Telegram message\n// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\nconst items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n const header = $('\ud83c\udf81 Format Messages').item.json.header || '';\n const aiResponse = item.json.text || item.json.response || item.json.output || '';\n \n const finalMessage = header + '\\n' + aiResponse;\n \n results.push({ json: { message: finalMessage } });\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "82995885-5700-42ff-8540-4d5553957d43",
"name": "\ud83d\udcf2 Send Telegram",
"type": "n8n-nodes-base.telegram",
"notes": "\ud83d\udc46 SETUP:\n1. Add Telegram credential (token from @BotFather)\n2. Set Chat ID (get yours from @userinfobot)",
"position": [
1648,
304
],
"parameters": {
"text": "={{ $json.message }}",
"additionalFields": {}
},
"typeVersion": 1.2
},
{
"id": "b3b8e08a-dc6f-491d-b625-adccf4753114",
"name": "Note: Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-144,
-560
],
"parameters": {
"width": 480,
"height": 660,
"content": "## \ud83c\udf82 Birthday & Anniversary Reminder with AI Gift Ideas\n\n### How it works\n1. Runs daily at 8:00 AM (configurable schedule).\n2. Reads a list of people (name, birthday, role, interests) from Google Sheets.\n3. Checks which birthdays or anniversaries are coming up in the next 7 days.\n4. Uses Groq AI (free) to generate 3 personalized gift suggestions per person.\n5. Sends a beautifully formatted reminder with gift ideas to your Telegram.\n\n### Setup steps\n- [ ] Create a Google Sheet with columns: `name`, `birthday` (DD/MM), `role`, `interests`\n- [ ] Create a Telegram bot via @BotFather and get your chat ID from @userinfobot\n- [ ] Get a free Groq API key at [console.groq.com](https://console.groq.com)\n- [ ] Add Groq as an OpenAI credential with base URL `https://api.groq.com/openai/v1`\n- [ ] Connect Google Sheets and Telegram credentials to the workflow nodes\n\n### Customization\n- Change the schedule in the trigger node (default: daily 8 AM)\n- Adjust the lookahead window (default: 7 days) in the Check Dates code node\n- Modify the AI prompt to change gift suggestion style or add budget constraints"
},
"typeVersion": 1
},
{
"id": "3dd0f21c-f92b-4660-acb6-fa1ba7ef9ae1",
"name": "Note: Step 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
240,
176
],
"parameters": {
"color": 7,
"width": 296,
"height": 296,
"content": "## Step 1: Read Data\n\nReads your people list from Google Sheets.\nRequired columns: `name`, `birthday` (DD/MM), `relationship`, `interests`"
},
"typeVersion": 1
},
{
"id": "a30beaf7-0b59-496f-b12b-ad052be94ecd",
"name": "Note: Step 2",
"type": "n8n-nodes-base.stickyNote",
"position": [
544,
176
],
"parameters": {
"color": 7,
"width": 456,
"height": 296,
"content": "## Step 2: Check Dates\n\nCompares each person's birthday against today.\nOnly events **today** or **in 7 days** pass through."
},
"typeVersion": 1
},
{
"id": "4de74857-d21b-4ca7-8967-ea4b1677c2f3",
"name": "Note: Step 3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1008,
176
],
"parameters": {
"color": 7,
"width": 540,
"height": 504,
"content": "## Step 3: AI Gift Ideas (Groq \u2014 Free)\n\nUses Groq LLM to generate a warm birthday message + 3 personalized gift suggestions based on the person's interests. Free at console.groq.com"
},
"typeVersion": 1
},
{
"id": "34d3d951-8583-4dd7-af86-fb427afa2e49",
"name": "Note: Step 4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1552,
176
],
"parameters": {
"color": 7,
"width": 320,
"height": 296,
"content": "## Step 4: Send Telegram\n\nSends formatted message with birthday info + AI gift ideas. Create a bot via @BotFather, get your chat ID via @userinfobot."
},
"typeVersion": 1
},
{
"id": "560024c0-a9a3-4af8-a482-ff25dcb4bdaa",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-144,
112
],
"parameters": {
"color": 7,
"width": 368,
"height": 448,
"content": "## Initialize workflow\n\nStarts the workflow."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"connections": {
"\u23f0 Daily 8 AM": {
"main": [
[
{
"node": "\ud83d\udcd6 Read People",
"type": "main",
"index": 0
}
]
]
},
"Groq Chat Model": {
"ai_languageModel": [
[
{
"node": "\ud83e\udd16 AI Personalize",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"\ud83d\udcc5 Check Dates": {
"main": [
[
{
"node": "\ud83c\udf81 Format Messages",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udcd6 Read People": {
"main": [
[
{
"node": "\ud83d\udcc5 Check Dates",
"type": "main",
"index": 0
}
]
]
},
"\u25b6\ufe0f Manual Test": {
"main": [
[
{
"node": "\ud83d\udcd6 Read People",
"type": "main",
"index": 0
}
]
]
},
"\ud83e\udd16 AI Personalize": {
"main": [
[
{
"node": "\ud83d\udcdd Combine Message",
"type": "main",
"index": 0
}
]
]
},
"\ud83c\udf81 Format Messages": {
"main": [
[
{
"node": "\ud83e\udd16 AI Personalize",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udcdd Combine Message": {
"main": [
[
{
"node": "\ud83d\udcf2 Send Telegram",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Never forget a birthday again. This workflow checks your contacts daily and sends you a Telegram alert 7 days before each birthday and on the day itself — with a warm, AI-generated personal message and 3 gift ideas tailored to the person's interests. Fill a Google Sheet…
Source: https://n8n.io/workflows/15335/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Get notified when the International Space Station passes over your location - but only when you can actually see it! This workflow combines real-time ISS tracking with weather condition checks to send
This template is perfect for: AI art enthusiasts who want to stay updated on trending AI-generated artwork Content curators looking to automate art discovery Japanese-speaking users who want translate
This workflow automates the process of generating and managing local business leads by scraping Google Maps data, analyzing business information with AI, and creating personalized outreach messages. T
GitHub Trending → Redis Dedup → AI Post → Telegram. Uses httpRequest, redis, telegram, chainLlm. Scheduled trigger; 19 nodes.
DailyQuote. Uses scheduleTrigger, httpRequest, telegram, chainLlm. Scheduled trigger; 17 nodes.