質問編集履歴

15

コードの修正

2024/04/30 10:00

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
@@ -13,7 +13,7 @@
13
13
  ### 該当のソースコード
14
14
 
15
15
  ```GAS
16
- function monitorMyCalendar(e) {
16
+ function monitorMyCalendar(e) { // 関数名も変えました
17
17
  if (e) {
18
18
  try {
19
19
  // 表示用の文字列
@@ -51,9 +51,10 @@
51
51
  // 追加・更新された予定を検出
52
52
  for (const event of events) {
53
53
  const eventUpdated = event.getLastUpdated();
54
+ const isNewEvent = eventUpdated > lastUpdated || event.getStartTime() > lastUpdated; // 新しいイベントまたは更新されたイベントかどうかを判定
54
55
  if (eventUpdated > twoWeeksLater) {
55
56
  break;
56
- } else if (eventUpdated > lastUpdated) {
57
+ } else if (isNewEvent) {
57
58
  twoWeeksMap.set(event.getId(), eventUpdated);
58
59
  // メール通知項目を生成
59
60
  const eventDetails = {
@@ -74,39 +75,43 @@
74
75
  }
75
76
 
76
77
  // 削除確認用の予定の控えをスプレッドシートから復元し、2週間分のみ抽出(シート名はカレンダーIDの最初の16文字)
77
- const SPREADSHEET_ID = "シートID";
78
- const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
78
+ const ss = SpreadsheetApp.openById("シートID");
79
79
  const sheet = ss.getSheetByName(e.calendarId.slice(0, 16)) ?? ss.insertSheet(e.calendarId.slice(0, 16));
80
80
  const savedEvents = sheet.getDataRange().getValues();
81
-
82
- if (currentTime.getFullYear() - lastUpdated.getFullYear() <= 1) {
83
- const delEventObj = Calendar.Events.list(e.calendarId, { axResults: 2500, orderBy: "updated", updatedMin: lastUpdated.toISOString() }).items.reduce((o, { id, status }) => {
81
+ const twoWeeksSavedEvents = savedEvents.filter(data => data[5] >= today && data[5] <= twoWeeksLater);
82
+
83
+ // 削除されたイベントIDのリストを格納するための配列
84
+ const deletedEventIds = [];
85
+
86
+ // 2週間分の保存されたイベントを反復処理
84
- if (status == "cancelled") {
87
+ for (const data of twoWeeksSavedEvents) {
88
+ if (!twoWeeksMap.has(data[0])) {
89
+ // 削除されたイベントIDを検出し、deletedEventIds に追加
85
- o[`${id}@google.com`] = true;
90
+ deletedEventIds.push(data[0]);
86
- }
91
+ }
87
- return o;
88
- }, {});
92
+ }
89
-
90
- const deletedEvents = savedEvents.filter(r => delEventObj[r[0]]);
93
+
91
- // 削除されたイベントの情報をメール通知するため処理
94
+ // deletedEventIds を元に削除されたイベントの詳細取得し、メール通知の準備を行う
92
- if (deletedEvents.length > 0) {
93
- for (const data of deletedEvents) {
95
+ for (const eventId of deletedEventIds) {
94
- // 削除されたことを示すラ追加してメール通知内容を作成
96
+ // 削除されたントの詳細取得
97
+ const deletedEventData = savedEvents.find(data => data[0] === eventId);
98
+
99
+ // 削除されたイベントの詳細が見つかった場合、メール通知項目を生成して mailBodies に追加
100
+ if (deletedEventData) {
95
- const eventDetails = {
101
+ const eventDetails = {
96
- title: `[削除済み] ${data[3] || 'タイトル' + isNotExist}`, // タイトルにラベルを追加
102
+ title: deletedEventData[3] || 'タイトル' + isNotExist,
97
- startTime: data[5] ? formatDate_(data[5]) : '開始日時' + isNotExist,
103
+ startTime: deletedEventData[5] ? formatDate_(deletedEventData[5]) : '開始日時' + isNotExist,
98
- endTime: data[6] ? formatDate_(data[6]) : '終了日時' + isNotExist,
104
+ endTime: deletedEventData[6] ? formatDate_(deletedEventData[6]) : '終了日時' + isNotExist,
99
- updateTime: formatDate_(calendar.getEventById(data[0]).getLastUpdated()),
105
+ updateTime: formatDate_(calendar.getEventById(eventId).getLastUpdated()),
100
- description: data[8] || '詳細' + isNotExist,
106
+ description: deletedEventData[8] || '詳細' + isNotExist,
101
- location: data[7] || '場所' + isNotExist,
107
+ location: deletedEventData[7] || '場所' + isNotExist,
102
- url: '', // 削除されたイベントの場合、URL は空にする
108
+ url: '',
103
- calendarId: e.calendarId,
109
+ calendarId: e.calendarId,
104
- calendarName: calendar.getName(),
110
+ calendarName: calendar.getName(),
105
- };
111
+ };
106
- // メール本文を蓄積する
112
+ // メール本文を蓄積する
107
- mailBodies.push(eventDetails);
113
+ mailBodies.push(eventDetails);
108
- noticeCount++; // 通知されるイベントの数を増やす
114
+ noticeCount++; // 通知されるイベントの数を増やす
109
- }
110
115
  }
111
116
  }
112
117
 
@@ -122,19 +127,18 @@
122
127
 
123
128
  // 6ヶ月分の予定の控えを更新(保存)
124
129
  if (events.length > 0) {
125
- // スプレッドシートに書き込むデータのフォーマットを修正
126
130
  const values = events.map(event => [
127
- event.getId(), // イベントID[0]
131
+ event.getId(), // イベントID[0]
128
- calendar.getName(), // カレンダー名[1]
132
+ calendar.getName(), // カレンダー名[1]
129
- e.calendarId, // カレンダーID[2]
133
+ e.calendarId, // カレンダーID[2]
130
- event.getTitle(), // タイトル[3]
134
+ event.getTitle(), // タイトル[3]
131
- formatDate_(event.getLastUpdated()), // 最終更新日時[4]
135
+ event.getLastUpdated(), // 最終更新日時[4]
132
- formatDate_(event.getStartTime()), // 開始日時[5]
136
+ event.getStartTime(), // 開始日時[5]
133
- formatDate_(event.getEndTime()), // 終了日時[6]
137
+ event.getEndTime(), // 終了日時[6]
134
- event.getLocation(), // 場所[7]
138
+ event.getLocation(), // 場所[7]
135
- event.getDescription(), // 詳細[8]
139
+ event.getDescription(), // 詳細[8]
136
140
  ]);
137
- // スプレッドシートの更新
141
+ sheet.clearContents();
138
142
  sheet.getRange(1, 1, values.length, values[0].length).setValues(values);
139
143
  }
140
144
 
@@ -160,28 +164,62 @@
160
164
  }
161
165
 
162
166
  // 通知を送信
163
- function sendEmailNotification_(mailBodies, date) {
167
+ function sendEmailNotification_(mailBodies, date, properties, lastUpdated, isNewEvent, isDeletedEvent) {
164
168
  try {
169
+ const lastNotificationDate = new Date(properties.getProperty('lastNotificationDate'));
165
- //const recipientEmail = '';
170
+ const currentTime = new Date();
171
+
172
+ // 前回の通知日時と現在の日時を比較し、新しいイベントまたは削除されたイベントがある場合にメール通知を送信する
173
+ if (lastNotificationDate < lastUpdated && currentTime >= lastUpdated && (isNewEvent || isDeletedEvent)) {
166
- const recipientEmail = 'test@gmail.com'; // 送信先のメールアドレスを設定してください
174
+ const recipientEmail = 'test@gmail.com'; // 送信先のメールアドレスを設定してください
175
+
176
+ // 新しいイベントの情報を含む通知メール
177
+ if (isNewEvent) {
167
- const subject = "Googleカレンダーイベントが更新されました";
178
+ const subject = "Googleカレンダーに新しいイベントが追加されました";
168
- let body = '前回の通知(' + date.noticedDate + ')以降、Googleカレンダーイベントが更新されました。\n' +
179
+ let body = '前回の通知(' + date.noticedDate + ')以降、Googleカレンダーに新しいイベントが追加されました。\n' +
169
- '今回の通知(' + date.currentDate + ')対象のカレンダー名: ' + mailBodies[0].calendarName + '\n\n';
180
+ '今回の通知(' + date.currentDate + ')対象のカレンダー名: ' + mailBodies[0].calendarName + '\n\n';
181
+
170
- for (const item of mailBodies) {
182
+ for (const item of mailBodies) {
171
- body +=
183
+ body +=
172
- '作成・更新日時: ' + item.updateTime + '\n' +
184
+ '作成日時: ' + item.updateTime + '\n' +
173
- 'タイトル: ' + item.title + '\n' +
185
+ 'タイトル: ' + item.title + '\n' +
174
- '開始日時: ' + item.startTime + '\n' +
186
+ '開始日時: ' + item.startTime + '\n' +
175
- '終了日時: ' + item.endTime + '\n' +
187
+ '終了日時: ' + item.endTime + '\n' +
176
- '場所: ' + item.location + '\n' +
188
+ '場所: ' + item.location + '\n' +
177
- '詳細: ' + item.description + '\n' +
189
+ '詳細: ' + item.description + '\n' +
178
- 'URL: ' + item.url + '\n\n';
190
+ 'URL: ' + item.url + '\n\n';
191
+ }
192
+ MailApp.sendEmail(recipientEmail, subject, body);
193
+ Logger.log('新しいイベントの通知メールが送信されました: ' + body);
194
+ }
195
+
196
+ // 削除されたイベントの情報を含む通知メール
197
+ if (isDeletedEvent) {
198
+ const subject = "Googleカレンダーのイベントが削除されました";
199
+ let body = '前回の通知(' + date.noticedDate + ')以降、Googleカレンダーからイベントが削除されました。\n' +
200
+ '今回の通知(' + date.currentDate + ')対象のカレンダー名: ' + mailBodies[0].calendarName + '\n\n';
201
+
202
+ for (const item of mailBodies) {
203
+ body +=
204
+ '削除日時: ' + item.updateTime + '\n' +
205
+ 'タイトル: ' + item.title + '\n' +
206
+ '開始日時: ' + item.startTime + '\n' +
207
+ '終了日時: ' + item.endTime + '\n' +
208
+ '場所: ' + item.location + '\n' +
209
+ '詳細: ' + item.description + '\n\n';
210
+ }
211
+ MailApp.sendEmail(recipientEmail, subject, body);
212
+ Logger.log('削除されたイベントの通知メールが送信されました: ' + body);
213
+ }
214
+
215
+ // 最後の通知時刻を保存
216
+ properties.setProperty('lastNotificationDate', currentTime.toISOString());
217
+ } else {
218
+ Logger.log('新しいイベントまたは削除されたイベントがないか、前回の通知以降に新しいイベントまたは削除されたイベントがありません。メールを送信しませんでした。');
179
219
  }
180
- MailApp.sendEmail(recipientEmail, subject, body);
181
- Logger.log('メールが送信されました: ' + body);
182
220
  } catch (error) {
183
221
  // メール送信中にエラーが発生した場合、エラーメッセージをログに出力する
184
- Logger.log('メールの送信中にエラーが発生しました: ' + error);
222
+ Logger.log('通知メールの送信中にエラーが発生しました: ' + error);
185
223
  }
186
224
  }
187
225
 
@@ -197,12 +235,6 @@
197
235
  ##### 上記の詳細・結果
198
236
  まずはトリガーの設定は以下に設定しています。
199
237
 
200
- ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2024-04-11/8e002cd6-8589-4ead-a31f-513e3a189a14.png)
201
-
202
- monitorAllCalendars関数でグーグルイベント更新があったら、その内容を以下のように行で任意のスプレッドシートに記載します。
203
-
204
- ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2024-04-11/a5f399b8-200f-4aa7-9882-ebf8ed4e4e50.png)
205
-
206
238
  今回はいくつか同じ内容が来てしまうのでその場合は
207
239
  removeDuplicatesFromSheet関数で削除を行っていますが
208
240
  一度のメールがこのコードですと「0通」になってしまいます。
@@ -210,25 +242,7 @@
210
242
  ```ここに言語を入力
211
243
  if (!lastEmailSent || (currentTime - lastEmailSent) >= emailInterval) {
212
244
  ```
213
-
214
245
  上記の条件分岐が当てはまっていない気がします。
215
-
216
246
  すみませんが皆様からのご教示のほどよろしくお願いいたします。
217
247
 
218
-
219
- ### 補足
220
- GASコード内の以下の部分は任意のメールアドレスを記入されています。
221
- もし検証される場合はお持ちのメールアドレスをご記入ください。
222
-
223
- ```ここに言語を入力
224
- var spreadsheetId = 'スプレッドシートのID';
225
- var sheetName = 'カレンダー変更通知の管理';
226
- var recipientEmail = '任意のメールアドレス'; // 送信先のメールアドレス
227
- ```
228
-
229
- ### 追加事項
230
- 以下のキャプチャは、イベントの設定変更を行うとき、場所を選択(会議室を選択)項目があります。
231
-
232
248
  ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2024-04-15/1793d04e-6518-49fc-a22b-de6e73bd1561.png)
233
-
234
-

14

ソースコードの更新

2024/04/30 09:29

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
@@ -7,21 +7,21 @@
7
7
  以下の点で困っています。
8
8
 
9
9
  **・なぜかメール通知がなされない**
10
- **・削除の場合送信なれない**
10
+ **・削除の場合送信ができない**
11
11
 
12
12
 
13
13
  ### 該当のソースコード
14
14
 
15
15
  ```GAS
16
- function monitorAllCalendars(e) {
16
+ function monitorMyCalendar(e) {
17
17
  if (e) {
18
18
  try {
19
19
  // 表示用の文字列
20
20
  const isNotExist = 'が設定されていません';
21
21
 
22
- // 同じスクリプトが起動したときは後者をキャンセル
22
+ // 過去にイベントオブジェクトが複数発生(スクリプトが複数起動したへの対応
23
23
  const lock = LockService.getScriptLock();
24
- lock.waitLock(100); // 既に実行中ならエラーとするロックを取得(0.1秒だけ待機)
24
+ lock.waitLock(0);
25
25
 
26
26
  // プロパティサービスから前回実行日時を取得
27
27
  const properties = PropertiesService.getScriptProperties();
@@ -32,80 +32,111 @@
32
32
  const currentTime = new Date();
33
33
  const currentDate = formatDate_(currentTime);
34
34
 
35
- // 実行日の日付と2週間後の日付を生成
35
+ // 実行日と2週間後及び6ヶ月後の日付を生成
36
36
  const today = new Date();
37
- today.setHours(0, 0, 0, 0);
37
+ today.setHours(0, 0, 0, 0); // 時刻をクリア
38
38
  const twoWeeksLater = new Date(today);
39
- twoWeeksLater.setDate(today.getDate() + 14); // 2週間後の日付を取得
39
+ twoWeeksLater.setDate(twoWeeksLater.getDate() + 14); // 2週間後の日付
40
+ const sixMonthsLater = new Date(today);
40
- twoWeeksLater.setHours(0, 0, 0, 0); // 時刻をリセットして日付のみにする
41
+ sixMonthsLater.setMonth(today.getMonth() + 6); // 6ヶ月後の日付
41
-
42
+
42
- // 更新されたカレンダーを処理
43
+ // 更新されたカレンダーを6ヶ月後まで取得
43
44
  const calendar = CalendarApp.getCalendarById(e.calendarId);
45
+ const events = calendar.getEvents(today, sixMonthsLater); // 6ヶ月後までの予定を取得
46
+
44
- let notifiedCount = 0; // 通知されるイベントの数をカウントする変数
47
+ let noticeCount = 0; // 通知されるイベントの数をカウントする変数
45
- const mailBodies = []
48
+ const mailBodies = []; // 通知内容を蓄積する配列
49
+ const twoWeeksMap = new Map();
50
+
46
- // 実行日から2週間後までの予定を対象に処理
51
+ // 追加・更新された予定を検出
47
- const events = calendar.getEvents(today, twoWeeksLater);
48
- if (events && events.length > 0) {
49
- for (const event of events) {
52
+ for (const event of events) {
50
- const eventId = event.getId();
53
+ const eventUpdated = event.getLastUpdated();
51
- // 通知すべきイベントが更新されたかどうかを確認
54
+ if (eventUpdated > twoWeeksLater) {
55
+ break;
52
- if (event.getLastUpdated() > lastUpdated) {
56
+ } else if (eventUpdated > lastUpdated) {
57
+ twoWeeksMap.set(event.getId(), eventUpdated);
58
+ // メール通知項目を生成
53
- let title = event.getTitle();
59
+ const eventDetails = {
54
- if (!title) {
55
- title = 'タイトル' + isNotExist;
60
+ title: event.getTitle() || 'タイトル' + isNotExist,
61
+ startTime: event.getStartTime() ? formatDate_(event.getStartTime()) : '開始日時' + isNotExist,
62
+ endTime: event.getEndTime() ? formatDate_(event.getEndTime()) : '終了日時' + isNotExist,
63
+ updateTime: formatDate_(eventUpdated),
64
+ description: event.getDescription() || '詳細' + isNotExist,
65
+ location: event.getLocation() || '場所' + isNotExist,
66
+ url: 'https://www.google.com/calendar/event?eid=' + Utilities.base64Encode(event.getId().split('@')[0] + ' ' + e.calendarId), // URL を直接指定
67
+ calendarId: e.calendarId,
68
+ calendarName: calendar.getName(),
69
+ };
70
+ // メール本文を蓄積する
71
+ mailBodies.push(eventDetails);
56
- Logger.log('イベントのタイトルがありませんでした。');
72
+ noticeCount++; // 通知されるイベントの数を増やす
57
- }
73
+ }
58
-
74
+ }
75
+
59
- // イベント開始日時と終了日時適切なフォマッに変換
76
+ // 削除確認用予定の控えスプレッドシートから復元し、2週間分のみ抽出(シート名はカレンダーIDの最初の16文字)
77
+ const SPREADSHEET_ID = "シートID";
78
+ const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
60
- const startTime = event.getStartTime() ? formatDate_(event.getStartTime()) : '開始日時' + isNotExist;
79
+ const sheet = ss.getSheetByName(e.calendarId.slice(0, 16)) ?? ss.insertSheet(e.calendarId.slice(0, 16));
80
+ const savedEvents = sheet.getDataRange().getValues();
81
+
82
+ if (currentTime.getFullYear() - lastUpdated.getFullYear() <= 1) {
83
+ const delEventObj = Calendar.Events.list(e.calendarId, { axResults: 2500, orderBy: "updated", updatedMin: lastUpdated.toISOString() }).items.reduce((o, { id, status }) => {
84
+ if (status == "cancelled") {
85
+ o[`${id}@google.com`] = true;
86
+ }
87
+ return o;
88
+ }, {});
89
+
61
- const endTime = event.getEndTime() ? formatDate_(event.getEndTime()) : '終了日時' + isNotExist;
90
+ const deletedEvents = savedEvents.filter(r => delEventObj[r[0]]);
62
- const updateTime = event.getLastUpdated() ? formatDate_(event.getLastUpdated()) : '作成・更新日時' + isNotExist;
63
-
64
- // 通知されるべきイベントの詳細ログに出力
91
+ // 削除されイベントの情報メール通知するための処理
65
- Logger.log('通知されるイベント: ' + title + ' (' + startTime + ' - ' + endTime + '<<' + updateTime + ')');
66
-
67
- const description = event.getDescription() || '詳細' + isNotExist;
68
- const location = event.getLocation() || '場所' + isNotExist;
92
+ if (deletedEvents.length > 0) {
69
-
93
+ for (const data of deletedEvents) {
94
+ // 削除されたことを示すラベルを追加してメール通知内容を作成
70
95
  const eventDetails = {
71
- title: title,
96
+ title: `[削除済み] ${data[3] || 'タイトル' + isNotExist}`, // タイトルにラベルを追加
72
- startTime: startTime,
97
+ startTime: data[5] ? formatDate_(data[5]) : '開始日時' + isNotExist,
73
- endTime: endTime,
98
+ endTime: data[6] ? formatDate_(data[6]) : '終了日時' + isNotExist,
74
- updateTime: updateTime,
99
+ updateTime: formatDate_(calendar.getEventById(data[0]).getLastUpdated()),
75
- description: description,
100
+ description: data[8] || '詳細' + isNotExist,
76
- location: location,
101
+ location: data[7] || '場所' + isNotExist,
77
- url: 'https://www.google.com/calendar/event?eid=' + Utilities.base64Encode(eventId.split('@')[0] + ' ' + e.calendarId), // URL を直接指定
102
+ url: '', // 削除されたイベントの場合、URL は空にする
78
103
  calendarId: e.calendarId,
79
104
  calendarName: calendar.getName(),
80
105
  };
81
-
82
- // メールを送信する
106
+ // メール本文蓄積する
83
107
  mailBodies.push(eventDetails);
84
- notifiedCount++; // 通知されるイベントの数を増やす
108
+ noticeCount++; // 通知されるイベントの数を増やす
85
109
  }
86
110
  }
87
111
  }
112
+
88
113
  if (mailBodies.length > 0) {
114
+ // 開始日時順に並び替え
115
+ mailBodies.sort((a, b) => new Date(a.startTime) - new Date(b.startTime));
116
+ // メールを送信
89
- sendEmailNotification_(mailBodies, { noticedDate, currentDate });
117
+ sendEmailNotification_(mailBodies, { noticedDate, currentDate }, properties, lastUpdated);
90
118
  // 最後の通知時刻を保存
91
119
  properties.setProperty('lastUpdated', currentTime.toISOString());
92
120
  }
93
- // 通知されるイベントの数をログに記録
94
- Logger.log('通知されるイベントの数: ' + notifiedCount);
121
+ Logger.log('通知されるイベントの数: ' + noticeCount);
95
-
96
-
122
+
97
- // 6後まで取得
123
+ // 6分の予定の控えを更新(保存)
98
- const sixMonthsLater = new Date(today);
99
- sixMonthsLater.setMonth(today.getMonth() + 6);
100
- const calendars = CalendarApp.getAllCalendars();
101
- let allEvents = [];
102
- calendars.forEach(calendar => {
124
+ if (events.length > 0) {
103
- const events = getEventsWithinPeriod(calendar, today, sixMonthsLater, lastUpdated);
125
+ // スプレッドシートに書き込むデータのフォーマットを修正
104
- allEvents = allEvents.concat(events);
126
+ const values = events.map(event => [
127
+ event.getId(), // イベントID[0]
128
+ calendar.getName(), // カレンダー名[1]
129
+ e.calendarId, // カレンダーID[2]
130
+ event.getTitle(), // タイトル[3]
131
+ formatDate_(event.getLastUpdated()), // 最終更新日時[4]
132
+ formatDate_(event.getStartTime()), // 開始日時[5]
133
+ formatDate_(event.getEndTime()), // 終了日時[6]
134
+ event.getLocation(), // 場所[7]
135
+ event.getDescription(), // 詳細[8]
105
- });
136
+ ]);
106
- Logger.log(allEvents);
137
+ // スプレッドシートの更新
107
-
138
+ sheet.getRange(1, 1, values.length, values[0].length).setValues(values);
108
-
139
+ }
109
140
 
110
141
  // スクリプトのロックを解放
111
142
  Utilities.sleep(300);
@@ -113,9 +144,9 @@
113
144
 
114
145
  } catch (error) {
115
146
  if (error.toString().includes('Lock timeout')) {
116
- Logger.log('実行中のスクリプトが重複しているので処理を中断しました');
147
+ Logger.log('実行中のスクリプトが重複しているので処理を中断しました');
117
148
  } else {
118
- Logger.log('monitorAllCalendarsのエラーが発生しました: ' + error);
149
+ Logger.log('予定確認中に次のエラーが発生しました: ' + error);
119
150
  }
120
151
  }
121
152
  } else {
@@ -123,32 +154,31 @@
123
154
  }
124
155
  }
125
156
 
126
- // 日付を指定された形式に整形
157
+ // 日付を指定された形式に整形(日付が文字列の場合に対応)
127
158
  function formatDate_(date) {
128
- return Utilities.formatDate(date, 'JST', 'yyyy/MM/dd HH:mm');
159
+ return Utilities.formatDate(new Date(date), 'JST', 'yyyy/MM/dd HH:mm'); // 日本時間で表示
129
160
  }
130
161
 
131
162
  // 通知を送信
132
163
  function sendEmailNotification_(mailBodies, date) {
133
164
  try {
165
+ //const recipientEmail = '';
134
- const recipientEmail = "kawata@actcube.jp"; // 送信先のメールアドレスを設定してください
166
+ const recipientEmail = 'test@gmail.com'; // 送信先のメールアドレスを設定してください
135
- const subject = "Googleカレンダーのイベント通知";
167
+ const subject = "Googleカレンダーのイベントが更新されました";
136
- let body = '';
137
- //let body = '前回の通知(' + date.noticedDate + ')以降、Googleカレンダーのイベント通知を行いました。\n' +
168
+ let body = '前回の通知(' + date.noticedDate + ')以降、Googleカレンダーのイベントが更新されました。\n' +
138
169
  '今回の通知(' + date.currentDate + ')対象のカレンダー名: ' + mailBodies[0].calendarName + '\n\n';
139
- for (const eventDetails of mailBodies) {
170
+ for (const item of mailBodies) {
140
171
  body +=
141
- 'タイトル : ' + eventDetails.title + '\n' +
142
- '作成・更新日時 : ' + eventDetails.updateTime + '\n' +
172
+ '作成・更新日時: ' + item.updateTime + '\n' +
173
+ 'タイトル: ' + item.title + '\n' +
143
- '開始日時 : ' + eventDetails.startTime + '\n' +
174
+ '開始日時: ' + item.startTime + '\n' +
144
- '終了日時 : ' + eventDetails.endTime + '\n' +
175
+ '終了日時: ' + item.endTime + '\n' +
176
+ '場所: ' + item.location + '\n' +
145
- '詳細 : ' + eventDetails.description + '\n' +
177
+ '詳細: ' + item.description + '\n' +
146
- '場所 : ' + eventDetails.location + '\n' +
147
- 'URL : ' + eventDetails.url + '\n\n';
178
+ 'URL: ' + item.url + '\n\n';
148
179
  }
149
180
  MailApp.sendEmail(recipientEmail, subject, body);
150
181
  Logger.log('メールが送信されました: ' + body);
151
-
152
182
  } catch (error) {
153
183
  // メール送信中にエラーが発生した場合、エラーメッセージをログに出力する
154
184
  Logger.log('メールの送信中にエラーが発生しました: ' + error);
@@ -156,26 +186,6 @@
156
186
  }
157
187
 
158
188
 
159
- function getEventsWithinPeriod(calendar, startDate, endDate, lastUpdated) {
160
- let events = [];
161
- let pageToken;
162
- do {
163
- const options = {
164
- timeMin: startDate.toISOString(),
165
- timeMax: endDate.toISOString(),
166
- maxResults: 2500,
167
- singleEvents: true,
168
- orderBy: 'startTime',
169
- pageToken: pageToken
170
- };
171
- const response = Calendar.Events.list(calendar.getId(), options);
172
- const items = response.items.filter(item => new Date(item.updated) > lastUpdated);
173
- events = events.concat(items);
174
- pageToken = response.nextPageToken;
175
- } while (pageToken);
176
- return events;
177
- }
178
-
179
189
  ```
180
190
 
181
191
  ### 試したこと・調べたこと

13

コード最新修正

2024/04/17 04:48

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
@@ -14,228 +14,166 @@
14
14
 
15
15
  ```GAS
16
16
  function monitorAllCalendars(e) {
17
+ if (e) {
17
- try {
18
+ try {
19
+ // 表示用の文字列
20
+ const isNotExist = 'が設定されていません';
21
+
22
+ // 同じスクリプトが起動したときは後者をキャンセル
18
- var calendarIds = getAllCalendarIds();
23
+ const lock = LockService.getScriptLock();
24
+ lock.waitLock(100); // 既に実行中ならエラーとするロックを取得(0.1秒だけ待機)
25
+
26
+ // プロパティサービスから前回実行日時を取得
27
+ const properties = PropertiesService.getScriptProperties();
19
- var lastUpdated = PropertiesService.getScriptProperties().getProperty('lastUpdated');
28
+ const lastUpdated = new Date(properties.getProperty('lastUpdated'));
29
+ const noticedDate = formatDate_(lastUpdated);
30
+
31
+ // スクリプトの実行日時を取得
20
- var currentTime = new Date();
32
+ const currentTime = new Date();
21
- var notifiedEvents = getNotifiedEvents() || [];
33
+ const currentDate = formatDate_(currentTime);
34
+
22
-
35
+ // 実行日の日付と2週間後の日付を生成
23
- var today = new Date();
36
+ const today = new Date();
24
- today.setHours(0, 0, 0, 0);
37
+ today.setHours(0, 0, 0, 0);
25
-
26
- var twoWeeksLater = new Date(today);
38
+ const twoWeeksLater = new Date(today);
27
- twoWeeksLater.setDate(today.getDate() + 14); // 2週間後の日付を取得
39
+ twoWeeksLater.setDate(today.getDate() + 14); // 2週間後の日付を取得
28
- twoWeeksLater.setHours(0, 0, 0, 0); // 時刻をリセットして日付のみにする
40
+ twoWeeksLater.setHours(0, 0, 0, 0); // 時刻をリセットして日付のみにする
41
+
29
-
42
+ // 更新されたカレンダーを処理
43
+ const calendar = CalendarApp.getCalendarById(e.calendarId);
30
- var notifiedCount = 0; // 通知されるイベントの数をカウントする変数
44
+ let notifiedCount = 0; // 通知されるイベントの数をカウントする変数
31
-
45
+ const mailBodies = []
32
- // スプレッドシートID指定
46
+ // 実行日から2週間後まで予定対象に処理
33
- var spreadsheetId = 'スプレッドシートのID';
34
-
35
- // シート名を指定
36
- var sheetName = 'カレンダー変更通知の管理';
37
- // シートの範囲を指定
38
- var range = 'A2:F'; // URLのために範囲を追加
39
-
40
- // スプレッドシートにヘッダーを追加
41
- var headers = ['タイトル', '開始日時', '終了日時', '詳細', '場所', 'URL']; // URLのヘッダーを追加
42
- var sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
43
-
44
- // シートが存在しない場合は新規作成する
45
- if (!sheet) {
46
- sheet = SpreadsheetApp.openById(spreadsheetId).insertSheet(sheetName);
47
- sheet.getRange('A1:F1').setValues([headers]); // URLのために範囲を変更
48
- }
49
-
50
- for (var i = 0; i < calendarIds.length; i++) {
51
- var calendarId = calendarIds[i];
52
- var startDateTime = today;
53
- var endDateTime = twoWeeksLater;
54
-
55
- var events = CalendarApp.getCalendarById(calendarId).getEvents(startDateTime, endDateTime);
47
+ const events = calendar.getEvents(today, twoWeeksLater);
56
-
57
48
  if (events && events.length > 0) {
58
- for (var j = 0; j < events.length; j++) {
59
- var event = events[j];
49
+ for (const event of events) {
60
- var eventId = event.getId();
50
+ const eventId = event.getId();
61
- var lastUpdatedTime = event.getLastUpdated();
62
-
63
51
  // 通知すべきイベントが更新されたかどうかを確認
64
- if (lastUpdatedTime > new Date(lastUpdated)) {
52
+ if (event.getLastUpdated() > lastUpdated) {
65
- var title = event.getTitle();
53
+ let title = event.getTitle();
66
54
  if (!title) {
67
- title = 'タイトルが設定されていません';
55
+ title = 'タイトル' + isNotExist;
68
56
  Logger.log('イベントのタイトルがありませんでした。');
69
57
  }
70
58
 
71
59
  // イベントの開始日時と終了日時を適切なフォーマットに変換
72
- var startTime = event.getStartTime() ? formatDate(event.getStartTime()) : '開始日時が設定されていません';
60
+ const startTime = event.getStartTime() ? formatDate_(event.getStartTime()) : '開始日時' + isNotExist;
73
- var endTime = event.getEndTime() ? formatDate(event.getEndTime()) : '終了日時が設定されていません';
61
+ const endTime = event.getEndTime() ? formatDate_(event.getEndTime()) : '終了日時' + isNotExist;
74
-
62
+ const updateTime = event.getLastUpdated() ? formatDate_(event.getLastUpdated()) : '作成・更新日時' + isNotExist;
63
+
75
- // イベントの詳細と場所取得
64
+ // 通知されるべきイベントの詳細をログに出力
65
+ Logger.log('通知されるイベント: ' + title + ' (' + startTime + ' - ' + endTime + '<<' + updateTime + ')');
66
+
76
- var description = event.getDescription() || '詳細が設定されていません';
67
+ const description = event.getDescription() || '詳細' + isNotExist;
77
- var location = event.getLocation() || '場所が設定されていません';
68
+ const location = event.getLocation() || '場所' + isNotExist;
69
+
78
-
70
+ const eventDetails = {
71
+ title: title,
72
+ startTime: startTime,
73
+ endTime: endTime,
74
+ updateTime: updateTime,
75
+ description: description,
76
+ location: location,
77
+ url: 'https://www.google.com/calendar/event?eid=' + Utilities.base64Encode(eventId.split('@')[0] + ' ' + e.calendarId), // URL を直接指定
78
+ calendarId: e.calendarId,
79
+ calendarName: calendar.getName(),
80
+ };
81
+
79
- // イベントのURL取得
82
+ // メール送信する
80
- var url = event.getOriginalCalendarId(); // 例としてイベントのカレンダーIDを取得
81
-
82
- // スプレッドシートにイベント情報を追加
83
- var rowData = [title, startTime, endTime, description, location, 'https://calendar.google.com/calendar/render?action=VIEW&eid=' + url]; // URLを追加
84
- sheet.appendRow(rowData);
85
-
86
- // 通知されたイベントを記録
87
- notifiedEvents.push(eventId);
83
+ mailBodies.push(eventDetails);
88
-
89
- // 通知されイベントの数を増やす
84
+ notifiedCount++; // 通知されイベントの数を増やす
90
- notifiedCount++;
91
-
92
- // 通知されたイベントを記録
93
- Logger.log('イベントがスプレッドシートに追加されました: ' + title);
94
85
  }
95
86
  }
96
87
  }
97
- }
98
-
99
- // 通知されるイベントの数をログに記録
88
+ if (mailBodies.length > 0) {
100
- Logger.log('スプレッドシートに追加されたイベントの数: ' + notifiedCount);
89
+ sendEmailNotification_(mailBodies, { noticedDate, currentDate });
101
-
102
- // 通知されたイベントと最後の通知時を保存
90
+ // 最後の通知時を保存
103
- PropertiesService.getScriptProperties().setProperty('notifiedEvents', notifiedEvents.join(','));
104
- PropertiesService.getScriptProperties().setProperty('lastUpdated', currentTime.toISOString());
91
+ properties.setProperty('lastUpdated', currentTime.toISOString());
105
-
106
- } catch (error) {
107
- Logger.log('monitorAllCalendarsのエラーが発生しました: ' + error);
108
- }
109
- }
110
-
111
- // 日付を指定された形式に整形する関数
112
- function formatDate(date) {
113
- var year = date.getFullYear();
114
- var month = ('0' + (date.getMonth() + 1)).slice(-2);
115
- var day = ('0' + date.getDate()).slice(-2);
116
- var hours = ('0' + date.getHours()).slice(-2);
117
- var minutes = ('0' + date.getMinutes()).slice(-2);
118
- return year + '/' + month + '/' + day + ' ' + hours + ':' + minutes;
119
- }
120
-
121
- // 通知されたイベントを取得するための関数
122
- function getNotifiedEvents() {
123
- var notifiedEvents = PropertiesService.getScriptProperties().getProperty('notifiedEvents');
124
- return notifiedEvents ? notifiedEvents.split(',') : [];
125
- }
126
-
127
- // カレンダーIDのリストを取得するための関数
128
- function getAllCalendarIds() {
129
- var calendars = CalendarApp.getAllCalendars();
130
- var calendarIds = [];
131
- for (var i = 0; i < calendars.length; i++) {
132
- var calendar = calendars[i];
133
- calendarIds.push(calendar.getId());
134
- }
135
- return calendarIds;
136
- }
137
-
138
- // 任意のスプレッドシートに更新情報を追加して後、任意のメールアドレスに通知
139
- function removeDuplicatesFromSheet() {
140
- var spreadsheetId = 'スプレッドシートのID';
141
- var sheetName = 'カレンダー変更通知の管理';
142
- var range = 'A2:F'; // A2からの範囲を指定
143
- var recipientEmail = '任意のメールアドレス'; // 送信先のメールアドレス
144
-
145
- var sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
146
- //var dataRange = sheet.getRange(range);
147
- var dataRange = sheet.getRange(range + sheet.getLastRow()); //データがないシートの全ての行を確認する必要はない
148
- var values = dataRange.getValues();
149
- var newData = [];
150
- var uniqueEntries = {};
151
-
152
- // 重複を除去し、一意のエントリのみを残す
153
- values.forEach(function(row) {
154
- var key = row.join('|');
155
- if (!uniqueEntries[key]) {
156
- newData.push(row);
157
- uniqueEntries[key] = true;
158
- }
159
- });
160
-
161
- // 削除されたデータを保存
162
- var deletedData = [];
163
- if (newData.length < values.length) {
164
- values.forEach(function(row) {
165
- var key = row.join('|');
166
- if (!uniqueEntries[key]) {
167
- deletedData.push(row);
168
92
  }
169
- });
170
- }
171
-
172
- // 新しいデータで既存の範囲を上書きする
173
- sheet.getRange(range).clearContent(); // 指定された範囲をクリア
174
- if (newData.length > 0) {
175
- var newRange = sheet.getRange(2, 1, newData.length, newData[0].length);
176
- newRange.setValues(newData);
177
- }
178
-
179
- // 更新されイベントの抽出
93
+ // 通知されイベントのログに記録
180
- var updatedEvents = newData.filter(function(row) {
181
- return row[5] !== ''; // URLが空でない場合、更新されイベントとみなす
94
+ Logger.log('通知されイベントの数: ' + notifiedCount);
182
- });
95
+
183
-
96
+
184
- // のメール送信時刻を取得
97
+ // 6カ月まで取得
185
- var lastEmailSent = PropertiesService.getScriptProperties().getProperty('lastEmailSent');
186
- var currentTime = new Date().getTime(); // 現在時刻のミリ秒単位の表現を取得
187
-
188
- // メールが送信されてから一定時間以上経過しているか確認
98
+ const sixMonthsLater = new Date(today);
189
- var emailInterval = 60000; // メール送信の間隔(ミリ秒)
190
- if (!lastEmailSent || (currentTime - lastEmailSent) >= emailInterval) {
191
- // 更新されたイベントがあればメール送信する
192
- if (updatedEvents.length > 0) {
99
+ sixMonthsLater.setMonth(today.getMonth() + 6);
193
- var message = '更新されたイベント:\n\n';
100
+ const calendars = CalendarApp.getAllCalendars();
101
+ let allEvents = [];
194
- updatedEvents.forEach(function(row) {
102
+ calendars.forEach(calendar => {
103
+ const events = getEventsWithinPeriod(calendar, today, sixMonthsLater, lastUpdated);
195
- message += formatEventMessage(row) + '\n\n';
104
+ allEvents = allEvents.concat(events);
196
105
  });
197
-
106
+ Logger.log(allEvents);
107
+
108
+
109
+
198
- // メール送信
110
+ // スクリプトのロックを解放
199
- MailApp.sendEmail({
111
+ Utilities.sleep(300);
200
- to: recipientEmail,
112
+ lock.releaseLock();
201
- subject: '更新されたイベントの通知',
113
+
202
- body: message + '\n '
114
+ } catch (error) {
203
- });
204
-
205
- // メールが送信されたら、スクリプトのプロパティを更新して再送信を防止する
206
- PropertiesService.getScriptProperties().setProperty('lastEmailSent', currentTime);
115
+ if (error.toString().includes('Lock timeout')) {
116
+ Logger.log('実行中のスクリプトが重複しているので処理を中断しました。');
207
- } else {
117
+ } else {
208
- // 更新されたイベントはないが、初めてのメール送信の場合は通知
209
- if (!lastEmailSent) {
210
- // 初めてのメール送信の場合は、通知
211
- MailApp.sendEmail({
212
- to: recipientEmail,
213
- subject: '更新されたイベントの通知',
214
- body: '更新されたイベントはありませんでした。'
215
- });
216
- // メールが送信されたら、スクリプトのプロパティを更新して再送信を防止する
217
- PropertiesService.getScriptProperties().setProperty('lastEmailSent', currentTime);
118
+ Logger.log('monitorAllCalendarsのエラーが発生しました: ' + error);
218
119
  }
219
120
  }
121
+ } else {
122
+ console.log('エディタからは実行できません');
220
123
  }
221
124
  }
222
125
 
223
- // イベントの情報を整形する関数
126
+ // 日付指定された形式に整形
224
- function formatEventMessage(event) {
127
+ function formatDate_(date) {
225
- var title = event[0];
226
- var startTime = event[1];
128
+ return Utilities.formatDate(date, 'JST', 'yyyy/MM/dd HH:mm');
129
+ }
130
+
227
- var endTime = event[2];
131
+ // 通知を送信
228
- var description = event[3];
229
- var location = event[4];
132
+ function sendEmailNotification_(mailBodies, date) {
230
-
133
+ try {
134
+ const recipientEmail = "kawata@actcube.jp"; // 送信先のメールアドレスを設定してください
135
+ const subject = "Googleカレンダーのイベント通知";
231
- var message = '';
136
+ let body = '';
137
+ //let body = '前回の通知(' + date.noticedDate + ')以降、Googleカレンダーのイベント通知を行いました。\n' +
138
+ '今回の通知(' + date.currentDate + ')対象のカレンダー名: ' + mailBodies[0].calendarName + '\n\n';
139
+ for (const eventDetails of mailBodies) {
140
+ body +=
232
- message += 'タイトル: ' + title + '\n';
141
+ 'タイトル : ' + eventDetails.title + '\n' +
142
+ '作成・更新日時 : ' + eventDetails.updateTime + '\n' +
233
- message += '開始日時: ' + startTime + '\n';
143
+ '開始日時 : ' + eventDetails.startTime + '\n' +
234
- message += '終了日時: ' + endTime + '\n';
144
+ '終了日時 : ' + eventDetails.endTime + '\n' +
235
- message += '詳細: ' + description + '\n';
145
+ '詳細 : ' + eventDetails.description + '\n' +
236
- message += '場所: ' + location + '\n';
146
+ '場所 : ' + eventDetails.location + '\n' +
237
-
147
+ 'URL : ' + eventDetails.url + '\n\n';
148
+ }
149
+ MailApp.sendEmail(recipientEmail, subject, body);
150
+ Logger.log('メールが送信されました: ' + body);
151
+
152
+ } catch (error) {
153
+ // メール送信中にエラーが発生した場合、エラーメッセージをログに出力する
154
+ Logger.log('メールの送信中にエラーが発生しました: ' + error);
155
+ }
156
+ }
157
+
158
+
159
+ function getEventsWithinPeriod(calendar, startDate, endDate, lastUpdated) {
160
+ let events = [];
161
+ let pageToken;
162
+ do {
163
+ const options = {
164
+ timeMin: startDate.toISOString(),
165
+ timeMax: endDate.toISOString(),
166
+ maxResults: 2500,
167
+ singleEvents: true,
168
+ orderBy: 'startTime',
169
+ pageToken: pageToken
170
+ };
171
+ const response = Calendar.Events.list(calendar.getId(), options);
172
+ const items = response.items.filter(item => new Date(item.updated) > lastUpdated);
173
+ events = events.concat(items);
174
+ pageToken = response.nextPageToken;
175
+ } while (pageToken);
238
- return message;
176
+ return events;
239
177
  }
240
178
 
241
179
  ```

12

文言の修正

2024/04/16 07:41

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
@@ -4,10 +4,10 @@
4
4
 
5
5
  ### 発生している問題・分からないこと
6
6
  今回の場合、
7
- 以下の点で困っています。
7
+ 以下の点で困っています。
8
8
 
9
9
  **・なぜかメール通知がなされない**
10
-
10
+ **・削除の場合、送信なれない**
11
11
 
12
12
 
13
13
  ### 該当のソースコード

11

本題のタイトルや、本文の変更

2024/04/16 07:26

投稿

kks
kks

スコア3

test CHANGED
@@ -1 +1 @@
1
- GASを使用してGoogleカレンダーでイベント更新があったら、スプレッドシートを通してその内容を任意のメールアドレスに送信
1
+ GASを使用してGoogleカレンダーでイベントを作成、更新、削除をしたら、スプレッドシートを通してその内容を任意のメールアドレスに送信
test CHANGED
@@ -1,5 +1,5 @@
1
1
  ### 実現したいこと
2
- 表題の件ですがGASを使用してGoogleカレンダーでイベント更新した場合、
2
+ 表題の件ですがGASを使用してGoogleカレンダーでイベントを作成、更新、削除した場合、
3
3
  任意のメールアドレスに送信されるという仕組みです。
4
4
 
5
5
  ### 発生している問題・分からないこと

10

追加事項の追加

2024/04/15 08:48

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
@@ -278,4 +278,9 @@
278
278
  var recipientEmail = '任意のメールアドレス'; // 送信先のメールアドレス
279
279
  ```
280
280
 
281
-
281
+ ### 追加事項
282
+ 以下のキャプチャは、イベントの設定変更を行うとき、場所を選択(会議室を選択)項目があります。
283
+
284
+ ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2024-04-15/1793d04e-6518-49fc-a22b-de6e73bd1561.png)
285
+
286
+

9

ソースコード修正

2024/04/12 01:32

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
@@ -177,11 +177,9 @@
177
177
  }
178
178
 
179
179
  // 更新されたイベントのみを抽出
180
- /*
181
180
  var updatedEvents = newData.filter(function(row) {
182
181
  return row[5] !== ''; // URLが空でない場合、更新されたイベントとみなす
183
182
  });
184
- */
185
183
 
186
184
  // 最後のメール送信時刻を取得
187
185
  var lastEmailSent = PropertiesService.getScriptProperties().getProperty('lastEmailSent');

8

ソースコードの修正

2024/04/12 01:29

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
@@ -139,11 +139,12 @@
139
139
  function removeDuplicatesFromSheet() {
140
140
  var spreadsheetId = 'スプレッドシートのID';
141
141
  var sheetName = 'カレンダー変更通知の管理';
142
+ var range = 'A2:F'; // A2からの範囲を指定
142
143
  var recipientEmail = '任意のメールアドレス'; // 送信先のメールアドレス
143
- var range = 'A2:F'; // A2からの範囲を指定
144
144
 
145
145
  var sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
146
- var dataRange = sheet.getRange(range);
146
+ //var dataRange = sheet.getRange(range);
147
+ var dataRange = sheet.getRange(range + sheet.getLastRow()); //データがないシートの全ての行を確認する必要はない
147
148
  var values = dataRange.getValues();
148
149
  var newData = [];
149
150
  var uniqueEntries = {};
@@ -176,9 +177,11 @@
176
177
  }
177
178
 
178
179
  // 更新されたイベントのみを抽出
180
+ /*
179
181
  var updatedEvents = newData.filter(function(row) {
180
182
  return row[5] !== ''; // URLが空でない場合、更新されたイベントとみなす
181
183
  });
184
+ */
182
185
 
183
186
  // 最後のメール送信時刻を取得
184
187
  var lastEmailSent = PropertiesService.getScriptProperties().getProperty('lastEmailSent');

7

タイトル変更、メールアドレス直接ではなくスプレッドシートを通して送信に変更

2024/04/11 07:22

投稿

kks
kks

スコア3

test CHANGED
@@ -1 +1 @@
1
- GASを使用してGoogleカレンダーでイベント更新があったら、その内容を任意のメールアドレスに送信
1
+ GASを使用してGoogleカレンダーでイベント更新があったら、スプレッドシートを通してその内容を任意のメールアドレスに送信
test CHANGED
@@ -4,11 +4,9 @@
4
4
 
5
5
  ### 発生している問題・分からないこと
6
6
  今回の場合、
7
- 以下の点で困っています。
7
+ 以下の点で困っています。
8
-
8
+
9
- **・なぜかメール通知がなされない
9
+ **・なぜかメール通知がなされない**
10
- ・2回呼ばれててしまう現象が不明(Googleの仕様?)**
11
-
12
10
 
13
11
 
14
12
 
@@ -31,6 +29,24 @@
31
29
 
32
30
  var notifiedCount = 0; // 通知されるイベントの数をカウントする変数
33
31
 
32
+ // スプレッドシートのIDを指定
33
+ var spreadsheetId = 'スプレッドシートのID';
34
+
35
+ // シート名を指定
36
+ var sheetName = 'カレンダー変更通知の管理';
37
+ // シートの範囲を指定
38
+ var range = 'A2:F'; // URLのために範囲を追加
39
+
40
+ // スプレッドシートにヘッダーを追加
41
+ var headers = ['タイトル', '開始日時', '終了日時', '詳細', '場所', 'URL']; // URLのヘッダーを追加
42
+ var sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
43
+
44
+ // シートが存在しない場合は新規作成する
45
+ if (!sheet) {
46
+ sheet = SpreadsheetApp.openById(spreadsheetId).insertSheet(sheetName);
47
+ sheet.getRange('A1:F1').setValues([headers]); // URLのために範囲を変更
48
+ }
49
+
34
50
  for (var i = 0; i < calendarIds.length; i++) {
35
51
  var calendarId = calendarIds[i];
36
52
  var startDateTime = today;
@@ -56,47 +72,32 @@
56
72
  var startTime = event.getStartTime() ? formatDate(event.getStartTime()) : '開始日時が設定されていません';
57
73
  var endTime = event.getEndTime() ? formatDate(event.getEndTime()) : '終了日時が設定されていません';
58
74
 
59
- // 通知されるべきイベントの詳細をログに出力
75
+ // イベントの詳細と場所取得
60
- Logger.log('通知されるイベント: ' + title + ' (' + startTime + ' - ' + endTime + ')');
61
-
62
76
  var description = event.getDescription() || '詳細が設定されていません';
63
77
  var location = event.getLocation() || '場所が設定されていません';
64
78
 
65
- // 通知されていない場合み通知送信
79
+ // イベントURL取得
66
- var eventDetails = {
80
+ var url = event.getOriginalCalendarId(); // 例としてイベントのカレンダーIDを取得
67
- title: title,
81
+
68
- startTime: startTime,
69
- endTime: endTime,
70
- description: description,
82
+ // スプレッドシートにイベント情報を追加
71
- location: location,
72
- url: 'https://calendar.google.com/calendar/render?action=VIEW&eid=' + eventId, // URL 直接指定
83
+ var rowData = [title, startTime, endTime, description, location, 'https://calendar.google.com/calendar/render?action=VIEW&eid=' + url]; // URLを追加
73
- triggerUid: "your_trigger_uid_here",
74
- authMode: "your_auth_mode_here",
75
- calendarId: calendarId
76
- };
77
-
78
- if (!notifiedEvents.includes(eventId)) {
79
- // メールを送信する
80
- sendEmailNotification(eventDetails);
84
+ sheet.appendRow(rowData);
81
-
85
+
82
- // 通知されたイベントを記録
86
+ // 通知されたイベントを記録
83
- notifiedEvents.push(eventId);
87
+ notifiedEvents.push(eventId);
84
-
88
+
85
- // 通知されたイベントの数を増やす
89
+ // 通知されたイベントの数を増やす
86
- notifiedCount++;
90
+ notifiedCount++;
87
-
91
+
88
- // 通知されたイベントを記録
92
+ // 通知されたイベントを記録
89
- Logger.log('イベントが通知されました: ' + title);
93
+ Logger.log('イベントがスプレッドシートに追加されました: ' + title);
90
- } else {
91
- Logger.log('通知されるイベントが既に通知済みです: ' + title);
92
- }
93
94
  }
94
95
  }
95
96
  }
96
97
  }
97
98
 
98
99
  // 通知されるイベントの数をログに記録
99
- Logger.log('通知されイベントの数: ' + notifiedCount);
100
+ Logger.log('スプレッドシートに追加されイベントの数: ' + notifiedCount);
100
101
 
101
102
  // 通知されたイベントと最後の通知時間を保存
102
103
  PropertiesService.getScriptProperties().setProperty('notifiedEvents', notifiedEvents.join(','));
@@ -106,7 +107,6 @@
106
107
  Logger.log('monitorAllCalendarsのエラーが発生しました: ' + error);
107
108
  }
108
109
  }
109
-
110
110
 
111
111
  // 日付を指定された形式に整形する関数
112
112
  function formatDate(date) {
@@ -118,12 +118,13 @@
118
118
  return year + '/' + month + '/' + day + ' ' + hours + ':' + minutes;
119
119
  }
120
120
 
121
-
121
+ // 通知されたイベントを取得するための関数
122
122
  function getNotifiedEvents() {
123
123
  var notifiedEvents = PropertiesService.getScriptProperties().getProperty('notifiedEvents');
124
124
  return notifiedEvents ? notifiedEvents.split(',') : [];
125
125
  }
126
126
 
127
+ // カレンダーIDのリストを取得するための関数
127
128
  function getAllCalendarIds() {
128
129
  var calendars = CalendarApp.getAllCalendars();
129
130
  var calendarIds = [];
@@ -134,26 +135,106 @@
134
135
  return calendarIds;
135
136
  }
136
137
 
137
-
138
+ // 任意のスプレッドシートに更新情報を追加して後、任意のメールアドレスに通知
138
- function sendEmailNotification(eventDetails) {
139
+ function removeDuplicatesFromSheet() {
140
+ var spreadsheetId = 'スプレッドシートのID';
139
- try {
141
+ var sheetName = 'カレンダー変更通知の管理';
140
- var recipientEmail = "任意のメールアドレス"; // 送信先のメールアドレスを設定してください
142
+ var recipientEmail = '任意のメールアドレス'; // 送信先のメールアドレス
141
- var subject = "Googleカレンダーのイベントが更新されました";
142
- var body = 'Googleカレンダーのイベントが更新されました。\n' +
143
- 'タイトル: ' + eventDetails.title + '\n' +
144
- '開始日時: ' + eventDetails.startTime + '\n' +
145
- '終了日時: ' + eventDetails.endTime + '\n' +
146
- '詳細: ' + eventDetails.description + '\n' +
147
- '場所: ' + eventDetails.location + '\n' +
148
- 'URL: ' + eventDetails.url;
149
-
150
- MailApp.sendEmail(recipientEmail, subject, body);
151
-
152
- Logger.log('メールが送信されました: ' + body); // 追加
143
+ var range = 'A2:F'; // A2からの範囲を指定
144
+
145
+ var sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
146
+ var dataRange = sheet.getRange(range);
147
+ var values = dataRange.getValues();
148
+ var newData = [];
153
- } catch (error) {
149
+ var uniqueEntries = {};
150
+
154
- // メール送信中にエラーが発生た場合、エラーメッセージログに出力
151
+ // 重複を除去し、一意のントリのみ
152
+ values.forEach(function(row) {
155
- Logger.log('メールの送信中にエラーが発生しました: ' + error);
153
+ var key = row.join('|');
154
+ if (!uniqueEntries[key]) {
155
+ newData.push(row);
156
+ uniqueEntries[key] = true;
156
- }
157
+ }
158
+ });
159
+
160
+ // 削除されたデータを保存
161
+ var deletedData = [];
162
+ if (newData.length < values.length) {
163
+ values.forEach(function(row) {
164
+ var key = row.join('|');
165
+ if (!uniqueEntries[key]) {
166
+ deletedData.push(row);
167
+ }
168
+ });
169
+ }
170
+
171
+ // 新しいデータで既存の範囲を上書きする
172
+ sheet.getRange(range).clearContent(); // 指定された範囲をクリア
173
+ if (newData.length > 0) {
174
+ var newRange = sheet.getRange(2, 1, newData.length, newData[0].length);
175
+ newRange.setValues(newData);
176
+ }
177
+
178
+ // 更新されたイベントのみを抽出
179
+ var updatedEvents = newData.filter(function(row) {
180
+ return row[5] !== ''; // URLが空でない場合、更新されたイベントとみなす
181
+ });
182
+
183
+ // 最後のメール送信時刻を取得
184
+ var lastEmailSent = PropertiesService.getScriptProperties().getProperty('lastEmailSent');
185
+ var currentTime = new Date().getTime(); // 現在時刻のミリ秒単位の表現を取得
186
+
187
+ // メールが送信されてから一定時間以上経過しているか確認
188
+ var emailInterval = 60000; // メール送信の間隔(ミリ秒)
189
+ if (!lastEmailSent || (currentTime - lastEmailSent) >= emailInterval) {
190
+ // 更新されたイベントがあればメール送信する
191
+ if (updatedEvents.length > 0) {
192
+ var message = '更新されたイベント:\n\n';
193
+ updatedEvents.forEach(function(row) {
194
+ message += formatEventMessage(row) + '\n\n';
195
+ });
196
+
197
+ // メール送信
198
+ MailApp.sendEmail({
199
+ to: recipientEmail,
200
+ subject: '更新されたイベントの通知',
201
+ body: message + '\n '
202
+ });
203
+
204
+ // メールが送信されたら、スクリプトのプロパティを更新して再送信を防止する
205
+ PropertiesService.getScriptProperties().setProperty('lastEmailSent', currentTime);
206
+ } else {
207
+ // 更新されたイベントはないが、初めてのメール送信の場合は通知
208
+ if (!lastEmailSent) {
209
+ // 初めてのメール送信の場合は、通知
210
+ MailApp.sendEmail({
211
+ to: recipientEmail,
212
+ subject: '更新されたイベントの通知',
213
+ body: '更新されたイベントはありませんでした。'
214
+ });
215
+ // メールが送信されたら、スクリプトのプロパティを更新して再送信を防止する
216
+ PropertiesService.getScriptProperties().setProperty('lastEmailSent', currentTime);
217
+ }
218
+ }
219
+ }
220
+ }
221
+
222
+ // イベントの情報を整形する関数
223
+ function formatEventMessage(event) {
224
+ var title = event[0];
225
+ var startTime = event[1];
226
+ var endTime = event[2];
227
+ var description = event[3];
228
+ var location = event[4];
229
+
230
+ var message = '';
231
+ message += 'タイトル: ' + title + '\n';
232
+ message += '開始日時: ' + startTime + '\n';
233
+ message += '終了日時: ' + endTime + '\n';
234
+ message += '詳細: ' + description + '\n';
235
+ message += '場所: ' + location + '\n';
236
+
237
+ return message;
157
238
  }
158
239
 
159
240
  ```
@@ -165,19 +246,25 @@
165
246
  - [ ] その他
166
247
 
167
248
  ##### 上記の詳細・結果
168
- まずはトリガーの設定はいかに設定しています。
249
+ まずはトリガーの設定は以下に設定しています。
169
-
250
+
170
- ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2024-04-10/a5a71246-8b95-45a1-b22c-554756634d23.png)
251
+ ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2024-04-11/8e002cd6-8589-4ead-a31f-513e3a189a14.png)
171
-
252
+
172
- monitorAllCalendars関数のをトリガー設定ています。
253
+ monitorAllCalendars関数でグーグルイベント更新があったら、そ内容以下のように行で任意のスプレッドシートに記載します。
173
-
254
+
174
- ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2024-04-10/669d50b6-1ae4-4b42-9705-13ff30b96738.png)
255
+ ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2024-04-11/a5f399b8-200f-4aa7-9882-ebf8ed4e4e50.png)
175
-
256
+
176
- ログ上記になっす。
257
+ 今回いくつか同じ内容が来うのでその場合は
177
- イベントは0個になっているのでメール送信ができないのでは?と思っております
258
+ removeDuplicatesFromSheet関数で削除を行っています
259
+ 一度のメールがこのコードですと「0通」になってしまいます。
260
+
261
+ ```ここに言語を入力
262
+ if (!lastEmailSent || (currentTime - lastEmailSent) >= emailInterval) {
263
+ ```
264
+
265
+ 上記の条件分岐が当てはまっていない気がします。
178
266
 
179
267
  すみませんが皆様からのご教示のほどよろしくお願いいたします。
180
-
181
268
 
182
269
 
183
270
  ### 補足
@@ -185,9 +272,9 @@
185
272
  もし検証される場合はお持ちのメールアドレスをご記入ください。
186
273
 
187
274
  ```ここに言語を入力
275
+ var spreadsheetId = 'スプレッドシートのID';
276
+ var sheetName = 'カレンダー変更通知の管理';
188
- var recipientEmail = "任意のメールアドレス"; // 送信先のメールアドレスを設定してください
277
+ var recipientEmail = '任意のメールアドレス'; // 送信先のメールアドレス
189
278
  ```
190
279
 
191
- 上記のソースコードでアカウントによっては2通送れる(正常?)らしいので、
280
+
192
- あとはGoogleカレンダーとの連携や設定の問題でしょうか?
193
-

6

コードを編集しました

2024/04/11 01:54

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
@@ -62,27 +62,33 @@
62
62
  var description = event.getDescription() || '詳細が設定されていません';
63
63
  var location = event.getLocation() || '場所が設定されていません';
64
64
 
65
- // イベントのIDが通知済みリストに含まれていない確認
65
+ // 通知れていない場合のみ通知送信
66
+ var eventDetails = {
67
+ title: title,
68
+ startTime: startTime,
69
+ endTime: endTime,
70
+ description: description,
71
+ location: location,
72
+ url: 'https://calendar.google.com/calendar/render?action=VIEW&eid=' + eventId, // URL を直接指定
73
+ triggerUid: "your_trigger_uid_here",
74
+ authMode: "your_auth_mode_here",
75
+ calendarId: calendarId
76
+ };
77
+
66
78
  if (!notifiedEvents.includes(eventId)) {
67
- // 通知されていない場合のみ通知を送信
68
- var eventDetails = {
69
- title: title,
70
- startTime: startTime,
71
- endTime: endTime,
72
- description: description,
73
- location: location,
74
- url: 'https://calendar.google.com/calendar/render?action=VIEW&eid=' + eventId, // URL を直接指定
75
- triggerUid: "your_trigger_uid_here",
76
- authMode: "your_auth_mode_here",
77
- calendarId: calendarId
78
- };
79
-
80
79
  // メールを送信する
81
80
  sendEmailNotification(eventDetails);
82
- notifiedCount++; // 通知されるイベントの数を増やす
83
81
 
84
82
  // 通知されたイベントを記録
85
83
  notifiedEvents.push(eventId);
84
+
85
+ // 通知されたイベントの数を増やす
86
+ notifiedCount++;
87
+
88
+ // 通知されたイベントを記録
89
+ Logger.log('イベントが通知されました: ' + title);
90
+ } else {
91
+ Logger.log('通知されるイベントが既に通知済みです: ' + title);
86
92
  }
87
93
  }
88
94
  }
@@ -100,6 +106,7 @@
100
106
  Logger.log('monitorAllCalendarsのエラーが発生しました: ' + error);
101
107
  }
102
108
  }
109
+
103
110
 
104
111
  // 日付を指定された形式に整形する関数
105
112
  function formatDate(date) {

5

タイトル変更

2024/04/11 01:28

投稿

kks
kks

スコア3

test CHANGED
@@ -1 +1 @@
1
- GASを使用してGoogleカレンダーでイベント更新があったら、その内容を任意のメールアドレスにメール
1
+ GASを使用してGoogleカレンダーでイベント更新があったら、その内容を任意のメールアドレスに送信
test CHANGED
File without changes

4

補足に追記

2024/04/11 01:01

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
@@ -181,4 +181,6 @@
181
181
  var recipientEmail = "任意のメールアドレス"; // 送信先のメールアドレスを設定してください
182
182
  ```
183
183
 
184
+ 上記のソースコードでアカウントによっては2通送れる(正常?)らしいので、
185
+ あとはGoogleカレンダーとの連携や設定の問題でしょうか?
184
186
 

3

補足を追加

2024/04/10 09:08

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
@@ -174,4 +174,11 @@
174
174
 
175
175
 
176
176
  ### 補足
177
+ GASコード内の以下の部分は任意のメールアドレスを記入されています。
178
+ もし検証される場合はお持ちのメールアドレスをご記入ください。
179
+
180
+ ```ここに言語を入力
181
+ var recipientEmail = "任意のメールアドレス"; // 送信先のメールアドレスを設定してください
177
- 特になし
182
+ ```
183
+
184
+

2

文言の修正

2024/04/10 09:03

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
@@ -167,7 +167,7 @@
167
167
  ![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2024-04-10/669d50b6-1ae4-4b42-9705-13ff30b96738.png)
168
168
 
169
169
  ログは上記になっています。
170
- イベントは0個になっているのでメール送信がd系ないのでは?と思っております。
170
+ イベントは0個になっているのでメール送信ができないのでは?と思っております。
171
171
 
172
172
  すみませんが皆様からのご教示のほどよろしくお願いいたします。
173
173
 

1

タグの追加

2024/04/10 09:03

投稿

kks
kks

スコア3

test CHANGED
File without changes
test CHANGED
File without changes