START_EVENT
2025-10-06
(C) Questetra, Inc. (MIT License)
3
2
This item starts a process when Gmail has received a new message.
このアイテムは、Gmail が新しいメールを受信すると、プロセスを開始します。
https://support.questetra.com/bpmn-icons/start-event-gmail-message-received/
https://support.questetra.com/ja/bpmn-icons/start-event-gmail-message-received/
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADPUlEQVRYR8WXX0hTURzHv2dzy5bb
1HKKRH+gtx7K2izooXI+BVH41F+IglAJmhVICr2kgRG6DFRERXBpGIgkZA/Oeigir+VzIGQE1bTU
yXYdy90Tu+5u997dea9p3PO2nd+fz/md359zCXReRKv/76cPW4ysoYKAnARoCSj2gCCP16dYAMEM
QKYo6OuYhRsqHvnIarGtCjB7wlWELNSCohJAthajACIg6MAKmhxvmJ9r6awJECgrrSSEPgKwTaNj
uViYUnKncHyiI5N+RoC5clcbpaj6R8cSNULQXjDGVCvZUgQIlDn7CSHnN8O5YINSOlA4PnlBbjMN
YDNPnuZMIRISgMSdt2/myeW2KCVV4pxIAvDZbsS0kHCGAgdsdQ0w2HPBPvchMvpCMxexWmGrb4Sx
qBiRl8NgB31i3TBi2CdURwqg3NUCCo8gme8b5g0IK8q8R7C+BuC4NUFMJU7YG70gZnNSLnj3JuL6
yUXgdYwxNfHfPEC8yWSxht/iOi949Q7IMkmcccFFLHquI/ZtRhEip/oWtlacS9tjB/sQ7nwi/j+y
YuG2x5sVDxBwuy4RoE8soQTA71MOodaHWB4ZSh3IakWetwvG3XsVweJXEO5slexR4HKhn/HxALPu
0m6AXtUEkBASrsR80AlbQ7Mk5HIKJQCA9Dj8E9cSAK5PAErWA8AHg2VBLBbV5FQGwJTDzxxaBShz
zScHS8JcxitQdZcuoAhAseAYZ/KFCFC5WhoApQBRnV2AglyGCMDhZ1YtzrpdqgCxwA+w/b2wemoB
YlCMQ+zrF4Sf9sBWd1+yrw6g4QriAPMXz8C4cxdyH3fxDUq8loeeIdTWDPORY7A3tqgDyK5ANQkF
AN6ywQD7Ay/MzqOg0SiW7t1GdPIDv6UZAOIk1FCGEoDE+bYcd+PP1CS4pWDyxNoBRGWopREpASgl
glYASSNSasU7Rt+CmFL9fEMAA70Id7eJeaWtmK8E2TDKqfIg+9TZZOmtTH/m54DaMu0/AHtTqu3S
UAgLN66A+zWXUpUPIx5ANo7VHG1gX3kcxw3q+iARTqTrk0yA0PVR+j8ise5neSoSOn6YCBC6fpqJ
S023j9MN1Lsm1b9qWLIw6P4tOAAAAABJRU5ErkJggg==
{
const auth = httpClient.createAuthSettingOAuth2(
'Google',
'https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force',
'https://accounts.google.com/o/oauth2/token',
'gmail',
'consumer_key',
'consumer_secret',
'access_token'
);
configs.putObject('conf_auth', auth);
configs.put('conf_label', label);
};
/**
* ラベル一覧 を取得する GET リクエストのテスト
* @param {Object} request
* @param request.url
* @param request.method
*/
const assertGetLabelListRequest = ({url, method}) => {
expect(url).toEqual('https://gmail.googleapis.com/gmail/v1/users/me/labels');
expect(method).toEqual('GET');
};
/**
* メール一覧を取得する GET リクエストのテスト
* @param {Object} request
* @param request.url
* @param request.method
* @param labelIds
* @param limit
* @param timestampLowerLimit
*/
const assertGetMessageListRequest = ({url, method}, labelIds, limit, timestampLowerLimit) => {
let expectedUrl = 'https://gmail.googleapis.com/gmail/v1/users/me/messages'
+ `?maxResults=${limit}`;
labelIds.forEach(labelId => {
expectedUrl += `&labelIds=${labelId}`;
});
const q = `newer: ${Math.floor(timestampLowerLimit.getTime() / 1000)}`;
expectedUrl += `&q=${encodeURIComponent(q)}`;
expectedUrl = expectedUrl.replace(/%20/g, '+'); // HttpRequestWrapper#queryParam() はスペースを + に置き換える;
expect(url).toEqual(expectedUrl);
expect(method).toEqual('GET');
};
/**
* メールを取得する GET リクエストのテスト
* @param {Object} request
* @param request.url
* @param request.method
* @param messageId
*/
const assertGetMessageRequest = ({url, method}, messageId) => {
const expectedUrl = `https://gmail.googleapis.com/gmail/v1/users/me/messages/${messageId}`
+ '?format=metadata';
expect(url).toEqual(expectedUrl);
expect(method).toEqual('GET');
};
/**
* 返り値の message のテスト
* @param message
* @param id
* @param timestamp
* @param rfc822msgId
*/
const assertMessage = (message, id, timestamp, rfc822msgId) => {
expect(message.id).toEqual(id);
expect(message.timestamp).toEqual(timestamp);
expect(message.rfc822msgId).toEqual(rfc822msgId);
};
const DATETIME_FORMAT = 'yyyy-MM-dd\'T\'HH:mm:ssX';
const LABEL_LIST_RES = {
"labels": [
{
"id": "CHAT",
"name": "CHAT",
"messageListVisibility": "hide",
"labelListVisibility": "labelHide",
"type": "system"
},
{
"id": "SENT",
"name": "SENT",
"type": "system"
},
{
"id": "INBOX",
"name": "INBOX",
"type": "system"
},
{
"id": "IMPORTANT",
"name": "IMPORTANT",
"messageListVisibility": "hide",
"labelListVisibility": "labelHide",
"type": "system"
},
{
"id": "TRASH",
"name": "TRASH",
"messageListVisibility": "hide",
"labelListVisibility": "labelHide",
"type": "system"
},
{
"id": "DRAFT",
"name": "DRAFT",
"type": "system"
},
{
"id": "SPAM",
"name": "SPAM",
"messageListVisibility": "hide",
"labelListVisibility": "labelHide",
"type": "system"
},
{
"id": "CATEGORY_FORUMS",
"name": "CATEGORY_FORUMS",
"messageListVisibility": "hide",
"labelListVisibility": "labelHide",
"type": "system"
},
{
"id": "CATEGORY_UPDATES",
"name": "CATEGORY_UPDATES",
"messageListVisibility": "hide",
"labelListVisibility": "labelHide",
"type": "system"
},
{
"id": "CATEGORY_PERSONAL",
"name": "CATEGORY_PERSONAL",
"messageListVisibility": "hide",
"labelListVisibility": "labelHide",
"type": "system"
},
{
"id": "CATEGORY_PROMOTIONS",
"name": "CATEGORY_PROMOTIONS",
"messageListVisibility": "hide",
"labelListVisibility": "labelHide",
"type": "system"
},
{
"id": "CATEGORY_SOCIAL",
"name": "CATEGORY_SOCIAL",
"messageListVisibility": "hide",
"labelListVisibility": "labelHide",
"type": "system"
},
{
"id": "STARRED",
"name": "STARRED",
"type": "system"
},
{
"id": "UNREAD",
"name": "UNREAD",
"type": "system"
},
{
"id": "Label_1234567",
"name": "ラベル 1",
"type": "user"
},
{
"id": "Label_2345678",
"name": "ラベル 2",
"type": "user"
},
{
"id": "Label_3456789",
"name": "ラベル 3",
"type": "user"
}
]
};
const MESSAGE_METADATA_1 = {
"id": "abc123",
"payload": {
"headers": [
{
"name": "From",
"value": "from@example.com"
},
{
"name": "To",
"value": "to@example.com"
},
{
"name": "Message-ID",
"value": "rfc822msgId-1234567"
},
{
"name": "Subject",
"value": "メール 1 の件名"
}
]
},
"internalDate": "1661482800000" // 2022-08-26T12:00:00+09:00
};
const MESSAGE_METADATA_2 = {
"id": "def456",
"payload": {
"headers": [
{
"name": "From",
"value": "from@example.com"
},
{
"name": "To",
"value": "to@example.com"
},
{
"name": "Message-ID",
"value": "rfc822msgId-4567890"
},
{
"name": "Subject",
"value": "メール 2 の件名"
}
]
},
"internalDate": "1660100400000" // 2022-08-10T12:00:00+09:00
};
const MESSAGE_METADATA_3 = {
"id": "efg789",
"payload": {
"headers": [
{
"name": "From",
"value": "from@example.com"
},
{
"name": "To",
"value": "to@example.com"
},
{
"name": "Message-ID",
"value": "rfc822msgId-7890123"
},
{
"name": "Subject",
"value": "メール 3 の件名"
}
]
},
"internalDate": "1659322800000" // 2022-08-01T12:00:00+09:00
};
const SAMPLE_MESSAGE_LIST_RES = {
"messages": [
{
"id": "abc123"
},
{
"id": "def456"
},
{
"id": "efg789"
}
]
};
const MESSAGE_DETAILS = [
MESSAGE_METADATA_1,
MESSAGE_METADATA_2,
MESSAGE_METADATA_3
];
/**
* 正常系のテストケース
* ラベルを 1 つだけ指定した場合
*/
test('Success - one label', () => {
const label = 'ラベル 1';
const labelIds = ['Label_1234567'];
prepareConfigs(label);
const limit = 3;
const timestampLowerLimit = dateFormatter.parse(DATETIME_FORMAT, '2022-08-01T00:00:00+09:00');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertGetLabelListRequest(request);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(LABEL_LIST_RES));
}
if (reqCount === 1) {
assertGetMessageListRequest(request, labelIds, limit, timestampLowerLimit);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(SAMPLE_MESSAGE_LIST_RES));
}
// message ごとにリクエスト
const messageCount = reqCount-2;
assertGetMessageRequest(request, SAMPLE_MESSAGE_LIST_RES.messages[messageCount].id);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(MESSAGE_DETAILS[messageCount]));
});
const result = list(limit, timestampLowerLimit);
expect(result.length).toEqual(3);
// 一覧取得のままの順序で返る
assertMessage(result[0],
'abc123',
dateFormatter.parse(DATETIME_FORMAT, '2022-08-26T12:00:00+09:00'),
'rfc822msgId-1234567'
);
assertMessage(result[1],
'def456',
dateFormatter.parse(DATETIME_FORMAT, '2022-08-10T12:00:00+09:00'),
'rfc822msgId-4567890'
);
assertMessage(result[2],
'efg789',
dateFormatter.parse(DATETIME_FORMAT, '2022-08-01T12:00:00+09:00'),
'rfc822msgId-7890123'
);
});
/**
* 正常系のテストケース
* ラベルを指定しなかった場合
*/
test('Success - no label', () => {
prepareConfigs('');
const limit = 2;
const timestampLowerLimit = dateFormatter.parse(DATETIME_FORMAT, '2022-08-01T00:00:00+09:00');
const messageListRes = {
"messages": [ // limit が 2 の場合、2件までしか返らない
{
"id": "abc123"
},
{
"id": "def456"
}
]
};
const messageDetails = [
MESSAGE_METADATA_1,
MESSAGE_METADATA_2
];
let reqCount = 0;
httpClient.setRequestHandler((request) => {
// ラベル一覧取得のリクエストはなし。
if (reqCount === 0) {
assertGetMessageListRequest(request, ['INBOX'], limit, timestampLowerLimit);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(messageListRes));
}
// message ごとにリクエスト
const messageCount = reqCount-1;
assertGetMessageRequest(request, messageListRes.messages[messageCount].id);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(messageDetails[messageCount]));
});
const result = list(limit, timestampLowerLimit);
expect(result.length).toEqual(2);
// 一覧取得のままの順序で返る
assertMessage(result[0],
'abc123',
dateFormatter.parse(DATETIME_FORMAT, '2022-08-26T12:00:00+09:00'),
'rfc822msgId-1234567'
);
assertMessage(result[1],
'def456',
dateFormatter.parse(DATETIME_FORMAT, '2022-08-10T12:00:00+09:00'),
'rfc822msgId-4567890'
);
});
/**
* 正常系のテストケース
* ラベルを複数件指定した場合
*/
test('Success - more than one labels', () => {
// ラベルを改行区切りで複数件、空行や前後に空白をふくめて指定する
const label = `ラベル 3
INBOX
STARRED
ラベル 2
ラベル 1`;
const labelIds = [ // LABEL_LIST_RES に含まれる順になる
'INBOX',
'STARRED',
'Label_1234567',
'Label_2345678',
'Label_3456789'
];
prepareConfigs(label);
const limit = 3;
const timestampLowerLimit = dateFormatter.parse(DATETIME_FORMAT, '2022-08-01T00:00:00+09:00');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertGetLabelListRequest(request);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(LABEL_LIST_RES));
}
if (reqCount === 1) {
assertGetMessageListRequest(request, labelIds, limit, timestampLowerLimit);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(SAMPLE_MESSAGE_LIST_RES));
}
// message ごとにリクエスト
const messageCount = reqCount-2;
assertGetMessageRequest(request, SAMPLE_MESSAGE_LIST_RES.messages[messageCount].id);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(MESSAGE_DETAILS[messageCount]));
});
const result = list(limit, timestampLowerLimit);
expect(result.length).toEqual(3);
// 一覧取得のままの順序で返る
assertMessage(result[0],
'abc123',
dateFormatter.parse(DATETIME_FORMAT, '2022-08-26T12:00:00+09:00'),
'rfc822msgId-1234567'
);
assertMessage(result[1],
'def456',
dateFormatter.parse(DATETIME_FORMAT, '2022-08-10T12:00:00+09:00'),
'rfc822msgId-4567890'
);
assertMessage(result[2],
'efg789',
dateFormatter.parse(DATETIME_FORMAT, '2022-08-01T12:00:00+09:00'),
'rfc822msgId-7890123'
);
});
/**
* 正常系のテストケース
* プロセス開始済みのメールは一覧から除かれる
*/
test('Success - filtered by isProcessStarted', () => {
const label = 'ラベル 1';
const labelIds = ['Label_1234567'];
prepareConfigs(label);
const limit = 3;
const timestampLowerLimit = dateFormatter.parse(DATETIME_FORMAT, '2022-08-01T00:00:00+09:00');
engine.addProcessStartedSet('def456'); // 2 件目のメールをプロセス開始済みにセット
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertGetLabelListRequest(request);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(LABEL_LIST_RES));
}
if (reqCount === 1) {
assertGetMessageListRequest(request, labelIds, limit, timestampLowerLimit);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(SAMPLE_MESSAGE_LIST_RES));
}
// 1 件目、3件目のメールのみ詳細取得のリクエストが送付される
if (reqCount === 2) {
assertGetMessageRequest(request, SAMPLE_MESSAGE_LIST_RES.messages[0].id);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(MESSAGE_DETAILS[0]));
}
assertGetMessageRequest(request, SAMPLE_MESSAGE_LIST_RES.messages[2].id);
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(MESSAGE_DETAILS[2]));
});
const result = list(limit, timestampLowerLimit);
expect(result.length).toEqual(2); // 2件のみ
// 一覧取得のままの順序で返る
assertMessage(result[0],
'abc123',
dateFormatter.parse(DATETIME_FORMAT, '2022-08-26T12:00:00+09:00'),
'rfc822msgId-1234567'
);
assertMessage(result[1],
'efg789',
dateFormatter.parse(DATETIME_FORMAT, '2022-08-01T12:00:00+09:00'),
'rfc822msgId-7890123'
);
});
/**
* 正常系のテストケース
* timestampLowerLimit より前のメールは一覧から除かれる
*/
test('Success - filtered by timestampLowerLimit', () => {
const label = 'ラベル 1';
const labelIds = ['Label_1234567'];
prepareConfigs(label);
const limit = 3;
// 1 件目のメールのみプロセス開始対象となるように timestampLowerLimit を設定
const timestampLowerLimit = dateFormatter.parse(DATETIME_FORMAT, '2022-08-10T12:00:01+09:00');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertGetLabelListRequest(request);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(LABEL_LIST_RES));
}
if (reqCount === 1) {
assertGetMessageListRequest(request, labelIds, limit, timestampLowerLimit);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(SAMPLE_MESSAGE_LIST_RES));
}
// message ごとにリクエスト
const messageCount = reqCount-2;
assertGetMessageRequest(request, SAMPLE_MESSAGE_LIST_RES.messages[messageCount].id);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(MESSAGE_DETAILS[messageCount]));
});
const result = list(limit, timestampLowerLimit);
expect(result.length).toEqual(1); // 1件のみ
assertMessage(result[0],
'abc123',
dateFormatter.parse(DATETIME_FORMAT, '2022-08-26T12:00:00+09:00'),
'rfc822msgId-1234567'
);
});
/**
* 異常系のテストケース
* ラベル一覧を取得する GET リクエストで 403 エラー
*/
test('Fail - 403 error in getting labels', () => {
prepareConfigs('ラベル 1');
const limit = 3;
const timestampLowerLimit = dateFormatter.parse(DATETIME_FORMAT, '2022-08-01T00:00:00+09:00');
httpClient.setRequestHandler((request) => {
assertGetLabelListRequest(request);
return httpClient.createHttpResponse(403, 'application/json', JSON.stringify({}));
});
try {
list(limit, timestampLowerLimit);
fail();
} catch (e) {
expect(e.toString()).toEqual('Failed to get labels. status: 403');
}
});
/**
* 異常系のテストケース
* 存在しないラベルを指定した場合
*/
test('Fail - label does not exist', () => {
const label = `IMPORTANT
存在しないラベル 1
存在しないラベル 2`;
prepareConfigs(label);
const limit = 3;
const timestampLowerLimit = dateFormatter.parse(DATETIME_FORMAT, '2022-08-01T00:00:00+09:00');
httpClient.setRequestHandler((request) => {
assertGetLabelListRequest(request);
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(LABEL_LIST_RES));
});
try {
list(limit, timestampLowerLimit);
fail();
} catch (e) {
expect(e.toString()).toEqual('label ids of 存在しないラベル 1, 存在しないラベル 2 not found');
}
});
/**
* 異常系のテストケース
* メッセージ一覧を取得する GET リクエストで 403 エラー
*/
test('Fail - 403 error in getting messages', () => {
const label = 'ラベル 1';
const labelIds = ['Label_1234567'];
prepareConfigs(label);
const limit = 3;
const timestampLowerLimit = dateFormatter.parse(DATETIME_FORMAT, '2022-08-01T00:00:00+09:00');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertGetLabelListRequest(request);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(LABEL_LIST_RES));
}
assertGetMessageListRequest(request, labelIds, limit, timestampLowerLimit);
return httpClient.createHttpResponse(403, 'application/json', JSON.stringify({}));
});
try {
list(limit, timestampLowerLimit);
fail();
} catch (e) {
expect(e.toString()).toEqual('Failed to get messages. status: 403');
}
});
/**
* 異常系のテストケース
* メッセージの詳細を取得する GET リクエストで 403 エラー
*/
test('Fail - 403 error in getting a message', () => {
const label = 'ラベル 1';
const labelIds = ['Label_1234567'];
prepareConfigs(label);
const limit = 3;
const timestampLowerLimit = dateFormatter.parse(DATETIME_FORMAT, '2022-08-01T00:00:00+09:00');
let reqCount = 0;
httpClient.setRequestHandler((request) => {
if (reqCount === 0) {
assertGetLabelListRequest(request);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(LABEL_LIST_RES));
}
if (reqCount === 1) {
assertGetMessageListRequest(request, labelIds, limit, timestampLowerLimit);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(SAMPLE_MESSAGE_LIST_RES));
}
if (reqCount === 2) { // 1 つ目のメッセージ詳細を取得
assertGetMessageRequest(request, SAMPLE_MESSAGE_LIST_RES.messages[0].id);
reqCount++;
return httpClient.createHttpResponse(200, 'application/json', JSON.stringify(MESSAGE_METADATA_1));
}
// 2 つ目のメッセージ詳細の取得で失敗
assertGetMessageRequest(request, SAMPLE_MESSAGE_LIST_RES.messages[1].id);
return httpClient.createHttpResponse(403, 'application/json', JSON.stringify({}));
});
try {
list(limit, timestampLowerLimit);
fail();
} catch (e) {
expect(e.toString()).toEqual('Failed to get message def456. status: 403');
}
});
]]>