Script (click to open)
- 次のスクリプトが記述されている XML ファイルをダウンロードできます
- gmail-message-received.xml (C) Questetra, Inc. (MIT License)
- コードの参考用にご利用ください
- アドオンとしてワークフローアプリにインポートすることはできません
/** * @typedef {Object} timestamp java.sql.Timestamp オブジェクト */ /** 日時フォーマッター */ const datetimeFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX"); /** * configs から必要な情報の取り出し * @returns {Object} setting 設定 * @returns {AuthSettingWrapper} setting.auth OAuth2 認証設定 * @returns {Array} setting.labels ラベル一覧 */ const prepare = () => { const auth = configs.getObject('conf_auth'); let label = configs.get('conf_label'); let labels = []; if (label !== null && label !== '') { labels = label.split('\n') .map(label => label.trim()) .filter(label => label !== ''); } return { auth, labels }; }; /** * 追加されたメールの検索 * @param {Number} limit 取得上限数 * @param timestampLowerLimit timestamp の下限 * @returns {Array} messages メッセージ一覧 * @returns {string} messages[].id Gmail Message ID * @returns {timestamp} messages[].timestamp メール受信時刻 * @returns {string} messages[].rfc822msgId RFC 822 Message-ID */ const list = (limit, timestampLowerLimit) => { const {auth, labels} = prepare(); let labelIds = ['INBOX']; if (labels.length !== 0) { labelIds = getLabelIds(auth, labels); } // HTTP リクエスト数制限を考慮する limit = Math.min(limit, httpClient.getRequestingLimit() - 2); const messages = getMessages(auth, labelIds, limit, timestampLowerLimit); logMessages(messages); return messages; }; /** * メッセージ一覧のログ出力 * @param {Array} messages メッセージ一覧 */ const logMessages = (messages) => { const replacer = (key, value) => value instanceof java.sql.Timestamp ? datetimeFormatter.format(value) : value; messages.forEach(msg => engine.log(JSON.stringify(msg, replacer))); }; /** * ラベルからラベル ID を取得する * @param {AuthSettingWrapper} auth OAuth2 認証設定 * @param {Array<String>} labels ラベル一覧 * @return {Array<String>} ラベル ID の一覧 */ function getLabelIds(auth, labels) { const response = httpClient.begin() .authSetting(auth) .get('https://gmail.googleapis.com/gmail/v1/users/me/labels'); const responseJson = response.getResponseAsString(); const status = response.getStatusCode(); if (status >= 300) { const accessLog = `--- users.labels.list --- ${status}\n${responseJson}\n`; engine.log(accessLog); throw `Failed to get labels. status: ${status}`; } const json = JSON.parse(responseJson); let found = json.labels .filter(label => labels.includes(label.name)); const foundLabels = found.map(label => label.name); const notFoundLabels = labels.filter(label => !foundLabels.includes(label)); if (notFoundLabels.length > 0) { const accessLog = `--- users.labels.list --- ${status}\n${responseJson}\n`; engine.log(accessLog); // id が見つからない label がある場合、エラーをスロー throw `label ids of ${notFoundLabels.join(', ')} not found`; } return found.map(label => label.id); } /** * Gmail REST API にメール取得の GET リクエストを送信し、メッセージ一覧を返す * @param {AuthSettingWrapper} auth OAuth2 認証設定 * @param {Array<String>} labelIds ラベル ID の一覧 * @param {Number} limit 取得上限数 * @param timestampLowerLimit timestamp の下限 * @returns {Array} messages メッセージ一覧 * @returns {string} messages[].id Gmail Message ID * @returns {timestamp} messages[].timestamp メール受信時刻 * @returns {string} messages[].rfc822msgId RFC 822 Message-ID */ function getMessages(auth, labelIds, limit, timestampLowerLimit) { let request = httpClient.begin() .authSetting(auth) .queryParam('maxResults', `${limit}`); engine.log(`labelIds: ${labelIds}`); labelIds.forEach(labelId => { request = request.queryParam('labelIds', labelId); }); // 単位はミリ秒ではなく秒 const q = `newer: ${Math.floor(timestampLowerLimit.getTime() / 1000)}`; engine.log(`q: ${q}`); request = request.queryParam('q', q); const response = request .get('https://gmail.googleapis.com/gmail/v1/users/me/messages'); // when error thrown const responseJson = response.getResponseAsString(); const status = response.getStatusCode(); if (status >= 300) { const accessLog = `--- users.messages.list --- ${status}\n${responseJson}\n`; engine.log(accessLog); throw `Failed to get messages. status: ${status}`; } const json = JSON.parse(responseJson); if (json.messages === undefined || json.messages === null) { // 該当メッセージが無い engine.log("no messages"); return []; } return json.messages .filter(msg => !engine.isProcessStarted(msg.id)) // 既にプロセス開始済みのものを除く .map(msg => getMessage(auth, msg.id)) // id 以外の情報を取得 // 検索条件ですでに timestampLowerLimit によりフィルタしているが、 // 検索条件の対象時刻とメールの timestamp が一致しない場合が稀にあるため、再フィルタ .filter(msg => { const isOld = msg.timestamp.before(timestampLowerLimit); if (isOld) { engine.log(`excluded by timestampLowerLimit: id=${msg.id}, timestamp=${datetimeFormatter.format(msg.timestamp)}`); } return !isOld; // timestampLowerLimit 以前のものを除外 }); } /** * Gmail REST API にメール取得の GET リクエストを送信し、internalDate 等を取得する * @param {AuthSettingWrapper} auth OAuth2 認証設定 * @param id {String} メッセージ ID * @return {Object} message メッセージ * @returns {string} message.id Gmail Message ID * @returns {timestamp} message.timestamp メール受信時刻 * @returns {string} message.rfc822msgId RFC 822 Message-ID */ function getMessage(auth, id) { const response = httpClient.begin() .authSetting(auth) .queryParam('format', 'metadata') .get(`https://gmail.googleapis.com/gmail/v1/users/me/messages/${id}`); const responseJson = response.getResponseAsString(); const status = response.getStatusCode(); if (status >= 300) { const accessLog = `--- users.messages.get --- ${status}\n${responseJson}\n`; engine.log(accessLog); throw `Failed to get message ${id}. status: ${status}`; } const json = JSON.parse(responseJson); const msgIdHeader = json.payload.headers.find(h => h.name.toLowerCase() === 'message-id'); const rfc822msgId = msgIdHeader !== undefined ? msgIdHeader.value : ''; return { id: json.id, timestamp: new java.sql.Timestamp(Number(json.internalDate)), rfc822msgId }; }

開始: Gmail: メール受信時
Start: Gmail: Email Message Received
このアイテムは、Gmail が新しいメールを受信すると、プロセスを開始します。
Basic Configs
- 工程名
- メモ
Configs for this Auto Step
- conf_auth
- C1: OAuth2 設定 *
- conf_label
- C2: ラベル (空白の場合、受信トレイ)
- conf_idData
- C3: メール ID を保存するデータ項目 *
- conf_timestampData
- C4: 受信時刻を保存するデータ項目
- conf_rfc822msgIdData
- C5: RFC 822 Message-ID ヘッダを保存するデータ項目
Notes
- 本モデリング要素は Google Workspace アカウント用であり、一般ユーザー向けアカウント(gmail.com)での利用はできません
- 事前準備として、Google Workspace の管理者権限を持つユーザーにより管理コンソールにて対象の OAuth アプリが信頼できるアプリとして設定されている必要があります
- この設定が完了していなければ、本モデリング要素は動作しません
- 本モデリング要素が使用する OAuth アプリのクライアント ID は 13039123046-t87nmrj499ffoa58asehks3asajvgqnh.apps.googleusercontent.com です
- アプリリリース後、定期的に Questetra BPM Suite から Gmail にポーリングが行われます
- ポーリングの状況は、[プロセスログ]より確認できます
- 初回のポーリング時にはプロセスは開始されず、チェックのみ行われます
- 指定されたラベルが付けられているメールがチェック対象となります
- Gmail の[ラベル]機能を利用して、プロセス開始すべきメールにラベルが付与されるように運用します
- [C2: ラベル ]にて複数のラベルが指定されている場合、指定されているすべてのラベルが付けられているメールがチェックの対象となります
- ユーザーが作成したラベルだけでなく、INBOX、UNREAD、STARRED などのシステムラベルも指定できます
- システムラベルの一覧は Gmail API のガイドに掲載されています
- 1回のポーリングでは対象となるラベルが付いているメ-ルのうち、新しいものから一定数のメールに対してチェックが行われます
- チェックされたメールのうち、プロセスが開始されてないものについてプロセスが開始されます
- 指定されたラベルがついていればプロセス開始済みであってもチェックの対象に含まれます
- メールからラベルが削除されるとチェック対象から除外されます
- 自動工程[Gmail: メールのラベルを解除]
- ラベルが削除されることで、Gmail のメールボックスで「Questetra に取り込み済み」であることを確認できるようになります
- メールからラベルが削除されるとチェック対象から除外されます
- 短時間に多数のメールを受信すると、一定数以上のメールについてはチェック対象とならず、プロセスは開始されません
- 目安は、3 分 ~ 15 分間で 90 プロセスです
- プロセスが開始されなかったメールでも、以降のポーリングでチェック対象となればプロセス開始されます
Capture

See also
Script (click to open)
- 次のスクリプトが記述されている XML ファイルをダウンロードできます
- gmail-message-received.xml (C) Questetra, Inc. (MIT License)
- コードの参考用にご利用ください
- アドオンとしてワークフローアプリにインポートすることはできません
/** * @typedef {Object} timestamp java.sql.Timestamp オブジェクト */ /** 日時フォーマッター */ const datetimeFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX"); /** * configs から必要な情報の取り出し * @returns {Object} setting 設定 * @returns {AuthSettingWrapper} setting.auth OAuth2 認証設定 * @returns {Array} setting.labels ラベル一覧 */ const prepare = () => { const auth = configs.getObject('conf_auth'); let label = configs.get('conf_label'); let labels = []; if (label !== null && label !== '') { labels = label.split('\n') .map(label => label.trim()) .filter(label => label !== ''); } return { auth, labels }; }; /** * 追加されたメールの検索 * @param {Number} limit 取得上限数 * @param timestampLowerLimit timestamp の下限 * @returns {Array} messages メッセージ一覧 * @returns {string} messages[].id Gmail Message ID * @returns {timestamp} messages[].timestamp メール受信時刻 * @returns {string} messages[].rfc822msgId RFC 822 Message-ID */ const list = (limit, timestampLowerLimit) => { const {auth, labels} = prepare(); let labelIds = ['INBOX']; if (labels.length !== 0) { labelIds = getLabelIds(auth, labels); } // HTTP リクエスト数制限を考慮する limit = Math.min(limit, httpClient.getRequestingLimit() - 2); const messages = getMessages(auth, labelIds, limit, timestampLowerLimit); logMessages(messages); return messages; }; /** * メッセージ一覧のログ出力 * @param {Array} messages メッセージ一覧 */ const logMessages = (messages) => { const replacer = (key, value) => value instanceof java.sql.Timestamp ? datetimeFormatter.format(value) : value; messages.forEach(msg => engine.log(JSON.stringify(msg, replacer))); }; /** * ラベルからラベル ID を取得する * @param {AuthSettingWrapper} auth OAuth2 認証設定 * @param {Array<String>} labels ラベル一覧 * @return {Array<String>} ラベル ID の一覧 */ function getLabelIds(auth, labels) { const response = httpClient.begin() .authSetting(auth) .get('https://gmail.googleapis.com/gmail/v1/users/me/labels'); const responseJson = response.getResponseAsString(); const status = response.getStatusCode(); if (status >= 300) { const accessLog = `--- users.labels.list --- ${status}\n${responseJson}\n`; engine.log(accessLog); throw `Failed to get labels. status: ${status}`; } const json = JSON.parse(responseJson); let found = json.labels .filter(label => labels.includes(label.name)); const foundLabels = found.map(label => label.name); const notFoundLabels = labels.filter(label => !foundLabels.includes(label)); if (notFoundLabels.length > 0) { const accessLog = `--- users.labels.list --- ${status}\n${responseJson}\n`; engine.log(accessLog); // id が見つからない label がある場合、エラーをスロー throw `label ids of ${notFoundLabels.join(', ')} not found`; } return found.map(label => label.id); } /** * Gmail REST API にメール取得の GET リクエストを送信し、メッセージ一覧を返す * @param {AuthSettingWrapper} auth OAuth2 認証設定 * @param {Array<String>} labelIds ラベル ID の一覧 * @param {Number} limit 取得上限数 * @param timestampLowerLimit timestamp の下限 * @returns {Array} messages メッセージ一覧 * @returns {string} messages[].id Gmail Message ID * @returns {timestamp} messages[].timestamp メール受信時刻 * @returns {string} messages[].rfc822msgId RFC 822 Message-ID */ function getMessages(auth, labelIds, limit, timestampLowerLimit) { let request = httpClient.begin() .authSetting(auth) .queryParam('maxResults', `${limit}`); engine.log(`labelIds: ${labelIds}`); labelIds.forEach(labelId => { request = request.queryParam('labelIds', labelId); }); // 単位はミリ秒ではなく秒 const q = `newer: ${Math.floor(timestampLowerLimit.getTime() / 1000)}`; engine.log(`q: ${q}`); request = request.queryParam('q', q); const response = request .get('https://gmail.googleapis.com/gmail/v1/users/me/messages'); // when error thrown const responseJson = response.getResponseAsString(); const status = response.getStatusCode(); if (status >= 300) { const accessLog = `--- users.messages.list --- ${status}\n${responseJson}\n`; engine.log(accessLog); throw `Failed to get messages. status: ${status}`; } const json = JSON.parse(responseJson); if (json.messages === undefined || json.messages === null) { // 該当メッセージが無い engine.log("no messages"); return []; } return json.messages .filter(msg => !engine.isProcessStarted(msg.id)) // 既にプロセス開始済みのものを除く .map(msg => getMessage(auth, msg.id)) // id 以外の情報を取得 // 検索条件ですでに timestampLowerLimit によりフィルタしているが、 // 検索条件の対象時刻とメールの timestamp が一致しない場合が稀にあるため、再フィルタ .filter(msg => { const isOld = msg.timestamp.before(timestampLowerLimit); if (isOld) { engine.log(`excluded by timestampLowerLimit: id=${msg.id}, timestamp=${datetimeFormatter.format(msg.timestamp)}`); } return !isOld; // timestampLowerLimit 以前のものを除外 }); } /** * Gmail REST API にメール取得の GET リクエストを送信し、internalDate 等を取得する * @param {AuthSettingWrapper} auth OAuth2 認証設定 * @param id {String} メッセージ ID * @return {Object} message メッセージ * @returns {string} message.id Gmail Message ID * @returns {timestamp} message.timestamp メール受信時刻 * @returns {string} message.rfc822msgId RFC 822 Message-ID */ function getMessage(auth, id) { const response = httpClient.begin() .authSetting(auth) .queryParam('format', 'metadata') .get(`https://gmail.googleapis.com/gmail/v1/users/me/messages/${id}`); const responseJson = response.getResponseAsString(); const status = response.getStatusCode(); if (status >= 300) { const accessLog = `--- users.messages.get --- ${status}\n${responseJson}\n`; engine.log(accessLog); throw `Failed to get message ${id}. status: ${status}`; } const json = JSON.parse(responseJson); const msgIdHeader = json.payload.headers.find(h => h.name.toLowerCase() === 'message-id'); const rfc822msgId = msgIdHeader !== undefined ? msgIdHeader.value : ''; return { id: json.id, timestamp: new java.sql.Timestamp(Number(json.internalDate)), rfc822msgId }; }
