GmailのメールをAIで要約してビヨンドトークへ自動投稿するワークフロー

GmailのメールをAIで要約してビヨンドトークへ自動投稿するワークフロー

2026年6月30日 (最終更新 2026年6月30日)

取引先とのメールのやり取りを、AIが自動で要約して自社アプリ「ビヨンドウェブ」のトークに投稿する仕組みを、ノーコードで作成しました。 受信箱を開かなくても、チーム全員が状況を把握できます。 今回はGmailですが、同じ仕組みでLINEやSlackの内容もトークに自動投稿できます。 プログラミングの知識がなくても、コピペと設定だけで動かせます。

この記事でできること

取引先とのメールのやり取りを、AIが自動で要約して、社内チャットに投稿してくれる仕組みを作ります。プログラミングの知識がなくても、手順どおりにコピペ+設定するだけで動かせます。

たとえば、こんな投稿が自動で流れてきます。

【相手・受信】展示会の御礼
・◯日14時に本社訪問の依頼
・訪問者は2名予定

【自分のアクション】
・◯日14時に訪問する旨を返信

受信したメールも、自分が送ったメールも、会社ごとにまとまってチャットに残ります。受信箱を開かなくても、チーム全員が状況を把握できるようになります。

なぜ便利なのか

メールは「担当者の受信箱の中」に閉じてしまいがちです。その結果、

  • チームに状況が共有されない

  • 担当者が休むと経緯がわからない

  • 「あの件どうなった?」が口頭頼み

この仕組みは、そんな“メールの中に埋もれた情報”を、自動でチームの見える場所に出してくれます。

仕組みをざっくり

登場するのは2つの道具です。

  • GAS(ガス):Gmailを5分おきに見張る「見張り役」。新しいメールを見つけて次に渡します。(Googleの無料ツール)

  • Dify(ディファイ):渡されたメールを「要約して、どこに投稿するか決めて、実際に投稿する」までやる「判断役」。(AIを組み込めるノーコードツール)

「見張りはGAS、判断はDify」と覚えればOKです。下の2枚の図が全体像です。

gas_mihari_flow
dify_handan_flow

はじめる前の準備

作り始める前に、次を用意します。特に③のコンタクト登録が、この仕組みの“要”です。

  1. Difyのアカウントと、AIを使うためのAPIキー(OpenAIなど)

  2. Googleアカウント(GASを動かすため/Gmailを見張るため)

  3. CRM(コンタクト)に取引先を登録しておく最重要

    • この仕組みは、CRMにメールアドレスが登録されている取引先とのメールだけを自動投稿します。

    • 逆に言うと、登録していない相手のメールは投稿されません(私的なメールや迷惑メールが自動で除外される、という安全装置にもなります)。

    • なので「チャットに流したい取引先は、先にCRMのコンタクトに登録しておく」必要があります。

  4. 管理者アカウント(チャットやCRMのデータを操作するため)

ポイント:コンタクト登録=この仕組みの“通行許可証”です。登録されている相手だけが通れます。

かんたん用語集

  • API:道具どうしが会話するための“窓口”。

  • トークン:その窓口に入るための“一時的な合言葉”。

  • ノード:Difyで並べる“処理のブロック”。線でつなぐと流れになります。

  • トリガー:GASを「5分おきに自動で動かす」ためのタイマー。


① Dify(判断役)を組み立てる

Difyは、ブロック(ノード)を並べて線でつなぐだけで作れます。コードが出てくる場所もありますが、中身は分からなくてOK。コピペして貼るだけです。

1. 入口を用意する(受け取る情報)

GASから渡される情報の“受け皿”を作ります。次の6つを登録します。

  • メールの向き(受信か送信か)

  • 相手のメールアドレス

  • 件名

  • 本文

  • メールのまとまりを表すID

  • 前回の投稿先 (任意)

2. ブロックを順番につなぐ

上から下へ、この順で並べます。

  1. ログイン:チャット側の合言葉(トークン)をもらう

  2. トークン取り出し:もらった合言葉を取り出す(コピペのコード)

  3. CRM照合:相手がCRMに登録されているか調べる

  4. 一致確認:登録されていれば“会社”を特定(コピペのコード)

  5. 判定A:登録されていなければ、ここで終了(投稿しない)

  6. 判定B:すでに投稿先が分かっている続きの会話なら、振り分けをスキップ

  7. トピック一覧取得:その会社の“開いている”投稿先を取得

  8. 振り分け(AI):既存の場所に足すか、新しく作るかをAIが判断

  9. 判定パース:AIの答えを整える(コピペのコード)

  10. 判定C:新規なら「新しい投稿先を作る」へ

  11. 新規作成:新しい投稿先を作る

  12. 新規ID取り出し:作った投稿先の番号を取り出す(コピペのコード)

  13. 集約:投稿先を1つに決める

  14. 要約(AI):投稿用に短くまとめる(受信/送信で書き分け)

  15. 投稿:チャットに投稿する

  16. 終了:投稿した/しなかった

3. コードのブロックは「コピペするだけ」

4か所に小さなコードを貼ります。意味を理解する必要はありません。 ただし1つだけ約束ごとがあります。

入力の名前と、コードの中の名前をそろえること。 たとえば入力を body という名前にしたら、コードも body を使います。1文字でも違うと動きません。

トークン取り出し(入力名:body

def main(body: str) -> dict:

import json

    return { "token": json.loads(body)["access_token"] }


一致確認(入力名:records_json / target

def main(records_json: str, target: str) -> dict:

import json

    try:

data = json.loads(records_json)

    except Exception:

return { "matched": 0, "company_id": 0 }

t = (target or "").strip().lower()

for c in data.get("records", []):

  if (c.get("email") or "").strip().lower() == t and c.get("company_id"):

return { "matched": 1, "company_id": c["company_id"] }

return { "matched": 0, "company_id": 0 }

判定パース(入力名:llm_text

def main(llm_text: str) -> dict:

import json, re

try:

m = re.search(r"\{.*\}", llm_text, re.S)

d = json.loads(m.group(0)) if m else { }

    except Exception:

d = {}

return {

  "action": d.get("action", "append"),

  "topic_id": int(d.get("topic_id") or 0),

  "new_title": d.get("new_title") or "",

}


新規ID取り出し(入力名:body

def main(body: str) -> dict:

import json

    try:

return { "new_topic_id": int(json.loads(body).get("id", 0)) }

    except Exception:

return { "new_topic_id": 0 }

4. AIへの指示(プロンプト)

  • 振り分け:「件名・本文と、候補の一覧を見て、既存に足すか・新しく作るかを答えて」と指示。似た話題なら既存へ、明らかに別件なら新規。

  • 要約:受信なら「相手の要点・依頼・期限」、自分の送信なら「自分が何を返信・提案したか」を箇条書きで。

5. いちばん大事な“最後のひと手間”

作り終えたら、必ず**「公開」ボタンを押す**こと。Difyは「公開した状態」で動くので、直しても公開しないと反映されません。「直したのに動かない」の9割はこれです。


② GAS(見張り役)を設定する

1. プロジェクトを作る

Googleの「Apps Script(script.google.com)」で新規プロジェクトを作ります。

2. DifyのAPIキーを取得

Difyで作ったワークフローを公開し、「APIアクセス」から APIキーapp-で始まる文字列)をコピーします。

3. コードを貼り付ける(コピペ)

最初から入っている文字を全部消して、下を貼り付けます。先頭の4行だけ自分の情報に書き換えればOKです。

const DIFY_URL = 'https://api.dify.ai/v1/workflows/run';

const DIFY_KEY = 'app-xxxxxxxx';          // DifyのAPIキー

const MY_EMAIL = 'you@yourcompany.co.jp'; // 自分のメール

const MY_DOMAIN = 'yourcompany.co.jp';    // 自社のドメイン(社内を除外)

function poll() {

  const props = PropertiesService.getScriptProperties();

  const lastRun = Number(props.getProperty('lastRun') || (Date.now() - 864e5));

  const threads = GmailApp.search(in: inbox OR in: sent) after: ${ Math.floor(lastRun / 1000)
});

let newest = lastRun;

threads.forEach(thread => {

  const known = props.getProperty('map_' + thread.getId());

  thread.getMessages().forEach(msg => {

    const t = msg.getDate().getTime();

    if (t <= lastRun) return;

    if (t > newest) newest = t;

    const isSent = (msg.getFrom() || '').toLowerCase().includes(MY_EMAIL);

    const external = pickExternal([msg.getFrom(), msg.getTo(), msg.getCc()].join(','));

    if (!external) return;

    const payload = {
      inputs: {

        direction: isSent ? 'sent' : 'received',

        external_email: external,

        subject: msg.getSubject() || '',

        body: (msg.getPlainBody() || '').slice(0, 4000),

        thread_id: thread.getId(),

        known_topic_id: known ? Number(known) : 0

      }, response_mode: 'blocking', user: 'gmail-poller'
    };

    const res = UrlFetchApp.fetch(DIFY_URL, {
      method: 'post', contentType: 'application/json',

      headers: { Authorization: 'Bearer ' + DIFY_KEY }, payload: JSON.stringify(payload), muteHttpExceptions: true
    });

    const out = JSON.parse(res.getContentText());

    const topicId = out.data && out.data.outputs ? out.data.outputs.topic_id : 0;

    if (topicId > 0) props.setProperty('map_' + thread.getId(), String(topicId));

  });

});

props.setProperty('lastRun', String(newest));

}

// メールの宛先・差出人・CCから「社外の相手」を見つける(CCの取引先も拾える)

function pickExternal(s) {

  const emails = ((s || '').match(/[\w.+-]+@[\w.-]+\.[\w.-]+/g) || []).map(e => e.toLowerCase());

  return emails.find(e => (e.split('@')[1] || '') !== MY_DOMAIN) || '';

}

// 最初に1回だけ実行:過去のメールをまとめて処理しないようにする

function startFresh() {

  PropertiesService.getScriptProperties().setProperty('lastRun', String(Date.now()));

}


4. 最初の1回を実行(権限の許可)

関数を poll にして「実行」を押します。初回は Gmailを読む許可などを求められるので、画面の案内に従って許可します。過去のメールを一気に処理したくない場合は、先に startFresh を1回実行しておきます。

5. 5分おきに自動で動かす(タイマー設定)

ここが“自動化”の本体です。画面左の**時計マーク(トリガー)**を開き、「トリガーを追加」で次のように設定して保存します。

  • 実行する関数:poll

  • イベントのソース:時間主導型

  • タイプ:分ベースのタイマー

  • 間隔:5分おき

これで完成です。初回は約5分後から動き始めます(数分前後することがあります)。

6. ちゃんと動いているか確認

  • 自動実行の記録は、画面左の**「実行数」**で見られます。

  • 新しいメールが無いときは一瞬で終わります(正常です)。実際の投稿を試したいときは、CRMに登録済みの取引先と本当にメールをやり取りしてみてください。


つまずきやすいポイント

  • 直したのに反映されない → Difyで「公開」を押し忘れている

  • 403や401で止まる → 合言葉(トークン)や設定の打ち間違い。特に英単語のスペルに注意(Authorization など)

  • 何も投稿されない → 相手がCRMに未登録(=対象外。正常な動作)/新着メールがまだ無い

  • コードのブロックでエラー → 入力の名前とコードの名前がズレている

運用のコツ

  • 流したい取引先は、先にCRMのコンタクトに登録しておく(これが対象の線引き)。

  • 続きの会話は同じ場所にまとまるので、トピックが散らかりません。

  • CCの取引先や自分の送信メールも拾えます。

まとめ

メールの中に閉じた情報を、チームの見える場所へ。これをプログラミングなしで実現できます。ポイントは2つだけ。

  1. CRMに取引先を登録しておく(通行許可証)

  2. 見張り役(GAS)と判断役(Dify)を用意してつなぐ

あとは手順どおりにコピペと設定をすれば、メールが自動でチャットにまとまっていきます。


よくある質問

この商品について質問がありますか?コミュニティや専門家に質問してください。

担当者に相談する