AutomationFlowsAI & RAG › Send Personalized Occasion Wishes with Ai, Google Sheets and Gmail

Send Personalized Occasion Wishes with Ai, Google Sheets and Gmail

ByArbaz Asif @arbaz on n8n.io

How it works Runs daily to check if today matches any birthday, anniversary, or special occasion in your Google Sheet AI Agent reads the sheet and returns a list of users having a special occasion to wish with details and a personalized wishing message If there is no one to…

Cron / scheduled trigger★★★★☆ complexityAI-powered11 nodesAgentGoogle Sheets ToolGmailOpenAI Chat
AI & RAG Trigger: Cron / scheduled Nodes: 11 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #11143 — we link there as the canonical source.

This workflow follows the Agent → Gmail 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 →

Download .json
{
  "id": "owivLiS5MO6IfmT4",
  "name": "occasion reminder",
  "tags": [],
  "nodes": [
    {
      "id": "0f023a71-85b7-4f0e-a02f-cbfaa9d89100",
      "name": "Every Day at 8 AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1120,
        -64
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 24
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "419cacda-a902-427a-8b7c-769534544a21",
      "name": "Date & Time",
      "type": "n8n-nodes-base.dateTime",
      "position": [
        -928,
        -64
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 2
    },
    {
      "id": "8f48ee04-443c-4d66-8e80-4d7f478bbef1",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -656,
        -64
      ],
      "parameters": {
        "text": "=Today's date is: {{ $json.currentDate }}\n\nPlease check the Google Sheet resource for any occasions matching today's date (month and day only).\n\nOUTPUT FORMAT:\nWhen occasion is found, return ONLY valid format like this (no other text):\n[{\n  \"hasOccasion\": true,\n  \"email\": \"sarah@email.com\",\n  \"subject\": \"Happy 30th Anniversary Sarah! \ud83c\udf39\u2615\",\n  \"message\": \"Happy 30th Anniversary, my love!...\"\n}]\n\nWhen no occasion is found, return ONLY:\n[{\n  \"hasOccasion\": false\n}]\n\nProceed now.",
        "options": {
          "systemMessage": "=You are my personal assistant specialized in relationship management and special occasion tracking.\n\nYOUR IDENTITY:\n- Thoughtful and detail-oriented\n- You help me maintain strong relationships by ensuring I never miss important dates\n- You have access to a Google Sheet containing all my friends' and family members' special occasions\n\nYOUR CAPABILITIES:\n- You can read and analyze dates from the Google Sheet resource attached\n- You understand different types of occasions: birthdays, anniversaries, graduations, engagements, etc.\n- You can calculate ages and anniversary years accurately\n- You generate personalized, heartfelt messages appropriate for different relationships\n\nYOUR RESPONSIBILITIES:\n1. Check if today matches any occasion in the sheet (compare month and day only, ignore year)\n2. If occasions are found today:\n   - Extract all relevant details (Name, Email, Occasion_Type, Relationship, Personal_Note, Occasion_Date)\n   - Calculate years passed (current year minus occasion year)\n   - Use correct ordinal suffix (1st, 2nd, 3rd, 4th, 21st, 22nd, 23rd, etc.)\n   - Generate warm, personalized messages that reflect the relationship type\n3. If no occasions are found today:\n   - Simply respond: \"No occasions today.\"\n\nMESSAGE GUIDELINES:\n- Adapt tone based on relationship:\n  * Spouse/Partner: Romantic, intimate, loving\n  * Parents: Respectful, warm, appreciative\n  * Siblings: Casual, playful, supportive\n  * Friends: Friendly, fun, genuine\n  * Professional contacts: Formal, respectful, professional\n- Reference the Personal_Note to add authentic, specific touches\n- Keep messages 3-5 sentences\n- Start birthday/anniversary messages with \"Happy [number][suffix] [occasion]!\"\n- Be genuine and heartfelt, never generic or robotic\n- Each message should feel unique and personal\n\nIMPORTANT RULES:\n- Match dates by MM-DD only (ignore the year in comparison)\n- Always calculate the correct age/years for context\n- Never send wishes if the date doesn't match\n- Process each person separately if multiple occasions exist today\n- Maintain privacy and handle personal information carefully\n"
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "1ea6f0a1-0017-4b76-9e93-00903bcdd0a0",
      "name": "Get row(s) in sheet in Google Sheets",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        -496,
        128
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/18i8WW1ytW7Zq255Djtj9Xg_uKIsAu9_Oqs452IkRiGQ/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "18i8WW1ytW7Zq255Djtj9Xg_uKIsAu9_Oqs452IkRiGQ",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/18i8WW1ytW7Zq255Djtj9Xg_uKIsAu9_Oqs452IkRiGQ/edit?usp=drivesdk",
          "cachedResultName": "data"
        },
        "descriptionType": "manual",
        "toolDescription": "Get row(s) in sheet in Google Sheets from the sheet named data."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "94e4ccb3-9794-44f8-872b-e710197ffdec",
      "name": "Send a message",
      "type": "n8n-nodes-base.gmail",
      "position": [
        -96,
        -64
      ],
      "parameters": {
        "sendTo": "={{ $json.output.email }}",
        "message": "={{ $json.output.message }}",
        "options": {},
        "subject": "={{ $json.output.subject }}"
      },
      "typeVersion": 2.1
    },
    {
      "id": "778195ab-b64b-4c06-96e9-db0901d7c63b",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -656,
        112
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "bdeccaf3-6199-4e8a-ab59-3a7d11000589",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "position": [
        -256,
        -64
      ],
      "parameters": {
        "jsCode": "// Get the string returned by the AI agent\nlet raw = items[0].json.output;\n\n// Sometimes output may already be parsed, handle both cases\nlet parsed;\n\ntry {\n  // Try to parse directly\n  parsed = JSON.parse(raw);\n} catch (e) {\n  // If output contains escaped JSON inside JSON, parse twice\n  try {\n    parsed = JSON.parse(JSON.parse(raw));\n  } catch (e2) {\n    throw new Error(\"AI output is not valid JSON array: \" + raw);\n  }\n}\n\n// Ensure we always get an array\nif (!Array.isArray(parsed)) {\n  parsed = [parsed];\n}\n\n// If no occasions found \u2192 [{ hasOccasion: false }]\nif (parsed.length === 1 && parsed[0].hasOccasion === false) {\n  // Return zero items \u2192 nothing is sent\n  return [];\n}\n\n// Convert each event into its own n8n item\nconst newItems = parsed.map(ev => ({\n  json: {\n    hasOccasion: ev.hasOccasion,\n    email: ev.email,\n    subject: ev.subject,\n    message: ev.message\n  }\n}));\n\nreturn newItems;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "186dc502-4b99-49cf-969f-63412a6938b4",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1776,
        -176
      ],
      "parameters": {
        "width": 528,
        "height": 480,
        "content": "## Overview: Automated Occasion Wisher \n**How it works** \n- Runs daily to check if today matches any birthday, anniversary, or special occasion in your Google Sheet\n- AI Agent reads the sheet and returns list of users having special occasion to wish with details and personalized wishing message\n- If there is no one to wish, no email is sent. If there are multiple people to wish, multiple personalized emails are sent\n\n**Setup steps** \n\n- Connect your Google Sheet containing columns as: Name, Occasion_Date, Email,\tOccasion_Type, Relationship, Personal_Note\n- Insert the AI prompt ensuring strict JSON output (list format only)\n- Configure the Email node for sending the final message\n\n**Customization**\n\n- Edit AI prompt to change message tone, length, or emojis\n- Add support for multiple reminder styles (e.g., early notification)\n- Extend with logging, Slack alerts, or saving sent-email history\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1bd4a7de-1b07-4d63-bbb8-2da1c4881dca",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1152,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 352,
        "height": 288,
        "content": "## 1. Trigger Everyday and fetch current date "
      },
      "typeVersion": 1
    },
    {
      "id": "cd9810d0-dac7-4280-8dda-8521d3edae99",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -720,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 352,
        "height": 480,
        "content": "## 2. AI Agent with Google Sheets resource"
      },
      "typeVersion": 1
    },
    {
      "id": "bcd7d0f9-3e97-426e-8344-2c5ad7ac2552",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -304,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 352,
        "height": 288,
        "content": "## 3. Format output from AI Agent and send email if found any event "
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "2ef52b03-2f91-431d-8255-b414812da166",
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Date & Time": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every Day at 8 AM": {
      "main": [
        [
          {
            "node": "Date & Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Send a message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet in Google Sheets": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

How it works Runs daily to check if today matches any birthday, anniversary, or special occasion in your Google Sheet AI Agent reads the sheet and returns a list of users having a special occasion to wish with details and a personalized wishing message If there is no one to…

Source: https://n8n.io/workflows/11143/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This workflow automates end-to-end ESG (Environmental, Social, and Governance) sustainability reporting for enterprise sustainability teams, compliance officers, and green governance leads. It solves

Agent, OpenAI Chat, Output Parser Structured +12
AI & RAG

Schedules automated vendor pricing analysis across multiple sources. Fetches delivery reliability and contract data, analyzes vendor performance using Claude AI, then distributes consolidated reports

HTTP Request, Airtable, OpenAI Chat +9
AI & RAG

Who is this template for? This workflow is perfect for competitive‑intel analysts, product managers, content marketers, and anyone who tracks multiple company blogs or news sources. If you need a week

HTTP Request, Output Parser Structured, Agent +5
AI & RAG

This n8n automation workflow automates the creation, scripting, production, and posting of YouTube videos. It leverages AI (OpenAI), image generation (PIAPI), video rendering (Shotstack), and platform

Agent, OpenAI Chat, Airtable Tool +7
AI & RAG

Enhance your support, onboarding, and internal knowledge workflows with an intelligent RAG-powered chatbot that responds using live data stored in Google Sheets. 🤖📚 Built for teams that rely on struct

Chat Trigger, Output Parser Structured, Memory Buffer Window +6