This workflow corresponds to n8n.io template #9714 — we link there as the canonical source.
This workflow follows the Gmail → 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 →
{
"id": "YV9jJYlu5axheX09",
"name": "Automate weekly pet health emails with AI, Gmail and Google Sheets",
"tags": [
{
"id": "T3xhK1cIuPex0boX",
"name": "Templates",
"createdAt": "2025-09-03T11:06:03.839Z",
"updatedAt": "2025-09-03T11:06:03.839Z"
}
],
"nodes": [
{
"id": "a1cb38ea-5319-4042-84e6-caad7bd27e8f",
"name": "Generate Personalized Tip",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
1328,
80
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini",
"cachedResultName": "GPT-4O-MINI"
},
"options": {
"temperature": 0.7
},
"messages": {
"values": [
{
"content": "=Generate a personalized pet care tip for:\n- Pet name: {{ $json.Pet_Name }}\n- Pet type: {{ $json.Pet_Type }}\n- Pet age: {{ $json.pet_age_months }} months\n- Location: Country ISO is {{ $json['Country (ISO)'] }}\n- Current date: {{ $now.format('MMMM YYYY') }}\n\nRequirements:\n- Veterinary-aligned and breed-appropriate advice\n- **Climate-specific** (consider hemisphere, season in {{ $json['Country (ISO)'] }})\n- Region-specific risks (parasites, weather hazards)\n- Actionable advice (2-3 sentences)\n- Brief headline (under 10 words)\n- Life stage: puppy/kitten (<12mo), adult (1-7yr), senior (7+yr)\n\nExamples:\n- UK October: rain gear, indoor exercise, fireworks anxiety\n- Australia October: spring heat, snake awareness, hydration\n- Canada October: early cold prep, paw protection\n\nFormat as JSON:\n{\n \"topic\": \"Brief topic title\",\n \"headline\": \"Engaging headline for {{ $json.Pet_Name }}\",\n \"content\": \"2-3 sentence tip with location-specific advice\",\n \"category\": \"Nutrition/Exercise/Health/Behavior/Safety\"\n}"
},
{
"role": "system",
"content": "=You are a veterinary wellness expert providing evidence-based weekly tips for pet owners.\n\nGuidelines:\n- Align with AAHA/WSAVA veterinary standards\n- Tailor advice to pet type and life stage\n- Include seasonal considerations ({{ $now.format('MMMM') }})\n- Be warm but professional\n- Always recommend vet consultation for medical concerns"
}
]
}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.8
},
{
"id": "1703951c-551a-4f84-9aad-3d1a1fec6144",
"name": "No Operation, do nothing",
"type": "n8n-nodes-base.noOp",
"position": [
1104,
-112
],
"parameters": {},
"typeVersion": 1
},
{
"id": "b454fd2e-7690-45a8-9bd1-f30138c822c8",
"name": "Calculate Pet Age",
"type": "n8n-nodes-base.code",
"position": [
1104,
80
],
"parameters": {
"jsCode": "const items = $input.all();\n\nreturn items.map(item => {\n const birthDate = new Date(item.json.Date_of_Birth);\n const ageInMs = Date.now() - birthDate;\n const ageMonths = Math.floor(ageInMs / (1000 * 60 * 60 * 24 * 30.44));\n const ageYears = Math.floor(ageMonths / 12);\n const remainingMonths = ageMonths % 12;\n \n let petAge;\n if (ageMonths < 12) {\n petAge = `${ageMonths} month${ageMonths !== 1 ? 's' : ''}`;\n } else if (remainingMonths === 0) {\n petAge = `${ageYears} year${ageYears !== 1 ? 's' : ''}`;\n } else {\n petAge = `${ageYears} year${ageYears !== 1 ? 's' : ''} and ${remainingMonths} month${remainingMonths !== 1 ? 's' : ''}`;\n }\n \n return {\n json: {\n ...item.json,\n pet_age_months: ageMonths,\n pet_age: petAge\n }\n };\n});"
},
"typeVersion": 2
},
{
"id": "1ab3dd7f-bb4a-4c00-b21f-7df710e66a67",
"name": "Send Health Tip using Gmail",
"type": "n8n-nodes-base.gmail",
"position": [
1904,
80
],
"parameters": {
"sendTo": "={{ $json.email }}",
"message": "=<p>Hi {{ $json.owner_name }},</p>\n\n<h3>{{ $json.tip_headline }}</h3>\n\n<p>{{ $json.tip_content }}</p>\n\n\n<p>Stay pawsitive! \ud83d\udc3e<br>\n<em>PetCare Team</em></p>",
"options": {
"senderName": "PetCare Team",
"appendAttribution": false
},
"subject": "={{ $json.tip_headline }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "d68799f3-e768-4139-b8d9-68fc1fd9a657",
"name": "Weekly Trigger (Mondays 9am)",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
208,
80
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
1
],
"triggerAtHour": 9
}
]
}
},
"typeVersion": 1.2
},
{
"id": "0aaeebf6-69fb-4acd-a70a-2920d3188345",
"name": "Filter: Active + 7-Day Check",
"type": "n8n-nodes-base.code",
"position": [
656,
80
],
"parameters": {
"jsCode": "const items = $input.all();\n\nreturn items.filter(item => {\n // Must be Active status\n if (item.json.Status !== 'Active') return false;\n \n // Never sent email = include\n if (!item.json.Last_Email_Sent) return true;\n \n // Sent >7 days ago = include\n const daysSince = (Date.now() - new Date(item.json.Last_Email_Sent)) / (1000*60*60*24);\n return daysSince > 7;\n});"
},
"typeVersion": 2
},
{
"id": "b74fedec-acdf-400d-b2e7-0b9aab4f3044",
"name": "Process Pets One-by-One",
"type": "n8n-nodes-base.splitInBatches",
"position": [
880,
80
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "ca404c94-1c4b-4a42-b2e2-b244c3e66873",
"name": "Format Email Data",
"type": "n8n-nodes-base.code",
"position": [
1680,
80
],
"parameters": {
"jsCode": "// Get pet data from Calculate Pet Age node\nconst petData = $('Calculate Pet Age').item.json;\nconst aiResponse = $json.message.content;\n\nconst cleanResponse = aiResponse.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n\nlet tipData;\ntry {\n tipData = JSON.parse(cleanResponse);\n} catch (e) {\n tipData = {\n topic: 'Weekly Pet Care Tip',\n headline: `Important advice for ${petData.Pet_Name}`,\n content: cleanResponse,\n category: 'General'\n };\n}\n\nreturn {\n json: {\n email: petData.Email,\n owner_name: petData.Owner_Name,\n pet_name: petData.Pet_Name,\n pet_type: petData.Pet_Type,\n pet_age: petData.pet_age,\n pet_age_months: petData.pet_age_months,\n tip_topic: tipData.topic,\n tip_headline: tipData.headline,\n tip_content: tipData.content,\n tip_category: tipData.category,\n row_number: petData.row_number\n }\n};"
},
"typeVersion": 2
},
{
"id": "4d490b67-69ff-453d-9916-fd9ad3a43c2e",
"name": "Send via SendGrid (Disabled)",
"type": "n8n-nodes-base.sendGrid",
"disabled": true,
"position": [
1888,
-144
],
"parameters": {
"toEmail": "={{ $json.email }}",
"fromName": "PetCare Team",
"resource": "mail",
"fromEmail": "user@example.com",
"templateId": "=d-xxxxxx",
"dynamicTemplate": true,
"additionalFields": {},
"dynamicTemplateFields": {
"fields": [
{
"key": "owner_name",
"value": "={{ $json.owner_name }}"
},
{
"key": "pet_name",
"value": "= {{ $json.pet_name }}"
},
{
"key": "tip_topic",
"value": "={{ $json.tip_topic }}"
},
{
"key": "tip_headline",
"value": "={{ $json.tip_headline }}"
},
{
"key": "tip_content",
"value": "={{ $json.tip_content }}"
},
{
"key": "tip_category",
"value": "={{ $json.tip_category }}"
},
{
"key": "pet_type",
"value": "={{ $json.pet_type }}"
}
]
}
},
"typeVersion": 1
},
{
"id": "5875181b-6e58-46e6-9c48-569e6aad9130",
"name": "Update Last_Email_Sent Date",
"type": "n8n-nodes-base.googleSheets",
"position": [
2128,
80
],
"parameters": {
"columns": {
"value": {
"Email": "={{ $('Format Email Data').item.json.email }}",
"Last_Email_Sent": "={{$now}}"
},
"schema": [
{
"id": "Email",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Owner_Name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Owner_Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Pet_Name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Pet_Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Country (ISO)",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Country (ISO)",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Pet_Type",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Pet_Type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Date_of_Birth",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Date_of_Birth",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Last_Email_Sent",
"type": "string",
"display": true,
"required": false,
"displayName": "Last_Email_Sent",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1625335217,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qd1H_IY_KEtB1C-ZJzpdmw9_yQEqdpnrf4ZdlV02gW4/edit#gid=1625335217",
"cachedResultName": "Pets"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1qd1H_IY_KEtB1C-ZJzpdmw9_yQEqdpnrf4ZdlV02gW4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qd1H_IY_KEtB1C-ZJzpdmw9_yQEqdpnrf4ZdlV02gW4/edit?usp=drivesdk",
"cachedResultName": "N8N SHEETS TEST"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "0dc11fbc-448d-467e-8957-82887556d9bd",
"name": "Log to Email_Log Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
2352,
80
],
"parameters": {
"columns": {
"value": {
"Status": "={{ $('Send Health Tip using Gmail').item.json.labelIds[0] }}",
"Pet_Name": "={{ $('Format Email Data').item.json.pet_name }}",
"Timestamp": "={{ $now }}",
"Parent_Email": "={{ $('Format Email Data').item.json.email }}",
"Tip_Category": "={{ $('Format Email Data').item.json.tip_category }}"
},
"schema": [
{
"id": "Timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "Timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Parent_Email",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Parent_Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Pet_Name",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Pet_Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Tip_Category",
"type": "string",
"display": true,
"required": false,
"displayName": "Tip_Category",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Parent_Email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1157171316,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qd1H_IY_KEtB1C-ZJzpdmw9_yQEqdpnrf4ZdlV02gW4/edit#gid=1157171316",
"cachedResultName": "Email_Log"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1qd1H_IY_KEtB1C-ZJzpdmw9_yQEqdpnrf4ZdlV02gW4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qd1H_IY_KEtB1C-ZJzpdmw9_yQEqdpnrf4ZdlV02gW4/edit?usp=drivesdk",
"cachedResultName": "N8N SHEETS TEST"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "6a2afbfa-bc25-4776-921a-dd639b634c7a",
"name": "Wait 2 Seconds",
"type": "n8n-nodes-base.wait",
"position": [
2704,
304
],
"parameters": {
"amount": 2
},
"typeVersion": 1.1
},
{
"id": "011414fc-c326-4cd7-b5af-b00d986b1608",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-880,
-64
],
"parameters": {
"width": 864,
"height": 544,
"content": "## Sends AI-generated, location & age-specific health tips to pet owners every week.\n\n\n### HOW IT WORKS:\n1. Loads active pets from Google Sheets\n2. Filters pets who haven't received email in 7+ days\n3. Calculates pet age from birthdate\n4. AI generates climate-aware veterinary tips\n5. Sends personalized email via Gmail or Sendgrid\n6. Updates sheet with timestamp to prevent duplicates\n\n### REQUIREMENTS:\n- Google Sheet, Airtable, Typeform or similar with: Email, Owner_Name, Pet_Name, Pet_Type, Date_of_Birth, Country, Status, Last_Email_Sent\n- OpenAI API (GPT-4o-mini)\n- Gmail OAuth2, SendGrid, Brevo, Mailchimp or similar\n- Two sheets: \"Pets\" (main) + \"Email_Log\" (tracking)\n\n### SCHEDULE: \n\n- Every Monday 9am. Modify according to your needs.\n\n"
},
"typeVersion": 1
},
{
"id": "92430d38-0a38-4b96-8a72-7517f16f5baa",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
384,
272
],
"parameters": {
"color": 7,
"width": 192,
"height": 112,
"content": "**Loads all rows where Status = \"Active\"**\n\nFilters applied: Status column"
},
"typeVersion": 1
},
{
"id": "59a432e6-2f31-4919-a7fd-908aeb2948ff",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
624,
256
],
"parameters": {
"color": 7,
"width": 224,
"height": 208,
"content": " **Skips if:**\n- Status \u2260 \"Active\"\n- Last_Email_Sent < 7 days ago\n\n **Includes if:**\n- Never emailed (empty field)\n- Last email >7 days old\n\n \n"
},
"typeVersion": 1
},
{
"id": "0927faad-6699-41f3-9082-9133f85a9111",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1024,
224
],
"parameters": {
"color": 7,
"width": 288,
"height": 192,
"content": "**Converts Date_of_Birth to readable age:**\n\n- <12mo: \"8 months\"\n- 12+mo: \"2 years and 3 months\"\n- Exact: \"5 years\"\n\n\nAdds: pet_age, pet_age_months\n\n"
},
"typeVersion": 1
},
{
"id": "daeda379-8395-4133-b7f5-cf4254129b27",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1360,
224
],
"parameters": {
"color": 7,
"width": 304,
"height": 208,
"content": "**Climate-specific advice based on:**\n\n- Pet type (Dog/Cat)\n- Age in months\n- Country (hemisphere + season)\n- Current date\n\nReturns JSON: topic, headline, content, category"
},
"typeVersion": 1
},
{
"id": "628e8125-7d58-4841-89a1-7460bbb7cc2b",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
2160,
288
],
"parameters": {
"color": 7,
"width": 304,
"height": 192,
"content": "Updates: Last_Email_Sent = current timestamp\nMatches on: Email column"
},
"typeVersion": 1
},
{
"id": "136e8aa3-f5d8-4786-8e00-08d25bb7cef3",
"name": "Load Pet Info",
"type": "n8n-nodes-base.googleSheets",
"position": [
432,
80
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "Active",
"lookupColumn": "Status"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1625335217,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qd1H_IY_KEtB1C-ZJzpdmw9_yQEqdpnrf4ZdlV02gW4/edit#gid=1625335217",
"cachedResultName": "Parents_Children"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1qd1H_IY_KEtB1C-ZJzpdmw9_yQEqdpnrf4ZdlV02gW4",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qd1H_IY_KEtB1C-ZJzpdmw9_yQEqdpnrf4ZdlV02gW4/edit?usp=drivesdk",
"cachedResultName": "N8N SHEETS TEST"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "bfff3b2c-40b9-4522-a862-e99f353745c2",
"connections": {
"Load Pet Info": {
"main": [
[
{
"node": "Filter: Active + 7-Day Check",
"type": "main",
"index": 0
}
]
]
},
"Wait 2 Seconds": {
"main": [
[
{
"node": "Process Pets One-by-One",
"type": "main",
"index": 0
}
]
]
},
"Calculate Pet Age": {
"main": [
[
{
"node": "Generate Personalized Tip",
"type": "main",
"index": 0
}
]
]
},
"Format Email Data": {
"main": [
[
{
"node": "Send via SendGrid (Disabled)",
"type": "main",
"index": 0
},
{
"node": "Send Health Tip using Gmail",
"type": "main",
"index": 0
}
]
]
},
"Log to Email_Log Sheet": {
"main": [
[
{
"node": "Wait 2 Seconds",
"type": "main",
"index": 0
}
]
]
},
"Process Pets One-by-One": {
"main": [
[
{
"node": "No Operation, do nothing",
"type": "main",
"index": 0
}
],
[
{
"node": "Calculate Pet Age",
"type": "main",
"index": 0
}
]
]
},
"Generate Personalized Tip": {
"main": [
[
{
"node": "Format Email Data",
"type": "main",
"index": 0
}
]
]
},
"Send Health Tip using Gmail": {
"main": [
[
{
"node": "Update Last_Email_Sent Date",
"type": "main",
"index": 0
}
]
]
},
"Update Last_Email_Sent Date": {
"main": [
[
{
"node": "Log to Email_Log Sheet",
"type": "main",
"index": 0
}
]
]
},
"Filter: Active + 7-Day Check": {
"main": [
[
{
"node": "Process Pets One-by-One",
"type": "main",
"index": 0
}
]
]
},
"Send via SendGrid (Disabled)": {
"main": [
[
{
"node": "Update Last_Email_Sent Date",
"type": "main",
"index": 0
}
]
]
},
"Weekly Trigger (Mondays 9am)": {
"main": [
[
{
"node": "Load Pet Info",
"type": "main",
"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.
gmailOAuth2googleSheetsOAuth2ApiopenAiApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automate weekly pet wellness emails with AI-generated, location and age-specific advice.
Source: https://n8n.io/workflows/9714/ — 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.
Stop finding out you're out of stock after a customer already tried to buy. This workflow monitors your entire product inventory daily, calculates how fast each SKU is selling, and automatically raise
The scoreboard shows you what happened. This workflow tells you why it happened. Every time an IPL match ends this automation detects the completed result, fetches the full scorecard, and sends it to
Look for new UseCases. Uses googleSheets, openAi, gmail. Scheduled trigger; 7 nodes.
Send A Chatgpt Email Reply And Save Responses To Google Sheets. Uses openAi, gmailTrigger, stickyNote, gmail. Event-driven trigger; 49 nodes.
Code. Uses openAi, gmailTrigger, stickyNote, gmail. Event-driven trigger; 49 nodes.