質問編集履歴
15
コードの修正
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 (event
|
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(
|
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
|
-
|
81
|
+
const twoWeeksSavedEvents = savedEvents.filter(data => data[5] >= today && data[5] <= twoWeeksLater);
|
82
|
+
|
83
|
+
// 削除されたイベントIDのリストを格納するための配列
|
84
|
+
const deletedEventIds = [];
|
85
|
+
|
86
|
+
// 2週間分の保存されたイベントを反復処理
|
84
|
-
|
87
|
+
for (const data of twoWeeksSavedEvents) {
|
88
|
+
if (!twoWeeksMap.has(data[0])) {
|
89
|
+
// 削除されたイベントIDを検出し、deletedEventIds に追加
|
85
|
-
|
90
|
+
deletedEventIds.push(data[0]);
|
86
|
-
|
91
|
+
}
|
87
|
-
return o;
|
88
|
-
|
92
|
+
}
|
89
|
-
|
90
|
-
|
93
|
+
|
91
|
-
|
94
|
+
// deletedEventIds を元に削除されたイベントの詳細を取得し、メール通知の準備を行う
|
92
|
-
if (deletedEvents.length > 0) {
|
93
|
-
|
95
|
+
for (const eventId of deletedEventIds) {
|
94
|
-
|
96
|
+
// 削除されたイベントの詳細を取得
|
97
|
+
const deletedEventData = savedEvents.find(data => data[0] === eventId);
|
98
|
+
|
99
|
+
// 削除されたイベントの詳細が見つかった場合、メール通知項目を生成して mailBodies に追加
|
100
|
+
if (deletedEventData) {
|
95
|
-
|
101
|
+
const eventDetails = {
|
96
|
-
|
102
|
+
title: deletedEventData[3] || 'タイトル' + isNotExist,
|
97
|
-
|
103
|
+
startTime: deletedEventData[5] ? formatDate_(deletedEventData[5]) : '開始日時' + isNotExist,
|
98
|
-
|
104
|
+
endTime: deletedEventData[6] ? formatDate_(deletedEventData[6]) : '終了日時' + isNotExist,
|
99
|
-
|
105
|
+
updateTime: formatDate_(calendar.getEventById(eventId).getLastUpdated()),
|
100
|
-
|
106
|
+
description: deletedEventData[8] || '詳細' + isNotExist,
|
101
|
-
|
107
|
+
location: deletedEventData[7] || '場所' + isNotExist,
|
102
|
-
|
108
|
+
url: '',
|
103
|
-
|
109
|
+
calendarId: e.calendarId,
|
104
|
-
|
110
|
+
calendarName: calendar.getName(),
|
105
|
-
|
111
|
+
};
|
106
|
-
|
112
|
+
// メール本文を蓄積する
|
107
|
-
|
113
|
+
mailBodies.push(eventDetails);
|
108
|
-
|
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(),
|
131
|
+
event.getId(), // イベントID[0]
|
128
|
-
calendar.getName(),
|
132
|
+
calendar.getName(), // カレンダー名[1]
|
129
|
-
e.calendarId,
|
133
|
+
e.calendarId, // カレンダーID[2]
|
130
|
-
event.getTitle(),
|
134
|
+
event.getTitle(), // タイトル[3]
|
131
|
-
|
135
|
+
event.getLastUpdated(), // 最終更新日時[4]
|
132
|
-
|
136
|
+
event.getStartTime(), // 開始日時[5]
|
133
|
-
|
137
|
+
event.getEndTime(), // 終了日時[6]
|
134
|
-
event.getLocation(),
|
138
|
+
event.getLocation(), // 場所[7]
|
135
|
-
event.getDescription(),
|
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
|
-
|
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カレンダー
|
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
|
-
'作成
|
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
ソースコードの更新
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 monitor
|
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(
|
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
|
-
// 実行日
|
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(to
|
39
|
+
twoWeeksLater.setDate(twoWeeksLater.getDate() + 14); // 2週間後の日付
|
40
|
+
const sixMonthsLater = new Date(today);
|
40
|
-
t
|
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 noti
|
47
|
+
let noticeCount = 0; // 通知されるイベントの数をカウントする変数
|
45
|
-
const mailBodies = []
|
48
|
+
const mailBodies = []; // 通知内容を蓄積する配列
|
49
|
+
const twoWeeksMap = new Map();
|
50
|
+
|
46
|
-
//
|
51
|
+
// 追加・更新された予定を検出
|
47
|
-
const events = calendar.getEvents(today, twoWeeksLater);
|
48
|
-
if (events && events.length > 0) {
|
49
|
-
|
52
|
+
for (const event of events) {
|
50
|
-
|
53
|
+
const eventUpdated = event.getLastUpdated();
|
51
|
-
|
54
|
+
if (eventUpdated > twoWeeksLater) {
|
55
|
+
break;
|
52
|
-
if (event
|
56
|
+
} else if (eventUpdated > lastUpdated) {
|
57
|
+
twoWeeksMap.set(event.getId(), eventUpdated);
|
58
|
+
// メール通知項目を生成
|
53
|
-
|
59
|
+
const eventDetails = {
|
54
|
-
if (!title) {
|
55
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
92
|
+
if (deletedEvents.length > 0) {
|
69
|
-
|
93
|
+
for (const data of deletedEvents) {
|
94
|
+
// 削除されたことを示すラベルを追加してメール通知内容を作成
|
70
95
|
const eventDetails = {
|
71
|
-
title: tit
|
96
|
+
title: `[削除済み] ${data[3] || 'タイトル' + isNotExist}`, // タイトルにラベルを追加
|
72
|
-
startTime:
|
97
|
+
startTime: data[5] ? formatDate_(data[5]) : '開始日時' + isNotExist,
|
73
|
-
endTime: e
|
98
|
+
endTime: data[6] ? formatDate_(data[6]) : '終了日時' + isNotExist,
|
74
|
-
updateTime:
|
99
|
+
updateTime: formatDate_(calendar.getEventById(data[0]).getLastUpdated()),
|
75
|
-
description: d
|
100
|
+
description: data[8] || '詳細' + isNotExist,
|
76
|
-
location:
|
101
|
+
location: data[7] || '場所' + isNotExist,
|
77
|
-
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
|
-
noti
|
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('通知されるイベントの数: ' + noti
|
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
|
-
|
124
|
+
if (events.length > 0) {
|
103
|
-
|
125
|
+
// スプレッドシートに書き込むデータのフォーマットを修正
|
104
|
-
al
|
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
|
-
|
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('
|
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 =
|
166
|
+
const recipientEmail = 'test@gmail.com'; // 送信先のメールアドレスを設定してください
|
135
|
-
const subject = "Googleカレンダーのイベント
|
167
|
+
const subject = "Googleカレンダーのイベントが更新されました";
|
136
|
-
let body = '';
|
137
|
-
|
168
|
+
let body = '前回の通知(' + date.noticedDate + ')以降、Googleカレンダーのイベントが更新されました。\n' +
|
138
169
|
'今回の通知(' + date.currentDate + ')対象のカレンダー名: ' + mailBodies[0].calendarName + '\n\n';
|
139
|
-
for (const
|
170
|
+
for (const item of mailBodies) {
|
140
171
|
body +=
|
141
|
-
'タイトル : ' + eventDetails.title + '\n' +
|
142
|
-
'作成・更新日時
|
172
|
+
'作成・更新日時: ' + item.updateTime + '\n' +
|
173
|
+
'タイトル: ' + item.title + '\n' +
|
143
|
-
'開始日時
|
174
|
+
'開始日時: ' + item.startTime + '\n' +
|
144
|
-
'終了日時
|
175
|
+
'終了日時: ' + item.endTime + '\n' +
|
176
|
+
'場所: ' + item.location + '\n' +
|
145
|
-
'詳細
|
177
|
+
'詳細: ' + item.description + '\n' +
|
146
|
-
'場所 : ' + eventDetails.location + '\n' +
|
147
|
-
'URL
|
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
コード最新修正
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
|
-
|
23
|
+
const lock = LockService.getScriptLock();
|
24
|
+
lock.waitLock(100); // 既に実行中ならエラーとするロックを取得(0.1秒だけ待機)
|
25
|
+
|
26
|
+
// プロパティサービスから前回実行日時を取得
|
27
|
+
const properties = PropertiesService.getScriptProperties();
|
19
|
-
|
28
|
+
const lastUpdated = new Date(properties.getProperty('lastUpdated'));
|
29
|
+
const noticedDate = formatDate_(lastUpdated);
|
30
|
+
|
31
|
+
// スクリプトの実行日時を取得
|
20
|
-
|
32
|
+
const currentTime = new Date();
|
21
|
-
|
33
|
+
const currentDate = formatDate_(currentTime);
|
34
|
+
|
22
|
-
|
35
|
+
// 実行日の日付と2週間後の日付を生成
|
23
|
-
|
36
|
+
const today = new Date();
|
24
|
-
today.setHours(0, 0, 0, 0);
|
37
|
+
today.setHours(0, 0, 0, 0);
|
25
|
-
|
26
|
-
|
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
|
-
|
44
|
+
let notifiedCount = 0; // 通知されるイベントの数をカウントする変数
|
31
|
-
|
45
|
+
const mailBodies = []
|
32
|
-
//
|
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
|
-
|
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
|
-
|
49
|
+
for (const event of events) {
|
60
|
-
|
50
|
+
const eventId = event.getId();
|
61
|
-
var lastUpdatedTime = event.getLastUpdated();
|
62
|
-
|
63
51
|
// 通知すべきイベントが更新されたかどうかを確認
|
64
|
-
if (
|
52
|
+
if (event.getLastUpdated() > lastUpdated) {
|
65
|
-
|
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
|
-
|
60
|
+
const startTime = event.getStartTime() ? formatDate_(event.getStartTime()) : '開始日時' + isNotExist;
|
73
|
-
|
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
|
-
|
67
|
+
const description = event.getDescription() || '詳細' + isNotExist;
|
77
|
-
|
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
|
-
//
|
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
|
-
|
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
|
-
|
89
|
+
sendEmailNotification_(mailBodies, { noticedDate, currentDate });
|
101
|
-
|
102
|
-
//
|
90
|
+
// 最後の通知時刻を保存
|
103
|
-
PropertiesService.getScriptProperties().setProperty('notifiedEvents', notifiedEvents.join(','));
|
104
|
-
|
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
|
-
|
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
|
-
i
|
99
|
+
sixMonthsLater.setMonth(today.getMonth() + 6);
|
193
|
-
|
100
|
+
const calendars = CalendarApp.getAllCalendars();
|
101
|
+
let allEvents = [];
|
194
|
-
|
102
|
+
calendars.forEach(calendar => {
|
103
|
+
const events = getEventsWithinPeriod(calendar, today, sixMonthsLater, lastUpdated);
|
195
|
-
|
104
|
+
allEvents = allEvents.concat(events);
|
196
105
|
});
|
197
|
-
|
106
|
+
Logger.log(allEvents);
|
107
|
+
|
108
|
+
|
109
|
+
|
198
|
-
//
|
110
|
+
// スクリプトのロックを解放
|
199
|
-
|
111
|
+
Utilities.sleep(300);
|
200
|
-
|
112
|
+
lock.releaseLock();
|
201
|
-
|
113
|
+
|
202
|
-
|
114
|
+
} catch (error) {
|
203
|
-
});
|
204
|
-
|
205
|
-
// メールが送信されたら、スクリプトのプロパティを更新して再送信を防止する
|
206
|
-
|
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
|
-
|
118
|
+
Logger.log('monitorAllCalendarsのエラーが発生しました: ' + error);
|
218
119
|
}
|
219
120
|
}
|
121
|
+
} else {
|
122
|
+
console.log('エディタからは実行できません');
|
220
123
|
}
|
221
124
|
}
|
222
125
|
|
223
|
-
//
|
126
|
+
// 日付を指定された形式に整形
|
224
|
-
function format
|
127
|
+
function formatDate_(date) {
|
225
|
-
var title = event[0];
|
226
|
-
|
128
|
+
return Utilities.formatDate(date, 'JST', 'yyyy/MM/dd HH:mm');
|
129
|
+
}
|
130
|
+
|
227
|
-
|
131
|
+
// 通知を送信
|
228
|
-
var description = event[3];
|
229
|
-
|
132
|
+
function sendEmailNotification_(mailBodies, date) {
|
230
|
-
|
133
|
+
try {
|
134
|
+
const recipientEmail = "kawata@actcube.jp"; // 送信先のメールアドレスを設定してください
|
135
|
+
const subject = "Googleカレンダーのイベント通知";
|
231
|
-
|
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
|
-
|
141
|
+
'タイトル : ' + eventDetails.title + '\n' +
|
142
|
+
'作成・更新日時 : ' + eventDetails.updateTime + '\n' +
|
233
|
-
|
143
|
+
'開始日時 : ' + eventDetails.startTime + '\n' +
|
234
|
-
|
144
|
+
'終了日時 : ' + eventDetails.endTime + '\n' +
|
235
|
-
|
145
|
+
'詳細 : ' + eventDetails.description + '\n' +
|
236
|
-
|
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
|
176
|
+
return events;
|
239
177
|
}
|
240
178
|
|
241
179
|
```
|
12
文言の修正
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
本題のタイトルや、本文の変更
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
追加事項の追加
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
ソースコード修正
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
ソースコードの修正
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
タイトル変更、メールアドレス直接ではなくスプレッドシートを通して送信に変更
test
CHANGED
@@ -1 +1 @@
|
|
1
|
-
GASを使用してGoogleカレンダーでイベント更新があったら、その内容を任意のメールアドレスに送信
|
1
|
+
GASを使用してGoogleカレンダーでイベント更新があったら、スプレッドシートを通してその内容を任意のメールアドレスに送信
|
test
CHANGED
@@ -4,11 +4,9 @@
|
|
4
4
|
|
5
5
|
### 発生している問題・分からないこと
|
6
6
|
今回の場合、
|
7
|
-
以下の
|
7
|
+
以下の1点で困っています。
|
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 event
|
80
|
+
var url = event.getOriginalCalendarId(); // 例としてイベントのカレンダーIDを取得
|
67
|
-
|
81
|
+
|
68
|
-
startTime: startTime,
|
69
|
-
endTime: endTime,
|
70
|
-
|
82
|
+
// スプレッドシートにイベント情報を追加
|
71
|
-
location: location,
|
72
|
-
|
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
|
-
|
84
|
+
sheet.appendRow(rowData);
|
81
|
-
|
85
|
+
|
82
|
-
|
86
|
+
// 通知されたイベントを記録
|
83
|
-
|
87
|
+
notifiedEvents.push(eventId);
|
84
|
-
|
88
|
+
|
85
|
-
|
89
|
+
// 通知されたイベントの数を増やす
|
86
|
-
|
90
|
+
notifiedCount++;
|
87
|
-
|
91
|
+
|
88
|
-
|
92
|
+
// 通知されたイベントを記録
|
89
|
-
|
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('
|
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
|
139
|
+
function removeDuplicatesFromSheet() {
|
140
|
+
var spreadsheetId = 'スプレッドシートのID';
|
139
|
-
|
141
|
+
var sheetName = 'カレンダー変更通知の管理';
|
140
|
-
|
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
|
-
|
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
|
-
|
149
|
+
var uniqueEntries = {};
|
150
|
+
|
154
|
-
|
151
|
+
// 重複を除去し、一意のエントリのみを残す
|
152
|
+
values.forEach(function(row) {
|
155
|
-
|
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
|
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-1
|
255
|
+
![イメージ説明](https://ddjkaamml8q8x.cloudfront.net/questions/2024-04-11/a5f399b8-200f-4aa7-9882-ebf8ed4e4e50.png)
|
175
|
-
|
256
|
+
|
176
|
-
|
257
|
+
今回はいくつか同じ内容が来てしまうのでその場合は
|
177
|
-
|
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
|
-
|
280
|
+
|
192
|
-
あとはGoogleカレンダーとの連携や設定の問題でしょうか?
|
193
|
-
|
6
コードを編集しました
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
|
-
//
|
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
タイトル変更
test
CHANGED
@@ -1 +1 @@
|
|
1
|
-
GASを使用してGoogleカレンダーでイベント更新があったら、その内容を任意のメールアドレスに
|
1
|
+
GASを使用してGoogleカレンダーでイベント更新があったら、その内容を任意のメールアドレスに送信
|
test
CHANGED
File without changes
|
4
補足に追記
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
補足を追加
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
文言の修正
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個になっているのでメール送信が
|
170
|
+
イベントは0個になっているのでメール送信ができないのでは?と思っております。
|
171
171
|
|
172
172
|
すみませんが皆様からのご教示のほどよろしくお願いいたします。
|
173
173
|
|
1
タグの追加
test
CHANGED
File without changes
|
test
CHANGED
File without changes
|