MinAI - Về trang chủ
Lý thuyết
2/1340 phút
Đang tải...

Calendar Workflows

Tự động hóa calendar với n8n - meeting reminders, prep materials, automatic follow-ups

📅 Calendar Workflows

Calendar Management

0

🎯 Mục tiêu bài học

TB5 min

Sau bài học này, bạn sẽ:

✅ Kết nối Google Calendar với n8n

✅ Tạo multi-stage meeting reminders tự động

✅ Xây dựng meeting prep automation và auto meeting notes

✅ Implement post-meeting follow-up và calendar analytics

Calendar là trung tâm của productivity. Bài này hướng dẫn automate meeting prep, reminders, và follow-ups để bạn luôn chuẩn bị tốt nhất.

1

🔍 Calendar Automation Overview

TB5 min

What Can Be Automated:

📅Calendar Automation Tasks
📋PRE-MEETING
Send reminders (1 day, 1 hour)
📄Prepare agenda documents
👥Gather participant info
📝Create meeting notes template
📧Send prep materials
🎯DURING MEETING
🎥Auto-start recordings
📝Live transcription
✍️Note-taking assistance
📝POST-MEETING
📧Send summary to attendees
Create action items
🔄Schedule follow-ups
🔧Update CRM/project tools

Checkpoint

Có bao nhiêu giai đoạn trong meeting lifecycle có thể automate?

2

🛠️ Google Calendar Setup

TB5 min

Connect Google Calendar:

Ví dụ
11. Add Google Calendar node
22. Create new credential
33. OAuth2 authentication
44. Required scopes:
5 - calendar.readonly
6 - calendar.events
7 - calendar.settings.readonly

Calendar Trigger Options:

Trigger when
Event created
✏️Event updated
🗑️Event deleted
Event starts (upcoming)
🔄Poll for events

Checkpoint

Những trigger options nào có sẵn cho Google Calendar trong n8n?

3

⚡ Workflow 1: Meeting Reminder System

TB5 min

Smart Reminders:

Multi-Stage Reminders

Schedule: Every Hour
📅Get Events (next 24h)
🔄For Each Event
📧24h → Prep Reminder | 1h → Start Reminder | 15m → Join Link

Reminder Logic Code:

JavaScript
1const events = $input.all();
2const now = new Date();
3const reminders = [];
4
5for (const event of events) {
6 const startTime = new Date(event.json.start.dateTime);
7 const hoursUntil = (startTime - now) / (1000 * 60 * 60);
8
9 // 24-hour reminder
10 if (hoursUntil > 23 && hoursUntil <= 24) {
11 reminders.push({
12 event: event.json,
13 type: '24h',
14 message: `📅 Tomorrow: ${event.json.summary}`,
15 includeAgenda: true
16 });
17 }
18
19 // 1-hour reminder
20 if (hoursUntil > 0.9 && hoursUntil <= 1) {
21 reminders.push({
22 event: event.json,
23 type: '1h',
24 message: `⏰ In 1 hour: ${event.json.summary}`,
25 includeJoinLink: true
26 });
27 }
28
29 // 15-minute reminder
30 if (hoursUntil > 0.2 && hoursUntil <= 0.25) {
31 reminders.push({
32 event: event.json,
33 type: '15m',
34 message: `🔔 Starting soon: ${event.json.summary}`,
35 includeJoinLink: true,
36 urgent: true
37 });
38 }
39}
40
41return reminders;

Send Slack Reminder:

JSON
1{
2 "name": "Send Slack Reminder",
3 "type": "n8n-nodes-base.slack",
4 "parameters": {
5 "channel": "@me",
6 "text": "={{ $json.message }}",
7 "attachments": [
8 {
9 "color": "#4CAF50",
10 "fields": [
11 {
12 "title": "Time",
13 "value": "={{ $json.event.start.dateTime }}",
14 "short": true
15 },
16 {
17 "title": "Location",
18 "value": "={{ $json.event.location || $json.event.hangoutLink || 'TBD' }}",
19 "short": true
20 }
21 ],
22 "actions": [
23 {
24 "type": "button",
25 "text": "Join Meeting",
26 "url": "={{ $json.event.hangoutLink }}"
27 }
28 ]
29 }
30 ]
31 }
32}

Checkpoint

Multi-stage reminder system gửi reminders ở những thời điểm nào?

4

🔧 Workflow 2: Meeting Prep Automation

TB5 min

Auto-Generate Prep Materials:

Meeting Prep Generator

📅Calendar Trigger: Event Tomorrow
👥Get Attendee Info
🔍Parallel: CRM + LinkedIn + Email Lookup
📄Generate Prep Document
📝Create Google Doc
📧Send via Slack/Email

Attendee Research Code:

JavaScript
1const event = $input.item.json;
2const attendees = event.attendees || [];
3
4// Extract external attendees (not from your company)
5const externalAttendees = attendees.filter(a =>
6 !a.email.includes('@yourcompany.com') &&
7 !a.self
8);
9
10const prepInfo = {
11 eventTitle: event.summary,
12 eventTime: event.start.dateTime,
13 agenda: event.description || 'No agenda provided',
14 attendees: externalAttendees.map(a => ({
15 email: a.email,
16 name: a.displayName || a.email.split('@')[0],
17 company: a.email.split('@')[1]?.replace('.com', '')
18 }))
19};
20
21return prepInfo;

Create Prep Document:

JavaScript
1const prep = $input.item.json;
2
3const template = `
4# Meeting Prep: ${prep.eventTitle}
5
6## Details
7- **When:** ${new Date(prep.eventTime).toLocaleString()}
8- **Attendees:** ${prep.attendees.map(a => a.name).join(', ')}
9
10## Agenda
11${prep.agenda}
12
13## Attendee Research
14${prep.attendees.map(a => `
15### ${a.name} (${a.company})
16- **Email:** ${a.email}
17- **Recent interactions:** [Check email/CRM]
18- **LinkedIn:** [Research needed]
19- **Notes:**
20`).join('\n')}
21
22## Questions to Ask
231.
242.
253.
26
27## Meeting Objectives
281.
292.
30
31## Notes
32(To be filled during meeting)
33
34## Action Items
35(To be filled after meeting)
36`;
37
38return { content: template, title: `Prep: ${prep.eventTitle}` };

Checkpoint

Meeting prep automation thu thập thông tin attendees từ những nguồn nào?

5

🏗️ Workflow 3: Auto Meeting Notes

TB5 min

Create Notes Template:

Meeting Notes Creator

📅Calendar Trigger: Meeting Started
📝Create Notion Page
📋Add Event Details
💬Send Page Link to Slack

Notion Meeting Notes Template:

JSON
1{
2 "name": "Create Notion Page",
3 "type": "n8n-nodes-base.notion",
4 "parameters": {
5 "operation": "create",
6 "databaseId": "meetings-database-id",
7 "properties": {
8 "Title": {
9 "title": [{ "text": { "content": "={{ $json.summary }}" }}]
10 },
11 "Date": {
12 "date": { "start": "={{ $json.start.dateTime }}" }
13 },
14 "Attendees": {
15 "multi_select": "={{ $json.attendees.map(a => ({name: a.email})) }}"
16 },
17 "Status": {
18 "select": { "name": "In Progress" }
19 }
20 },
21 "content": {
22 "type": "callout",
23 "content": "Meeting in progress..."
24 }
25 }
26}

Checkpoint

Auto meeting notes template bao gồm những sections nào?

6

📊 Workflow 4: Post-Meeting Follow-Up

TB5 min

Automated Follow-Up:

Post-Meeting Actions

🔔Webhook: Meeting Notes Submitted
📋Parse Notes for Action Items
Create Tasks in Todoist
📧Send Summary Email to Attendees
📅Schedule Follow-Up Meeting (if needed)
💾Update CRM

Extract Action Items:

JavaScript
1const notes = $input.item.json.content;
2
3// Find action items (lines starting with - [ ] or TODO:)
4const actionItemRegex = /(?:- \[ \]|TODO:?)\s*(.+?)(?:\n|$)/gi;
5const matches = [...notes.matchAll(actionItemRegex)];
6
7const actionItems = matches.map((match, index) => {
8 const text = match[1].trim();
9
10 // Try to extract assignee
11 const assigneeMatch = text.match(/@(\w+)/);
12 const assignee = assigneeMatch ? assigneeMatch[1] : 'unassigned';
13
14 // Try to extract due date
15 const dueDateMatch = text.match(/due:?\s*(\d{1,2}\/\d{1,2})/i);
16 const dueDate = dueDateMatch ? dueDateMatch[1] : null;
17
18 return {
19 id: index + 1,
20 task: text.replace(/@\w+/, '').replace(/due:?\s*\d{1,2}\/\d{1,2}/i, '').trim(),
21 assignee,
22 dueDate
23 };
24});
25
26return { actionItems };

Send Summary Email:

JavaScript
1const meeting = $input.item.json;
2
3const emailBody = `
4Hi everyone,
5
6Thank you for attending ${meeting.title}. Here's a quick summary:
7
8## Key Decisions
9${meeting.decisions || 'None recorded'}
10
11## Action Items
12${meeting.actionItems.map(a =>
13 `- ${a.task} (${a.assignee})${a.dueDate ? ` - Due: ${a.dueDate}` : ''}`
14).join('\n')}
15
16## Next Steps
17${meeting.nextSteps || 'Follow up scheduled for next week'}
18
19Full meeting notes: ${meeting.notesLink}
20
21Best regards,
22[Auto-generated by n8n]
23`;
24
25return {
26 to: meeting.attendees.map(a => a.email).join(','),
27 subject: `Meeting Summary: ${meeting.title}`,
28 body: emailBody
29};

Checkpoint

Post-meeting follow-up extract action items bằng regex pattern nào?

7

💡 Workflow 5: Calendar Analytics

TB5 min

Weekly Meeting Report:

Weekly Calendar Analysis

Schedule: Friday 5 PM
📅Get This Week's Events
📊Calculate Statistics
📝Generate Report
📧Send to Self

Calculate Meeting Stats:

JavaScript
1const events = $input.all();
2
3let stats = {
4 totalMeetings: 0,
5 totalMinutes: 0,
6 byType: {},
7 byDay: {Mon: 0, Tue: 0, Wed: 0, Thu: 0, Fri: 0},
8 longestMeeting: null,
9 busiestDay: ''
10};
11
12for (const event of events) {
13 const e = event.json;
14
15 // Skip all-day events
16 if (!e.start.dateTime) continue;
17
18 stats.totalMeetings++;
19
20 // Calculate duration
21 const start = new Date(e.start.dateTime);
22 const end = new Date(e.end.dateTime);
23 const duration = (end - start) / (1000 * 60);
24 stats.totalMinutes += duration;
25
26 // Track longest meeting
27 if (!stats.longestMeeting || duration > stats.longestMeeting.duration) {
28 stats.longestMeeting = { title: e.summary, duration };
29 }
30
31 // By day
32 const day = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][start.getDay()];
33 stats.byDay[day] = (stats.byDay[day] || 0) + 1;
34
35 // By type (based on title keywords)
36 let type = 'Other';
37 if (e.summary.toLowerCase().includes('1:1')) type = '1:1';
38 else if (e.summary.toLowerCase().includes('standup')) type = 'Standup';
39 else if (e.summary.toLowerCase().includes('review')) type = 'Review';
40
41 stats.byType[type] = (stats.byType[type] || 0) + 1;
42}
43
44// Find busiest day
45stats.busiestDay = Object.entries(stats.byDay)
46 .sort((a, b) => b[1] - a[1])[0][0];
47
48stats.avgMeetingLength = Math.round(stats.totalMinutes / stats.totalMeetings);
49stats.hoursInMeetings = (stats.totalMinutes / 60).toFixed(1);
50
51return stats;

Generate Weekly Report:

JavaScript
1const stats = $input.item.json;
2
3const report = `
4# Weekly Calendar Report
5
6## Overview
7- **Total Meetings:** ${stats.totalMeetings}
8- **Hours in Meetings:** ${stats.hoursInMeetings}h
9- **Average Meeting Length:** ${stats.avgMeetingLength} min
10- **Busiest Day:** ${stats.busiestDay}
11
12## By Type
13${Object.entries(stats.byType).map(([type, count]) =>
14 `- ${type}: ${count}`
15).join('\n')}
16
17## By Day
18| Day | Meetings |
19|-----|----------|
20${Object.entries(stats.byDay).map(([day, count]) =>
21 `| ${day} | ${count} |`
22).join('\n')}
23
24## Longest Meeting
25 ${stats.longestMeeting.title} (${stats.longestMeeting.duration} min)
26
27*Generated automatically by n8n*
28`;
29
30return { report };

Checkpoint

Calendar analytics tính toán những metrics nào?

8

🌟 Workflow 6: Smart Scheduling

TB5 min

Find Optimal Meeting Time:

JavaScript
1// Find free slots for meeting
2const busySlots = $input.all().map(e => ({
3 start: new Date(e.json.start.dateTime),
4 end: new Date(e.json.end.dateTime)
5}));
6
7const workDayStart = 9; // 9 AM
8const workDayEnd = 18; // 6 PM
9const meetingDuration = 30; // 30 minutes
10
11const freeSlots = [];
12const today = new Date();
13today.setHours(workDayStart, 0, 0, 0);
14
15// Check next 5 business days
16for (let day = 0; day < 5; day++) {
17 const checkDate = new Date(today);
18 checkDate.setDate(checkDate.getDate() + day);
19
20 // Skip weekends
21 if (checkDate.getDay() === 0 || checkDate.getDay() === 6) continue;
22
23 // Check each 30-min slot
24 for (let hour = workDayStart; hour < workDayEnd; hour++) {
25 for (let min = 0; min < 60; min += 30) {
26 const slotStart = new Date(checkDate);
27 slotStart.setHours(hour, min, 0, 0);
28
29 const slotEnd = new Date(slotStart);
30 slotEnd.setMinutes(slotEnd.getMinutes() + meetingDuration);
31
32 // Check if slot conflicts with any busy time
33 const isConflict = busySlots.some(busy =>
34 (slotStart >= busy.start && slotStart < busy.end) ||
35 (slotEnd > busy.start && slotEnd <= busy.end)
36 );
37
38 if (!isConflict) {
39 freeSlots.push({
40 start: slotStart.toISOString(),
41 end: slotEnd.toISOString(),
42 display: slotStart.toLocaleString()
43 });
44 }
45 }
46 }
47}
48
49return { freeSlots: freeSlots.slice(0, 10) }; // Return top 10 options

Checkpoint

Smart scheduling kiểm tra những điều kiện gì khi tìm available slots?

9

📋 Best Practices

TB5 min
Calendar Automation Tips

Do:

  • ✅ Test reminders with your own events first
  • ✅ Respect time zones
  • ✅ Keep notifications concise
  • ✅ Allow opt-out from automated emails

Don't:

  • ❌ Send too many reminders (max 2-3)
  • ❌ Auto-create events without confirmation
  • ❌ Process declined events
  • ❌ Ignore private/sensitive events

Checkpoint

Tối đa bao nhiêu reminders nên gửi cho một meeting?

10

📝 Bài Tập Thực Hành

TB5 min
Calendar Challenge

Build your calendar system:

  1. Create multi-stage reminder workflow
  2. Build meeting prep automation
  3. Set up post-meeting follow-up
  4. Implement weekly calendar report
  5. Design smart scheduling assistant

Master your calendar! 📅

Checkpoint

Bạn đã hoàn thành những challenges nào trong bài tập?

11

🧠 Key Takeaways

TB5 min
Remember
  • 📅 Prep is key - Automate pre-meeting preparation
  • Smart reminders - Stage them appropriately
  • 📝 Capture everything - Automate note templates
  • 📊 Track time - Know where your time goes
  • 🔄 Close the loop - Automate follow-ups

Checkpoint

Tại sao prep automation quan trọng cho meetings?

🚀 Bài tiếp theo

Note-Taking Automation — Save content to Notion, Obsidian và organize knowledge automatically.