開始: Gmail: メール受信時 (Start: Gmail: Email Message Received)
Gmail が新しいメールを受信すると、プロセスを開始します。
Configs
  • C1: OAuth2 設定 *
  • C2: ラベル (空白の場合、受信トレイ)
  • C3: メール ID を保存するデータ項目 *
  • C4: 受信時刻を保存するデータ項目
  • C5: RFC 822 Message-ID ヘッダを保存するデータ項目

Notes

  • 本モデリング要素は Google Workspace アカウント用です。一般ユーザー向けアカウント(gmail.com)での利用はできません。
  • 事前準備として、Google Workspace の管理者が対象の OAuth アプリを信頼できるアプリとして設定済みである必要があります。この設定がなされていない状態での利用はできません。
    • 本モデリング要素が使用する OAuth アプリのクライアント ID は 13039123046-t87nmrj499ffoa58asehks3asajvgqnh.apps.googleusercontent.com です。
  • ユーザーが作成したラベルだけでなく、INBOX、UNREAD、STARRED などのシステムラベルも指定できます。システムラベルの一覧は Gmail API のガイドに掲載されています。
  • 定期的に Questetra BPM Suite から Gmail にポーリングが行われ、新着メールがないかチェックされます。新着メールがあれば、プロセスが開始されます。
  • 初回のチェック時には、プロセスは開始されません。チェックのみ行われます。チェックの状況は、プロセスログより確認できます。
  • 短時間に多数のメールを受信すると、全てのメールについて、プロセスは開始されません。目安は、15 分間で 90 プロセスです。

Capture

See also

Appendix

  • gmail-message-received.xml (C) Questetra, Inc. (MIT License)
    • アドオンとしてワークフローアプリにインポートすることはできません
    • コードの参考用にご利用ください
Script (click to open)

/**
 * @typedef {Object} timestamp java.sql.Timestamp オブジェクト
 */

/** 日時フォーマッター */
const dateFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");

/**
 * configs から必要な情報の取り出し
 * @returns {Object} setting 設定
 * @returns {string} setting.auth HTTP 認証設定
 * @returns {Array} setting.labels ラベル一覧
 */
const prepare = () => {
    const auth = configs.get('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 ? dateFormatter.format(value) : value;
    messages.forEach(msg => engine.log(JSON.stringify(msg, replacer)));
};

/**
 * ラベルからラベル ID を取得する
 * @param {String} auth 認証設定
 * @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 {String} auth 認証設定
 * @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(`lavelIds: ${labelIds}`);
    labelIds.forEach(labelId => {
        request = request.queryParam('labelIds', labelId);
    });
    // 時刻は Sent が対象なので、余裕を持たせて、timestampLowerLimit の 1 日前の時刻から
    // 単位はミリ秒ではなく秒
    const q = `newer: ${Math.floor(timestampLowerLimit.addDays(-1).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 以外の情報を取得
        .filter(msg => !msg.timestamp.before(timestampLowerLimit)); // timestamp が下限より前のものを除く
}

/**
 * Gmail REST API にメール取得の GET リクエストを送信し、internalDate 等を取得する
 * @param auth {String} auth 認証設定
 * @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
    };
}

    
%d人のブロガーが「いいね」をつけました。