cybozu developer network

カテゴリー内の他の記事

添付ファイル付きのGmailメッセージをkintoneに自動的にアップロード

(Author : Fuji Business International Mamoru Fujinoki)

はじめに

外部からの問い合わせメールをkintoneに記録して管理するには、こちらの記事にあるようにZapier等のサービスを利用すれば、コードなしでも実現できます。
しかしながら、添付ファイルが送られて来た場合に、そういったサービスだけでは添付ファイルをkintoneにアップロードする機能はサポートされておらず、対処しきれません。
今回は、Google Apps Script (以下GAS)を使って、定期的にGmailに送られて来たメールの内容と添付ファイルをkintoneに記録するアプリの作成をします。
この方法を用いれば、例えば、ウェブサイトの問い合わせフォームの送信先をGmailに設定すれば、問い合わせの内容を添付ファイルも含め自動的にkintoneへ記録管理することが可能になります。

1. 事前に必要なもの

  • Googleアカウント
  • kintoneアカウント ※開発者ライセンスの取得方法はこちら

2. 開発の流れ

以上の手順で開発して行きます。

3. kintoneアプリの作成

ステップ1

kintoneでメール問い合わせのアプリを作成します。
以下のテーブルおよび画像を参照して、新規アプリを作成します。

フィールドの種類 フィールド名 フィールドコード
文字列(1行) 氏名 name
文字列(1行) Eメール email
文字列(1行) 件名 subject
文字列(複数行) 内容 message
添付ファイル 添付ファイル Attachment

gasmail-21.png

 

ステップ2

フォーム保存後、「アプリの設定」タブに移動し、「APIトークン」をクリックします。

gasmail-01.png

「生成する」ボタンをクリックして、APIトークンを生成し、「レコード追加」オプションをチェックした後、「保存」ボタンをクリックして設定を保存します。

gasmail-22.png

最後に「アプリの設定」画面に戻り、「アプリを更新」ボタンをクリックして、設定を有効にします。
生成した「APIトークン」、「アプリID」(URI記載の番号)、「アプリ名」は後々コード内で使用しますので、メモしておいてください。

gasmail-23.png

 

4. Gmail APIのGASエディタの設定

ステップ1

Google.comにてログインし、Googleアプリアイコンより、Googleドライブを選択します。

gasmail-02.png

次に左上の「新規」メニューより、「その他」→「Google Apps Script」を選択します。
「Google Apps Script」がメニューにない場合、「アプリを追加」より、「Google Apps Script」を追加します。

gasmail-03.png

gasmail-19.png

GASのエディタが表示されますので、適当なプロジェクト名を入力します。

gasmail-04.png

ステップ2

kintone APIの呼び出しには、GitHubに公開されているGoogle Apps Script Library for kintoneのライブラリを使用します。
エディタのメニューより、「ライブラリ」の横の「+」ボタンを選択します。

gasmail-05.png

 

Google Apps Script Library for kintone のREADME.mdに記載されている、「Script ID (For New editor)」の値を「スクリプト ID」欄に入力し、「検索」ボタンでライブラリを検索します。
ライブラリが表示されたら、最新のバージョンを選択し、「追加」をクリックします。

画面例

これでライブラリがプロジェクトに追加されました。

ステップ3

Gmail APIを有効にします。
「リソース」メニューより、「サービス」を選択します。

gasmail-07.png

一覧より、「Gmail API」を探し、サービスを追加します。

gasmail-08.png

5. GASのコーディング

以下を参考にGASスクリプトエディタにコードを書き込みます。

コードの解説

変数の定義

複数の関数で使用する変数を最初に定義します。
domainには、下記のようにご使用のアカウントのフルドメイン名を指定します。(海外アカウントの場合、例えばUSだと{サブドメイン名}.kintone.comのように指定します。)
また、上記で作成したアプリID、APIトークン、アプリ名を指定します。

sendToKintone 関数

Google Apps Script Library for kintoneを使って、kintone API でレコードの生成を行います。
kintoneアプリの情報をapps変数にJSON形式で設定します。
appidには、上記で作成したアプリID、nameにはアプリ名、tokenには上記で生成したAPIトークンを設定します。また、ライブラリの初期化の際は、このapps変数、およびdomain変数を指定します。

getGmailMessage関数

Gmailのメッセージデータを取得し、kintoneへ送信するレコードを生成します。

指定した件名で添付ファイル付の未読のすべてのメッセージのスレッドを取得します。
検索の条件のクエリーは、画面のようにGmailの検索画面にて検索オプション表示し、条件設定した後、検索すると表示されるので、これをコピーしてコード内に設定します。

gasmail-26.png

gasmail-25.png

取得したスレッドの全てのメッセージを取得します。
次に個々のメッセージをループし、送信するレコードのデータを取得してJSON形式のレコードを生成します。
※未読を含むスレッド内のメールすべてを取得しているため、個々のメッセージが未読であるかのチェックを行います。

添付ファイルを取得します。
「uploadAttachment」関数でファイルをkintoneにアップロードし、その際に返される「FileKey」を設定します。

メッセージ処理後は既読に設定します。

uploadAttachment関数

Gmailから取得した添付ファイルをkintoneにアップロードします。返り値として「fileKey」が返されます。
ファイルのデータはblob形式でコピーし、XMLHttpRequestを使ってmultipart/form-data形式でPOSTします。また、ヘッダーにkintoneアプリで生成したAPIトークンを設定します。

GAS内で外部APIサービスを利用するには、次の関数を用います。

replaceCharacters関数

特殊文字を変換するための関数です。
特に最初の変換は、kintoneに送るレコードがJSON形式でレコード値に「"」が含まれているとエラーが生じるため「'」に変換しています。

動作確認

ステップ1

画面のようにお使いのEメールクライアントより、Gmail宛先、返信先、件名、メッセージを入力し、添付ファイルを添えて、送信します。(「返信先」を指定しないとEメール欄が空欄となります。)

gasmail-24.png

宛先のGmailアカウントにメールが受信されました。(送信後、未読の状態を保つため、該当のGmailメッセージは開かないでください。)

gasmail-11.png

 

ステップ2

次にエディタの上部のメニューより、「sendToKintone」を選択し「実行」をクリックすると、作成したプログラムが実行されます。

gasmail-12.png

初めて実行するとGmailへの承認が要求されますので、許可し、該当のGmailアカウントを選択します。

gasmail-13.png

gasmail-15.png

以下のような警告が表示される場合がありますので、「cybozu.com(安全ではないページ)に移動」を選択してください。

gasmail-20.png

さらにアクセスするスコープを許可します。

gasmail-16.png

するとプログラムが実行され、エラーが無く、「Gメール問い合わせ」アプリに添付ファイル付でレコードが追加されていれば成功です。

gasmail-14.png

 

トリガーの設定

最後にプログラムを定期的に実行するためにトリガーを設定します。
エディタのメニューより、「トリガー」を選択します。

gasmail-17.png

 トリガーを新規に追加し、「sendToKintone」関数を指定し、1分毎にプログラムを実行します。

gasmail-18.png

 設定後、保存します。

 

注意事項

  1. 添付ファイル名に日本語が含まれている場合、kintone側で文字化けしてしまうことがあります。
  2. 上記サンプルコード内の検索クエリーをそのままお使いいただくとGmailのメッセージを複数返信した場合、添付ファイルがなくても、kintoneにレコード登録されてしまう場合がございますのでご注意ください。

 

まとめ

外部サービスからレコードを追加するには、kintone APIで比較的容易に実現できますが、添付ファイルの追加には一工夫必要となります。今回のようにGmailを介して添付ファイルをkintoneにアップロードすれば、外部からメールで送られて来た添付ファイルも容易に管理できるようになるのではないでしょうか。
今回の方法を応用すれば、メール添付ファイル以外にも様々なケースで外部からkintoneへファイルをアップロードできるようになると思います。

 

参照

Google Apps Script Library for kintone
Advanced Google Services
Google Apps Script Gmail Service
URL Fetch Service
ファイルアップロード
ファイルアップロードで必須となる3つの手順

このTipsは、2018年4月版 kintoneで確認したものになります。

記事に関するフィードバック

記事のコメント欄は記事に対するフィードバックをする場となっております。
右の記事フィードバックのためのガイドを参照してコメントしてください。
記事のリンク切れなど、気になる点がある場合も、こちらのフォームからフィードバックいただけますと幸いです。

Avatar
yui

初心者です。よろしくお願いします。
4. Gmail APIのGASエディタの設定_ステップ3に、
「次に「Google API コンソール」のリンクをクリックして、「Google API コンソール」設定画面へ移動します。」とありますが、
Google拡張サービスのGmail APIの設定画面に「これらのサービスをGoogle API コンソールで有効にする・・」のメッセージが表示されません。
別ルートで「Google API コンソール」設定画面に移動しましたが、画面上のプロジェクト名にステップ2で設定したプロジェクト名が表示されません(検索しても出てきません)
とりあえず「有効にする」をクリックして後はサンプルコードをベースにコーディングしました。
実行したところ、https://subdomain.cybozu.com/k/v1/file.json のリクエストに失敗しました(エラー: 401)になります。
上記の設定と関係しているのでしょうか?ご助言いただければ幸いです。

Avatar
cybozu Development team

yui 様

お問い合わせありがとうございます。cybozu developer network 事務局です。

GASへの拡張機能追加時に、Google API コンソール上での有効化は不要になったようです。
こちらでも確認したところ、Google API コンソール上での有効化操作をせず、ほか手順通りの操作を行うことで実行が可能でした。
yui様の環境で発生しているエラーは、別の理由かと存じます。

kintone環境へセキュアアクセスの設定を行っている場合は、外部サービスからkintoneへのAPI実行ができない場合がございます。
御社のご設定についてご確認いただけますでしょうか。

本Tipsでは、APIトークン認証を用いてkintone REST APIを実行しております。
ドキュメントに記載の通り、セキュアアクセス環境でAPIトークン認証を実行するためには、有効なクライアント証明書が必要です。

以上、ご確認よろしくお願いいたします。

Avatar
yui

ありがとうございます。 GoogleAPIコンソール上での有効化は不要という事で安心しました。

一歩?前に進めます。

セキュアアクセスの設定は行っていないので、別の原因を調べてみます。

また動けなくなってしまったら、質問させていただきます。

yui

Avatar
yui

引き続き質問させてください。

(客先)環境を確認したところ、IPアドレス制限がかかっていました。

IPアドレス制限がかかっている環境でGmailとの連携を実現する方法はありますでしょうか?

ご助言いただければ幸いです。

 

Avatar
cybozu Development team

yui 様

IPアドレス制限を設定しているkintone環境で外部サービスとの連携を行う場合、
外部サービス(本記事の場合Googleのサービス)からkintoneへアクセスするIPアドレスのアクセス許可設定が必要です。

その設定を行って問題ないか、セキュリティ等を充分にご検討頂いたうえでご設定ください。

各サービスで利用されているIPアドレスにつきましては、サービスご提供元へお問い合わせください。

以上、ご確認よろしくお願いいたします。

Avatar
yui

いつもご丁寧なご回答をありがとうございます。

五月雨式で恐縮ですがこのTIPSのようにGmailからKintoneへのレコード書き込みはI、IPアドレス制限のkintone環境では難しいようですが、他のTIPSにありますようにkintoneからGmailを読みに行く場合はIPアドレス制限のkintone環境からでも問題ないのでしょうか?基本的なことが理解不足で申し訳ありませんがよろしくお願いします。

Avatar
cybozu Development team

yui 様

IPアドレス制限は、cybozu.comへのアクセスを自社のネットワークだけに許可し、社外からのアクセスを遮断する制限です。
kintoneからGmailへアクセスする場合は、IPアドレス制限を設定しているkintone環境からでも問題ありません。

ヘルプページ:IPアドレス制限を設定する

Avatar
yui

ありがとうございます。

IPアドレス制限を設定しているkintone環境へのメール取込についてKintone側からGMailを取り込む方法に方向転換します。

数々のアドバイス、大変助かりました。本当にありがとうございました。

 

Avatar
SU

こちらの手順とおり設定し、Gmailの受信メールは問題なくkintoneに取り込まれるのですが、

取り込まれ既読となったメールも再び取り込まれる場合があります。

解決策はありますでしょうか?注意書きにあるような受信メールに返信したということはありません。

Avatar
cybozu Development team

SU 様

お世話になっております。cybozu developer network 運営でございます。

お問い合わせ頂いた現象を確認できなかったため、
初回に kintone に取り込んだメールの件数、ファイル形式、再取り込みしたメールの件数など
詳細な状況についてお伺いできますでしょうか。

 

Avatar
SU

お返事頂きありがとうございます。

本日午前中の挙動です。添付ファイルはすべてPDFです。

09:43 未読メールNo.01 レコード追加

10:23 未読メールNo.02 レコード追加

11:02 未読メールNo.03 レコード追加

11:02 未読メールNo.04 レコード追加

11:14 既読メールNo.01 レコード追加(重複)

11:14 未読メールNo.05 レコード追加

11:27 既読メールNo.03 レコード追加(重複)

11:27 既読メールNo.04 レコード追加(重複)

11:27 未読メールNo.06 レコード追加

以上となります。
メールで受信したのは、6件ですが、kintoneに取り込まれたのは重複3件を含む9件となります。

よろしくお願いいたします。

Avatar
SU

既読メールが重複して取り込まれる法則として確認できるのは、

新規のメールが届くタイミングに合わせて、既読メールが取り込まれるという点くらいです。

Avatar
cybozu Development team

SU 様

お世話になっております。cybozu developer network 運営でございます。

詳細にご報告くださりありがとうございます。

PDF を添付し、複数件のパターンでテストしたのですが、該当の挙動を確認できませんでした。
大変申し訳ありませんが、本プログラムのバグではなく、何らかの要因で gmail 側で未読になってしまっている可能性が考えられます。

その他に考えられる内容としては、kintone にレコードを登録する際に時間がかかり、該当の挙動が発生している可能性が考えられます。
容量の大きいファイルが添付されていると本現象が発生する可能性がございます。

この場合は、トリガーの実行間隔を30分にするなどの対応をお願い致します。

よろしくお願い致します。

Avatar
SU

重複されるメールですが、

同じ送り主、かつ同じ件名の場合に重複して取り込まれることがわかりました。

例えば、

送り主A、件名「B」という新規メールを受信した場合、

これまでの、既読の

送り主A、件名「B」も一緒に取り込まれるのです。

送り主、あるいは件名が異なる場合は重複して取り込まれることはありません。

何かヒントになりませんでしょうか?

Avatar
SU

度々申し訳ありません。
送り主が異なる場合でも、件名が同じであれば、既読メールが取り込まれる場合がありました。

 

Avatar
cybozu Development team

SU様

お世話になっております。
詳細なご報告をありがとうございます。

再度確認しましたところ、こちらでも再現いたしました。

  • スレッドに未読のメールが含まれる場合
    -> スレッドに含まれるすべてのメール(既読メール含む)がkintoneへ登録される

スレッドとは:「受信者がメールに返信すると、Gmail では返信がスレッドにまとめられ、最新のメールが一番下に表示されます。」
Gmailヘルプ「メールをスレッドごとにグループ化する」より

 

お手数ですが、下記の通りコードを修正いただけますでしょうか?

  • 修正前コードの50~75行目までを、if(message.isUnread()) {}で囲む。
    ※修正後のコードでは、50行目、77行目の赤枠が追加された状態となります。

    ※本記事内のコードも修正済です。

お手数をおかけしまして大変申し訳ございません。よろしくお願いいたします。

Avatar
SU

おかげ様で解決致しました。

ありがとうございました。

Avatar
佐藤

emailが getReplyTo() では取得できていないようです。

Avatar
cybozu Development team

佐藤 様

お世話になっております。cybozu developer network 運営でございます。
返事が遅くなりまして大変申し訳ございませんでした。

「動作確認」の「ステップ1」に記載している通り、
「返信先」を指定しないとEメール欄が空欄となりますので、
getReplyTo() が実行されていないように見えると思います。

こちらではOutlookからGmailにメールを送って検証しましたが、
返信先を指定せず(デフォルト)送信した場合、emailの値が空白になります。
返信先に送信元と違うメールアドレスを指定した場合、getReplyTo()が実行れました。

どうぞご確認お願い致します。

Avatar
SU

これまで正常に動作していたのですが、

本日よりエラー表示されるようになりました。エラー内容は下記の通りです。
何が原因でしょうか?

https://*******.cybozu.com のリクエストに失敗しました(エラー: 403)。サーバー応答の一部: <!DOCTYPE html> <html> <head> <script type="text/javascript"><!-- t = new String(location.hostname).split('.'); t.splice(1, 0, 's'); s = t.jo...(応答の全文を見るには muteHttpExceptions オプションを使用してください)(行 40、ファイル「コード」)

Avatar
SU

度々申し訳ありません。
IPアドレス制限をかけたことによるエラーでした。
IPアドレス制限をしたい場合はどのような設定にすればいいのでしょうか?

Avatar
cybozu Development team

SU 様

お世話になっております。cybozu developer network 運営でございます。

IP アドレスについては、GoogleAppsScript 側の IP アドレス範囲をご指定頂く必要があります。
詳しい数値につきましては、GoogleAppsScript 側のヘルプをご確認くださいますようお願い致します。

Avatar
HY

記事の通りにやったのですが、GASのコーディングの所で保存した場合に

SyntaxError: Unexpected token :(行 10、ファイル「コード.gs」)

 

とエラーが出てうまくいきません。なんででしょうか?

10行目は

/*
* 添付ファイル付のGmailメッセージをkintoneに自動的にアップロード
* Copyright (c) 2018 Cybozu
*
* Licensed under the MIT License
*/

'use strict';
var domain = "{}.cybozu.com";
var appId = {14};

 

とアプリ番号を入れています。(「var domain = "{}」の所は実際はちゃんと入れています)

Avatar
cybozu Development team

HY 様

お世話になっております。cybozu developer network 運営でございます。

理解が間違っていましたら申し訳ありませんが、
HY 様の環境で、appIdの部分のコードは「var appId = 14;」ではなく、「var appId = {14};」と記述していますでしょうか?
その場合、「{}」を除いて「var appId = 14;」と書いていただければ、エラーが出ずに処理されると思います。

※コード例にある「{}」は、「{}」の中に情報を入力してください、という意味の記号なので、「{}」を含めて書くと文法ミスと判定されます。
※domain、apiToken、appNameも同じく、「{}」を除いてご記述ください。

分かりづらい表記で大変恐縮ですが、ご確認のほどよろしくお願いいたします。

Avatar
HY

迅速な対応ありがとうございます。

エラーは出なくなりました。

 

たびたびの質問で申し訳ないのですが、何もエラーが問題なく承認なども終わった後にKintoneのアプリを見てもレコードが追加されていませんでした。記事と同じようにやっているのでどこが違うかわかりません。エラーとかも出てないので余計に。

この場合はどこが間違っているのでしょうか。

Avatar
cybozu Development team

HY 様
お世話になっております。cybozu developer network 運営でございます。

kintoneアプリにレコードが追加されない現象について、
考えられる原因は下記のいずれかだと思いますが、ご確認頂いてもよろしいでしょうか?
ーーーーーーーーーーーーーーーーーーーーーーー
・var domain = "{}.cybozu.com"; の設定は、正しく設定されていますでしょうか。

・検索条件の部分、記事と同じく下記のように設定していますでしょうか。
 var threads = GmailApp.search('is:unread subject:(検索したい件名) has:attachment');
 ※本記事のサンプルコードでは、上記条件で取得したメールを前提に処理しているので、
  条件を変更した場合、その後の処理の変更も必要となります。

・設定して頂いた検索条件にヒットするメールは一件以上存在する、で間違いないでしょうか。
ーーーーーーーーーーーーーーーーーーーーーーー

Avatar
HY

またまた迅速な対応ありがとうございます。

 

var threads = GmailApp.search('is:unread subject:(検索したい件名) has:attachment');

この部分が間違っていて出てきていませんでした。ここを正しく修正したら。レコードが追加されました。

丁寧な説明とご対応ありがとうございます。

 

Avatar
佐野達弥

こちらのとおりに設定したと思うのですが、実行すると、

ReferenceError: fax is not defined(行 93、ファイル「コード」)

というエラーが出てしまいます。

アプリ名は「fax」です。

ご教授願えないでしょうか。

Avatar
cybozu Development team

佐藤達弥 様
お世話になっております。cybozu developer network 運営でございます。

こちらでアプリ名をサンプルコードとは別のものに変更して確認いたしましたところ、

同じエラーを再現することができませんでした。
お手数ですが、記事内「コードの解説」の「変数の定義」を再度ご確認いただけないでしょうか。

その際の技術的なご質問につきましては、ぜひ cybozu developer コミュニティ をご活用ください。
ご確認よろしくお願いいたします。

Avatar
青山昌司

お世話になっております。AppsScript内のキャプチャーとは現状違うようですが

ライブラリの追加でスクリプトIDへProject keyを入れて検索すればよいのでしょうか?

検索をしても検索できず先に進めません。

エラー:ライブラリを検索できませんでした。ID とアクセス権限を確認して、もう一度お試しください。


ご教示のほどよろしくお願いいたします。

サインインしてコメントを残してください。