Outlook 連携 - kintone から Outlook メールの送受信をしよう

目次

caution
警告

  • 2020年8月改訂のセキュアコーディング ガイドライン に抵触する内容が含まれています。
    認証情報が漏洩した場合の影響を考慮して慎重に検討してください。
    該当箇所:外部ライブラリ(MSAL.js)内のアクセストークン保存部分

  • このカスタマイズで利用しているkintone JS SDKは現在推奨されていません。
    今後は kintone JavaScript Clientを利用するように書き換えてください。

はじめに

MicrosoftのOutlookといえばビジネス利用でお世話になっている方も多いはず。
そのOutlookメールがkintone上で送受信できるサンプルです。

メリットとしては、メールをkintoneに取り込むことで、他のkintoneアプリとの連携がしやすくなります。
また、kintoneのプロセス管理機能を使用してステータスを管理できます。

Outlook側への認証にOAuth2.0を利用しています。
少し敷居が高く感じられるかもしれませんが、詳しい手順の解説とサンプルコードを公開していますのでぜひ参考にしてください。
詳しい手順の解説とサンプルコードを公開していますのでぜひ参考にしてください。

サンプルコードは GitHub上 (External link) に公開しています。

概要

今回の注目部分はなんといっても認証部分です!
Microsoftが提供している MSAL.js (外部サイト) (External link) を利用することで、Outlook(Microsoftアカウント)とのOAuth2.0を利用した認証をkintone上で行うことができます。

連携の流れは以下となっています。

  • kintoneからOAuth認証を用いてEntra ID V2 Endpointへサインインする。
  • kintoneからAzureへアクセストークンを取得する。
  • アクセストークンを使ってGraph APIをたたく。
  • レスポンスをkintoneのアプリに登録する。

Graph APIはMicrosoft Cloudサービスリソースへのアクセスを可能にするAPIです。

kintone アプリの作成

kintoneアプリでは以下のフィールドを配置してください。

フィールド名 フィールドタイプ フィールドコード
subject 文字列(1行) subject
contents リッチエディター contents
from 文字列(1行) from
TO 文字列(1行) TO
CC 文字列(1行) CC
BCC 文字列(1行) BCC
messageId 文字列(1行) messageId
mailAccount 文字列(1行) mailAccount
attachFile 添付ファイル attachFile

こちらがアプリの配置したフィールドのフォーム画面です。

Microsoft Entra ID アプリケーションの登録

下準備

Outlookとkintoneを連携させるため、Microsoft Entra IDへアプリケーションを登録する必要があります。
事前に以下を行ってください。

  1. Microsoftアカウントの取得
  2. 手順1. で取得したアカウントで Azure Portal (External link) へログイン

アプリケーションの登録

  1. 左メニューの「Microsoft Entra ID」を選択します。

  2. 「アプリの登録」を選択します。

  3. 「アプリケーションの登録」ボタンまたは、「新規登録」をクリックします。

  4. 次のように入力します。入力が終わったら「登録」ボタンをクリックします。

    項目
    名前 任意のアプリ名(今回は kintone×Outlookとします)
    サポートされているアカウントの種類 必要に応じて、以下のいずれかを選択します。
    • 任意の施設ディレクトリー内のアカウント(任意の Entra ID ディレクトリー・マルチテナント)
    • 任意の施設ディレクトリー内のアカウント(任意の Entra ID ディレクトリー・マルチテナント)と個人の Microsoft アカウント
    リダイレクトURL
    • 「Web」
    • 先ほど作成した kintone アプリの URL
  5. 作成したアプリケーションで、「認証」メニューを選択します。
    「暗黙の付与」の「アクセストークン」と「IDトークン」にチェックを入れ、「保存」ボタンをクリックします。

  6. アプリケーションIDは、作成したアプリケーションの「概要」メニューで確認できます。
    kintoneに適用するカスタマイズファイルで利用するので、メモしておいてください。

以上で登録は完了です。

認証時のリクエストにアクセス権のスコープを含めているため、アプリ登録画面での「Microsoft Graphのアクセス許可」の設定は不要です。

プログラムの説明

今回使用するプログラム

  • SAMPLE-kintone-connect-azure (External link)
    サンプルプログラム一式です。

  • 利用するプログラムファイル

    • common-js-functions.min.js
      • 共通処理を記述するプログラムです。
      • commonディレクトリー内にあります。
    • kintone-connect-outlook_mail_common.js
      • kintoneアプリ/Microsoftアプリの設定を記述するプログラムです。
      • 環境に合わせて修正する部分があります(後述)
      • outlook-mailディレクトリー内にあります。
    • OAuth.js
      • OAuth2.0を利用してAzureへの認証処理を行うプログラムです。
      • commonディレクトリー内にあります。
    • kintone-connect-outlook_mail.js
      • アクセストークンを用いてOutlookからメールデータを取得するプログラムです。
      • outlook-mailディレクトリー内にあります。
  • kinotne JS SDK (External link) v0.7.0
    kintone REST APIを便利に扱うことができるライブラリです。
    詳しくは kintone JS SDK を参照してください。

    • 入手方法
      1. https://github.com/kintone-labs/kintone-js-sdk (External link) にアクセスします。
      2. [Clone or download]ボタンをクリックし、zipファイルをダウンロードします。
      3. ファイルを解凍し、「dist」下の「kintone-js-sdk.min.js」を利用します。
  • kintone UI Component (External link) v0.4.2
    kintoneライクなUIパーツを簡単に作成できるライブラリです。
    詳しくは、 「kintone UI Component v0」を使って簡単にkintoneライクなUIを設置するを参照してください。

また、今回は上記プログラム以外にライブラリとして以下を利用します。

  • MSAL.js
    AzureからOAuth認証でアクセストークンを取得するプログラムです。
    • https://secure.aadcdn.microsoftonline-p.com/lib/1.0.0/js/msal.js
  • jQuery v3.4.1
    • https://js.cybozu.com/jquery/3.4.1/jquery.min.js
  • Sweet Alert2 v8.17.6
    • https://js.cybozu.com/sweetalert2/v8.17.6/sweetalert2.min.js
    • https://js.cybozu.com/sweetalert2/v8.17.6/sweetalert2.min.css

プログラムの修正

kintone-connect-outlook_mail_common.jsを修正します。

  • アプリケーションの登録の手順6. でメモしておいたアプリケーションID(7行目)を変更してください。
  • kintoneアプリのフィールドコードが kintone アプリの作成に記載したフィールドコードと異なる場合には、28行目〜53行目を修正してください。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// kintone-connect-outlook_mail_common.js

window.kintoneAzureConnect = {

  config: {
    auth: {
      clientId: '####################',
      authority: 'https://login.microsoftonline.com/common'
    },
    cache: {
      cacheLocation: 'localStorage',
      storeAuthStateInCookie: true
    }
  },

  graphApiScorp: {
    scopes: ['mail.read', 'mail.send']
  },

  mail: {
    mailGetUrl: 'https://graph.microsoft.com/v1.0/me/messages?$top=100',
    mailSendUrl: 'https://graph.microsoft.com/v1.0/me/sendmail'
  },

  kintone: {
    fieldCode: {

      // Field code of subject
      subject: 'subject',

      // Field code of content
      content: 'contents',

      // Field code of from
      from: 'from',

      // Field code of to
      to: 'TO',

      // Field code of cc
      cc: 'CC',

      // Field code of bcc
      bcc: 'BCC',

      // Field code of messageId
      messageId: 'messageId',

      // Field code of mailAccount
      mailAccount: 'mailAccount',

      // Field code of attachFile
      attachFile: 'attachFile'
    }
  }
};

プログラムの配置

これらのプログラムを「アプリの設定 > JavaScript/CSSでカスタマイズ」下に配置します。

プログラムの解説

kintoneイベントの処理(kintone-connect-outlook_mail.js)

kintoneの各イベント処理は以下となっています。

レコード一覧画面表示イベント

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
kintone.events.on('app.record.index.show', (event) => {

  kintoneMailService.init();

  /* create kintone ui */
  kintoneMailService.uiCreateForIndex(kintone.app.getHeaderSpaceElement());

  // 初期処理
  outlookAPI.init();

  // Singinボタン押下時
  kintoneMailService.data.ui.btnSignIn.on('click', () => {
    outlookAPI.signIn();
  });

  // Singoutボタン押下時
  kintoneMailService.data.ui.btnSignOut.on('click', () => {
    outlookAPI.signOut();
  });

  // GET MAILボタン押下時
  kintoneMailService.data.ui.btnGetmail.on('click', () => {
    outlookAPI.getMail();
  });
});

レコード詳細画面表示イベント

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
kintone.events.on('app.record.detail.show', (event) => {
  const record = event.record;

  kintoneMailService.init();

  /* create kintone ui */
  kintoneMailService.uicreateForDetail();

  // SEND MAILボタン押下時
  kintoneMailService.data.ui.btnSendmail.on('click', () => {
    outlookAPI.sendMailInit(record);
  });
});

レコード作成/編集画面表示イベント

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
kintone.events.on('app.record.create.show', (event) => {
  const record = event.record;
  kintone.app.record.setFieldShown(MESSAGE_ID_FIELD_CODE, false);
  kintone.app.record.setFieldShown(MAIL_ACCOUNT_FIELD_CODE, false);
  record[FROM_FIELD_CODE].disabled = true;
  record[FROM_FIELD_CODE].value = storage.getItem('SIGN_USER_MAILACCOUNT');
  return event;
});

// レコード編集画面の表示時
kintone.events.on('app.record.edit.show', (event) => {
  const record = event.record;
  kintone.app.record.setFieldShown(MESSAGE_ID_FIELD_CODE, false);
  kintone.app.record.setFieldShown(MAIL_ACCOUNT_FIELD_CODE, false);
  record[FROM_FIELD_CODE].disabled = true;
  return event;
});
Outlookモジュール ( kintone-connect-outlook_mail.js )

kintoneとOutlookのコネクション部分を一部抜粋して説明します。

MSAL.jsのインスタンス化

userAgentApplicationとしてインスタンス化し、以降の処理に利用します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const outlookAPI = {

  // 初期処理
  init: function() {

    AO.init();
    if (!kintoneMailService.isExpireAccessToken() || !kintoneMailService.isSignUserDispInfo()) {
      kintoneMailService.data.ui.kintoneCustomizeOutlookHeaderNotSigned.style.display = 'inline-block';
      kintoneMailService.data.ui.kintoneCustomizeOutlookHeaderSigned.style.display = 'none';
    } else {
      kintoneMailService.data.ui.kintoneCustomizeOutlookHeaderNotSigned.style.display = 'none';
      kintoneMailService.data.ui.kintoneCustomizeOutlookHeaderSigned.style.display = 'inline-block';
      kintoneMailService.data.ui.kintoneCustomizeOutlookUserInfo.setText(storage.getItem('SIGN_USER_MAILACCOUNT'));
      kintoneMailService.data.mail.profile.emailAddress = storage.getItem('SIGN_USER_MAILACCOUNT');
      kintoneMailService.data.isLoginOutlook = true;
    }
  }
};

Azureからトークンを取得する

サインイン処理では、まずAzureからIDトークンを取得します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    signIn: function() {
      var self = this;
      KC.ui.loading.show();

      AO.signIn().then(function(id_token) {
        self.callGraphApi();
        KC.ui.loading.hide();
      }, function(error) {
        Swal.fire({
          title: 'Error!',
          type: 'error',
          text: kintoneMailService.setting.i18n.message.error.signInFailure,
          allowOutsideClick: false
        });
        KC.ui.loading.hide();
      });
    },

    signOut: function() {
      KC.ui.loading.show();
      storage.clear();
      AO.signOut();
      KC.ui.loading.hide();
    },

そして取得したIDトークンを用いてアクセストークンを取得します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    callGraphApi: function() {
      var self = this;

      AO.callGraphApi().then(function(token) {

        var userInfo = AO.getUserInfo();

        // 「getMail」「signout」ボタンを表示
        kintoneMailService.data.ui.kintoneCustomizeOutlookHeaderNotSigned.style.display = 'none';
        kintoneMailService.data.ui.kintoneCustomizeOutlookHeaderSigned.style.display = 'inline-block';
        kintoneMailService.data.ui.kintoneCustomizeOutlookUserInfo.setText(userInfo);
        kintoneMailService.data.mail.profile.emailAddress = userInfo;
        kintoneMailService.data.isLoginOutlook = true;

        // セッションに入れておく
        storage.setItem('SESSION_KEY_TO_ACCESS_TOKEN', token.accessToken);
        storage.setItem('SIGN_USER_MAILACCOUNT', userInfo);

        KC.ui.loading.hide();

      }, function(error) {
        if (error) {
          Swal.fire({
            title: 'Error!',
            type: 'error',
            text: kintoneMailService.setting.i18n.message.error.getAccessTokenFailure,
            allowOutsideClick: false
          });
          self.userAgentApplication = null;
          KC.ui.loading.hide();
        }
      }).catch(function() {
        KC.ui.loading.hide();
      });
    },

取得したアクセストークンを用いてメールデータを取得する

GraphAPIをkintone上で叩いてOutlookのメールデータを取得しています。
外部APIをkintone上でたたく方法は 外部の API を実行するを確認してください。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
    getMail: function() {
      var self = this;
      var accessToken;
      var header;
      KC.ui.loading.show();

      if (kintoneMailService.isExpireAccessToken()) {
        accessToken = storage.getItem('SESSION_KEY_TO_ACCESS_TOKEN');
      } else {
        KC.ui.loading.hide();
        return;
      }

      header = {
        'Authorization': 'Bearer ' + accessToken,
        'Content-Type': 'application/json',
        'outlook.body-content-type': 'html'
      };

      // OutlookのINBOXからメール取得
      kintone.proxy(MAIL_GET_URL, 'GET', header, {}).then(function(res) {
        var data = JSON.parse(res[0]).value;
        if (data === undefined) {
          Swal.fire({
            title: 'ERROR!',
            type: 'error',
            text: kintoneMailService.setting.i18n.message.error.accessOutlookFailure,
            allowOutsideClick: false
          });
          KC.ui.loading.hide();
          return;
        }

        // 受信箱にメールが存在しない場合
        if (data.length === 0) {
          Swal.fire({
            title: 'WARN!',
            type: 'warning',
            text: kintoneMailService.setting.i18n.message.warning.noMail,
            allowOutsideClick: false
          });
          KC.ui.loading.hide();
          return;
        }

        // 取得したメールをkintoneへ登録
        self.putMailToKintoneApp(0, data, accessToken).catch(function(err) {
          Swal.fire({
            title: 'ERROR!',
            type: 'error',
            text: kintoneMailService.setting.i18n.message.error.addKintoneRecordFailure,
            allowOutsideClick: false
          });
          KC.ui.loading.hide();
        });
      }, function(err) {
        Swal.fire({
          title: 'ERROR!',
          type: 'error',
          text: kintoneMailService.setting.i18n.message.error.getOutlookMailFailure,
          allowOutsideClick: false
        });
        KC.ui.loading.hide();
      });
    },

    // 取得したメールをkintoneへ登録
    putMailToKintoneApp: function(index, data, accessToken) {
      var self = this;

      return this.getMessageIDIndexIsNotRetrived(index, data).then(function(indexMessage) {

        if (indexMessage === null) {
          return indexMessage;
        }
        // まだ未取得のメールを登録
        return self.addMailIntoKintone(data[indexMessage], accessToken).then(function(result) {
          // Process next mail
          if (indexMessage + 1 < data.length) {
            return self.putMailToKintoneApp(indexMessage + 1, data, accessToken);
          }
          return null;
        });
      }).then(function(resp) {
        window.location.reload();
        KC.ui.loading.hide();
      });
    }

動作確認

kintoneアプリのレコード一覧画面に『Sign In Outlook』というボタンが表示されるので、ボタンをクリックします。

Microsoft Entra ID アプリケーションの登録録で準備したMicrosoftアカウントを使ってログインします。

メールアドレスを入力したあとにエラーが表示される場合、Microsoftアプリの設定が間違っている可能性はあります。
もう一度設定内容を確認してください。

ログインに成功した場合、先ほどまで『Sign In Outlook』だったボタンが『Receive Mail』『Sign out』に変わります。

『Receive Mail』ボタンをクリックすることで、Graph APIにリクエストを投げてレスポンス(メールデータ)をkintoneのレコードに登録します。

無事、Outlookのメールがkintoneに登録されました。

すでに取得済み(kintoneに登録済み)のメールは登録されません。

次に、送信の確認をします。

kintoneのレコード追加を選択し、必要な部分を記入します。

本文はkintoneのリッチエディターフィールドを利用しているので、文字色や文字サイズの変更などもできます。

レコードを保存すると、レコード詳細画面の上部に『Send Mail』というボタンが表示されるので、ボタンをクリックすればメールを送信できます。

きちんとメールが送信できたことを確認できます。

おわりに

いかがでしょうか。

Microsoftアプリの設定を事前にしておけば、kintone上だけでOutlookのメール確認ができてしまいます!

今回はOutlookメールのみの紹介でしたが、Graph APIの項目によってスケジュールやその他の機能と連携できます。

変更履歴

  • 2019/11/18
    • 以下の変更に伴い、ソースコードを修正しました。
      • 利用ライブラリの変更
        • kintone Utility Library for JavaScript → kintone JS SDK
        • kintone UI Componentを追加
      • jQuery v3.2。ゼロからv3.4.1に変更
      • SweetAlert2 v6.10。ゼロからv8.17.6に変更
      • Microsoft Graph vゼロからv2に変更
information

このTipsは、2019年11月版kintoneで動作を確認しています。