Outlook 連携 - kintone から Outlook スケジュールを登録しよう

目次

caution
警告

はじめに

kintone から Outlook のスケジュールを登録できるサンプルです。

Outlook スケジュールの「イベントタイトル」「開始日時」「終了日時」「詳細内容」「添付ファイル」を kintone から登録できます。
また、kintone のレコードを変更した場合や、レコードを削除した場合にも、Outlook のイベントも更新されます。

Outlook のイベントを変更した場合は、kintone のレコードには反映されません。

メリットとしては、kintone に登録したレコードの内容をイベントとして Outlook のスケジュールに登録し共有できることです。
また、kintone のプロセス管理機能を使用してステータスを管理できます。

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

サンプルコードは SAMPLE-kintone-connect-azure (External link) に公開しています。

概要

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

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

  • kintone から OAuth 認証を用いて Entra ID V2 Endpoint へサインイン
  • kintone から Azure へアクセストークンを取得
  • アクセストークンを使って Graph API をたたく。
  • kintone からデータを Outlook スケジュールに登録

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

kintone アプリの作成

kintone アプリストア (External link) にある「 To Do (External link) 」アプリを使います。
アプリに以下のフィールドを追加してください。

フィールド名 フィールドタイプ フィールドコード
イベントID 文字列(1行) EventId

また、アプリストアの「To Do」アプリは「開始日」「終了日」が「日付」フィールドとなっているため、「日時」フィールドに変更してください。

フィールド名 フィールドタイプ フィールドコード
開始日時 日時 From
終了日時 日時 To

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

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

下準備

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

  1. Microsoft アカウントを取得します。
  2. 1 で取得したアカウントで Azure Portal (External link) へログインします。

アプリケーションの登録

Outlook 連携 - kintone から Outlook メールの送受信をしよう Microsoft Entra ID アプリケーションの登録 を参考に作成します。

今回使用するプログラムの準備

サンプルプログラム一式

SAMPLE-kintone-connect-azure (External link) にプログラムを置いています。

入手方法
  1. https://github.com/kintone-samples/SAMPLE-kintone-connect-azure/releases/tag/1.1.0 (External link) へアクセスします。
  2. [Assets]の「Source code(zip)」をクリックし、zip ファイルをダウンロードします。
  3. ファイルを解凍します。
利用するプログラムファイル
common-js-functions.min.js

共通処理を記述するプログラムです。
common ディレクトリー内にあります。

kintone-connect-outlook-schedule-common.js

kintone アプリ/Microsoft アプリの設定を記述するプログラムです。
環境に合わせて修正する部分があります(後述)。
outlook-schedule ディレクトリー内にあります。

oauth.js

OAuth2.0 を利用して Azure への認証処理を行うプログラムです。
common ディレクトリー内にあります。

kintone-connect-outlook-schedule.js

アクセストークンを用いて Outlook へスケジュールデータの登録/更新/削除するプログラムです。
outlook-schedule ディレクトリー内にあります。

kintone JS SDK v0.7.0

kintone REST API を便利に扱うことができるライブラリです。
詳しくは kintone JS SDK を参照してください。

入手方法
  1. 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 を設置する

入手方法
  1. kintone-labs/kintone-ui-component v0.4.2 (External link) にアクセスします。
  2. 「Assets」の[Source code]をクリックし、zip ファイルをダウンロードします。
  3. ファイルを解凍し、dist 下の「kintone-ui-component.min.js」「kintone-ui-component.min.css」を利用します。

その他のライブラリ

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

  • 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-schedule-common.js を修正します。

プログラムの 7 行目を アプリケーションの登録 でメモしておいたアプリケーション ID に変更してください。
kintone アプリのフィールドコードが kintone アプリの作成 に記載したフィールドコードと異なる場合には、25 行目〜41 行目を修正してください。

 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
// kintone-connect-outlook-schedule-common.js

window.kintoneAzureConnect = {

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

  graphApiScorp: {
    scopes: ['calendars.readwrite'],
  },

  eventUrl: 'https://graph.microsoft.com/v1.0/me/events',

  kintone: {
    fieldCode: {

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

      // Field code of body
      body: 'Details',

      // Field code of start
      startDate: 'From',

      // Field code of end
      endDate: 'To',

      // Field code of eventId
      eventId: 'EventId',

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

プログラムの配置

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

プログラムの解説

Azure への認証処理 (oauth.js

Azure との認証部分の処理をまとめています。

 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
// oauth.js

/* global Msal */
(function() {
  'use strict';

  var KAC = window.kintoneAzureConnect;

  var azureOauth = {

    userAgentApplication: null,

    getUserInfo: function() {
      return this.userAgentApplication.getAccount().userName;
    },

    init: function() {
      var self = this;
      self.userAgentApplication = new Msal.UserAgentApplication(KAC.config);
    },

    signIn: function() {
      var self = this;
      return self.userAgentApplication.loginPopup(KAC.graphApiScorp);
    },

    signOut: function() {
      var self = this;
      self.userAgentApplication.logout();
    },

    callGraphApi: function() {
      var self = this;
      return self.userAgentApplication.acquireTokenSilent(KAC.graphApiScorp);
    }
  };

  window.azureOauth = azureOauth || {};
}());

kintone イベントの処理 (kintone-connect-outlook-schedule.js

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

レコード一覧画面を表示した後のイベント
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
  kintone.events.on('app.record.index.show', function(event) {

    kintoneScheduleService.init();

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

    // init process
    outlookAPI.init();

    // click sign in button
    kintoneScheduleService.data.ui.btnSignIn.on('click', function() {
      outlookAPI.signIn();
    });

    // click sign out button
    kintoneScheduleService.data.ui.btnSignOut.on('click', function() {
      outlookAPI.signOut();
    });
  });
レコード詳細画面を表示した後のイベント
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
  kintone.events.on('app.record.detail.show', function(event) {
    var record = event.record;

    kintoneScheduleService.init();
    kintoneScheduleService.uicreateForDetail();

    kintoneScheduleService.data.ui.btnSendEvent.on('click', function() {
      // Confirm whether to execute
      Swal.fire({
        title: kintoneScheduleService.setting.i18n.message.info.confirmRegister,
        type: 'warning',
        confirmButtonColor: '#DD6B55',
        confirmButtonText: kintoneScheduleService.setting.i18n.button.registerExec,
        cancelButtonText: kintoneScheduleService.setting.i18n.button.cancelExec,
        showCancelButton: 'true',
        allowOutsideClick: false
      }).then(function(isConfirm) {
        if (isConfirm.value) {
          return kintoneScheduleService.checkDateTime(record).then(function(isAllDay) {
            outlookAPI.setDataForRegistration(record, isAllDay);
          }, function() {
            KC.ui.loading.hide();
          });
        }
      }, function(dismiss) {
        KC.ui.loading.hide();
      });
    });
  });
レコード作成/編集画面を表示した後のイベント
801
802
803
804
805
806
807
808
809
810
  kintone.events.on(['app.record.create.show',
    'app.record.edit.show', 'app.record.index.edit.show'], function(event) {
    var record = event.record;
    if (event.type === 'app.record.create.show') {
      record[EVENT_ID_FIELD_CODE].value = '';
    }
    record[EVENT_ID_FIELD_CODE].disabled = true;

    return event;
  });
レコードの保存に成功した後のイベント
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
  kintone.events.on('app.record.edit.submit.success', function(event) {
    var record, eventId;
    record = event.record;

    kintoneScheduleService.init();

    if (record[EVENT_ID_FIELD_CODE] === undefined) {
      return event;
    }

    eventId = record[EVENT_ID_FIELD_CODE].value;
    if (eventId === '' || !kintoneScheduleService.isExpireAccessToken()) {
      return event;
    }

    return new kintone.Promise(function(resolve, reject) {
      Swal.fire({
        title: kintoneScheduleService.setting.i18n.message.info.confirmUpdate,
        type: 'warning',
        confirmButtonColor: '#DD6B55',
        confirmButtonText: kintoneScheduleService.setting.i18n.button.updateExec,
        cancelButtonText: kintoneScheduleService.setting.i18n.button.cancelExec,
        showCancelButton: 'true',
        allowOutsideClick: false
      }).then(function(isConfirm) {
        if (isConfirm.dismiss === 'cancel') {
          event.error = 'ダメです';
          return event;
        }
        return kintone.Promise.all([kintoneScheduleService.checkDateTime(record), outlookAPI.getToOutlook(record)]);
      }).then(function(respdata) {
        if (respdata.type === 'app.record.edit.submit.success') {
          return resolve(event);
        }
        return outlookAPI.setDataForUpdate(record, respdata[0]);
      }).then(function() {
        resolve(event);
      }).catch(function(error) {
        return Swal.fire({
          title: 'Error!',
          type: 'error',
          text: kintoneScheduleService.setting.i18n.message.error.updateFailure,
          allowOutsideClick: false
        }).then(function() {
          KC.ui.loading.hide();
          resolve(event);
        });
      });
    });
  });
レコードを削除する前のイベント
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
  kintone.events.on('app.record.detail.delete.submit', function(event) {
    var record = event.record;
    var eventId = record[EVENT_ID_FIELD_CODE].value;
    if (!kintoneScheduleService.isExpireAccessToken() || eventId === '') {
      return event;
    }

    return new kintone.Promise(function(resolve, reject) {
      Swal.fire({
        title: kintoneScheduleService.setting.i18n.message.info.confirmDelete,
        type: 'warning',
        confirmButtonColor: '#DD6B55',
        confirmButtonText: kintoneScheduleService.setting.i18n.button.deleteExec,
        cancelButtonText: kintoneScheduleService.setting.i18n.button.cancelExec,
        showCancelButton: 'true',
        allowOutsideClick: false
      }).then(function(isConfirm) {
        if (isConfirm.dismiss === 'cancel') {
          return resolve(false);
        }
        return outlookAPI.getToOutlook(record);
      }).then(function(respdata) {
        if (respdata === undefined) {
          KC.ui.loading.hide();
          return resolve(false);
        }
        return outlookAPI.setDataForDelete(record);
      }).then(function(resp) {
        resolve(event);
      }).catch(function() {
        Swal.fire({
          title: 'Error!',
          type: 'error',
          text: kintoneScheduleService.setting.i18n.message.error.deleteFailure,
          allowOutsideClick: false
        }).then(function() {
          KC.ui.loading.hide();
          resolve(true);
        });
      });
    });
  });

Outlook モジュール (kintone-connect-outlook-schedule.js

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

MSAL.js のインスタンス化

userAgentApplication としてインスタンス化し、以降の処理に利用します。
oauth.js の処理を呼び出しています。

327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
  var outlookAPI = {

    init: function() {

      AO.init();
      if (!kintoneScheduleService.isExpireAccessToken() || !kintoneScheduleService.isSignUserDispInfo()) {
        kintoneScheduleService.data.ui.kintoneCustomizeOutlookHeaderNotSigned.style.display = 'inline-block';
        kintoneScheduleService.data.ui.kintoneCustomizeOutlookHeaderSigned.style.display = 'none';
      } else {
        kintoneScheduleService.data.ui.kintoneCustomizeOutlookUserInfo.setText(storage.getItem('SIGN_USER_DISPINFO'));
        kintoneScheduleService.data.ui.kintoneCustomizeOutlookHeaderNotSigned.style.display = 'none';
        kintoneScheduleService.data.ui.kintoneCustomizeOutlookHeaderSigned.style.display = 'inline-block';
        kintoneScheduleService.data.ui.kintoneCustomizeOutlookUserInfo.element.style.display = 'inline-block';
        kintoneScheduleService.data.isLoginOutlook = true;
      }
    },
Azureからトークンを取得する

サインイン処理では、まず Azure から ID トークンを取得します。
oauth.js の処理を呼び出しています。

344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
    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: kintoneScheduleService.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 トークンを用いてアクセストークンを取得します。

370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
    callGraphApi: function() {
      var self = this;

      AO.callGraphApi().then(function(token) {
        var userInfo = AO.getUserInfo();

        kintoneScheduleService.data.ui.kintoneCustomizeOutlookHeaderNotSigned.style.display = 'none';
        kintoneScheduleService.data.ui.kintoneCustomizeOutlookHeaderSigned.style.display = 'inline-block';
        kintoneScheduleService.data.ui.kintoneCustomizeOutlookUserInfo.setText(userInfo);
        kintoneScheduleService.data.ui.kintoneCustomizeOutlookUserInfo.element.style.display = 'inline-block';
        kintoneScheduleService.data.isLoginOutlook = true;

        storage.setItem('SESSION_KEY_TO_ACCESS_TOKEN', token.accessToken);
        storage.setItem('SIGN_USER_DISPINFO', userInfo);

        KC.ui.loading.hide();
      }, function(error) {
        if (error) {
          Swal.fire({
            title: 'Error!',
            type: 'error',
            text: kintoneScheduleService.setting.i18n.message.error.getAccessTokenFailure,
            allowOutsideClick: false
          });
          self.userAgentApplication = null;
          KC.ui.loading.hide();
        }
      }).then(function() {
        KC.ui.loading.hide();
      }).catch(function() {
        KC.ui.loading.hide();
      });
    },
取得したアクセストークンを用いたスケジュールデータの登録

GraphAPI を kintone 上で叩いて Outlook のスケジュールデータを登録しています。
外部 API を kintone 上でたたく方法は 外部の API を実行する を参照してください。

516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
    registerToOutlookForAttachement: function(index, file, eventId, accessToken) {
      var self = this;
      var url = EVENT_URL + '/' + eventId + '/attachments';
      var header = {
        'Authorization': 'Bearer ' + accessToken,
        'Content-Type': 'application/json'
      };

      return kintone.proxy(url, 'POST', header, file[index]).then(function(respdata) {
        var responseDataJson = window.JSON.parse(!respdata[0] ? '{}' : respdata[0]);
        if (typeof responseDataJson.error !== 'undefined') {
          throw responseDataJson;
        }

        if (index + 1 < file.length) {
          self.registerToOutlookForAttachement(index + 1, file, eventId, accessToken);
        }
      });
    },

動作確認

kintone アプリのレコード一覧画面を開きます。
「Outlook にログイン」というボタンが表示されるので、ボタンをクリックします。

OAuth 認証画面が表示されるので、「Microsoft Entra ID アプリケーションの登録」の 下準備 で準備した Microsoft アカウントでログインします。

メールアドレスを入力したあとにエラーが表示される場合、Microsoft アプリの設定を確認してください。

ログインに成功した場合、先ほどまで「Outlook にログイン」だったボタンが「Outlook からログアウト」に変わります。

kintone のレコードを追加します。

レコードを保存すると、レコード詳細画面の上部に「予定を登録」というボタンが表示されるので、ボタンをクリックすればイベントを登録できます。

無事 kintone のレコードの内容が Outlook のスケジュールに登録されました。

変更履歴

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

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