kintone向けのblastengineを使ったメール送信プラグインを開発する


kintoneはサイボウズ社の提供するノーコードサービスです。業務アプリとして使われている方も多いのではないでしょうか。

そんなkintoneでは外部から操作できるAPIに加えて、アプリと連携して動作するプラグインが開発できます。今回はblastengineでメール送信を行うプラグインを開発してみました。

## 完成品

完成版のコードは [kintone-plugin](https://github.com/BlastengineMania/kintone-plugin) にアップしてあります。実装時の参考にしてください。

## ベースの作成

プラグインのベースは `create-kintone-plugin` というコマンドで作成できます。対話型でプラグインのベースになるコードを生成してくれます。

```
% npx create-kintone-plugin blastengine

  
kintoneプラグインのプロジェクトを作成するために、いくつかの質問に答えてください :)
では、はじめましょう！

  
? プラグインの英語名を入力してください [1-64文字] blastengine
? プラグインの説明を入力してください [1-200文字] Blastengine APIを使ってKintoneからメール送信を行うプラグインです
? 日本語をサポートしますか？ Yes
? プラグインの日本語名を入力してください [1-64文字] (省略可) 
? プラグインの日本語の説明を入力してください [1-200文字] (省略可) 
? 中国語をサポートしますか？ No
? プラグインの英語のWebサイトURLを入力してください (省略可) https://blastengine.jp/
? プラグインの日本語のWebサイトURLを入力してください (省略可) https://blastengine.jp/
? モバイルページをサポートしますか？ Yes
? @kintone/plugin-uploaderを使いますか？ Yes
依存ライブラリをインストールします
npm WARN deprecated puppeteer@15.5.0: < 18.1.0 is no longer supported

added 446 packages, and audited 447 packages in 29s

129 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Success! Created blastengine at blastengine

npm start

  ファイルの変更を監視してプラグインのzipを自動的に作成するプロセスを起動します
  その後、@kintone/plugin-uploaderにより、プラグインのzipは自動的にアップロードされます

npm run build

  プラグインのzipを作成します

npm run lint

  ESLintを使ってJavaScriptのソースコードをチェックします

まずは次のコマンドを実行してください
その後、あなたのkintone環境の情報を入力してください

  cd blastengine
  npm start

kintoneプラグイン開発をはじめましょう！
開発に関する情報はcybozu developer network:

  https://developer.cybozu.io
```

## kintoneに取り込む

プラグインを試すには、kintoneにプラグインをアップロードする必要があります。その際、 `npm start` でコードの変更を監視、自動でアップロードしてくれます。アップロードされたら、kintoneのシステム管理＞プラグインにてプラグインが読み込まれているのが確認できるでしょう。

![blastengine-kintone-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/bac564d6-4823-9a9c-3c61-b8eaaaa1f964.jpeg)


### アプリへの追加

続いて、kintoneアプリにてプラグインを読み込みます。アプリの設定＞プラグインにて **プラグインの追加** をクリックします。

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/76d4ed17-4244-9b94-3c1a-4a2271b3e353.png)


アップロードしたプラグインを選択して、追加ボタンを押します。

![Untitled.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/c89ad657-8478-621a-0ebd-aff65a94b5ac.jpeg)


これで準備は完了です。

## プラグインの開発

ここからはblastengineプラグインの開発時において修正した部分を解説します。

### 設定画面（config.html）

プラグインの設定画面では、以下の4項目を設定できるようにしました。これはプラグインのベースをカスタマイズしただけです。

- APIキー
- ユーザー名
- 送信元名
- 送信元アドレス

![Untitled 1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/7ac0eda8-88fa-2f19-7c22-cd12e5d4b429.jpeg)


```html
<section class="settings">
  <h2 class="settings-heading">blastengineの設定</h2>
  <p class="kintoneplugin-desc">APIキーとユーザー名、デフォルトのFrom情報を登録してください</p>
  <form class="js-submit-settings">
    <p class="kintoneplugin-row">
      <label for="api-key">
        <input type="text" name="api-key" class="js-text-api-key kintoneplugin-input-text" placeholder="APIキー">
      </label>
    </p>
    <p class="kintoneplugin-row">
      <label for="username">
        <input type="text" name="username" class="js-text-username kintoneplugin-input-text" placeholder="ユーザー名">
      </label>
    </p>
    <p class="kintoneplugin-row">
      <label for="from-name">
        <input type="text" name="from-name" class="js-text-from-name kintoneplugin-input-text" placeholder="送信元（名前）">
      </label>
    </p>
    <p class="kintoneplugin-row">
      <label for="from-address">
        <input type="text" name="from-address" class="js-text-from-address kintoneplugin-input-text" placeholder="送信元（メールアドレス）">
      </label>
    </p>
    <p class="kintoneplugin-row">
        <button type="button" class="js-cancel-button kintoneplugin-button-dialog-cancel">キャンセル</button>
        <button class="kintoneplugin-button-dialog-ok">保存</button>
    </p>
  </form>
</section>
```

さらに `manifest.json` にて `required_params` を追加します。これがないと、必須の項目が設定されていませんと言ったエラーが出続けます。

```json
{
  "manifest_version": 1,
  // 中略
  "config": {
    // 中略
    "required_params": [
      "api-key",
      "username",
      "from-name",
      "from-address"
    ]
```

### 設定値の取得と復元

設定画面を表示した際には、kintoneに保存されている設定値を取得し、画面上に反映します。

```jsx
(function($, PLUGIN_ID) {
  'use strict';
  // 入力フォームの確認
  const $form = $('.js-submit-settings');
  const elements = $form.serializeArray();
  const $cancelButton = $('.js-cancel-button');
  if (!($form.length > 0 && $cancelButton.length > 0 && elements.length > 0)) {
    throw new Error('Required elements do not exist.');
  }
  // 設定を復元する
  const config = kintone.plugin.app.getConfig(PLUGIN_ID);
  for (const element of elements) {
    $(`[name="${element.name}"]`).val(config[element.name]);
  }
// 省略
```

### 設定の保存処理

設定値の保存は入力値の取得を行った後、 `kintone.plugin.app.setConfig` にて設定値を保存します。この時、入力されたAPIキーとユーザー名を使ってトークンを生成し、それも保存しています。

```jsx
// 設定を保存する処理
$form.on('submit', async function(e) {
  e.preventDefault();
  // 保存する値を作成
  const params = {};
  $form.serializeArray().forEach(element => {
    params[element.name] = element.value;
  });
  const hash = await async_digestMessage(`${params.username}${params['api-key']}`);
  const token = await base64Encode(hash);
  // eslint-disable-next-line require-atomic-updates
  params.token = token;
  // 設定を保存
  kintone.plugin.app.setConfig(params, function() {
    alert('プラグイン設定を保存しました');
    window.location.href = '../../flow?app=' + kintone.app.getId();
  });
});
```

`async_digestMessage` および `base64Encode` 関数はSHA256のハッシュ値計算と、そのBASE64エンコードを行う関数です。

参考）

- [【テックコラム】JavaScript Web Crypto API で SHA256 ハッシュ値を作る | DataCurrent](https://www.datacurrent.co.jp/column/jssha256-20211222/)
- [JavaScriptでBase64エンコード・デコード（UTF-8も） - Qiita](https://qiita.com/i15fujimura1s/items/6fa5d16b1e53f04f3b06)

```jsx
async function async_digestMessage(message) {
  const msgUint8 = new TextEncoder('utf-8').encode(message);
  const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map(function(b) {
    return b.toString(16).padStart(2, '0');
  }).join('');
}

function base64Encode(...parts) {
  return new Promise(resolve => {
    const reader = new FileReader();
    reader.onload = () => {
      const offset = reader.result.indexOf(',') + 1;
      resolve(reader.result.slice(offset));
    };
    reader.readAsDataURL(new Blob(parts));
  });
}
```

これで設定値が保存されました。

## 実際の使い方

### コードを追加する

現在は特にイベント処理を行っていません。 `desktop.js` にデモのコードだけ用意しています。例えば、以下は編集完了時のイベントでメール送信を行います。

```jsx
// 例：編集完了時のイベント
kintone.events.on('app.record.edit.submit.success', async (event) => {
	// 更新内容
	// event.record
	try {
		// delivery_id（数値）が返ってくれば送信成功
		const delivery_id = await window.kintonePlugin.blastengine.transaction({
			to: 'admin@example.com',
			cc: ['manager@example.com'],
			bcc: ['ceo@example.com'],
			subject: 'テストメールの件名',
			text_part: 'テストメールの本文',
			html_part: '<h1>テストメールの本文</h1>'
		});
		// 送信完了時の処理
		event.url = `/k/${event.appId}/show#record=${event.recordId}`;
		return event;
	} catch (e) {
		throw new Error('メール送信に失敗しました');
	}
});
```

kintoneには他にもたくさんのイベントが用意されていますので、必要なものを利用してください。

[イベント処理の記述方法 – cybozu developer network](https://developer.cybozu.io/hc/ja/articles/201941954)

### プラグインのビルド

以下のURLで詳しく説明されていますが、`kintone-plugin-packer` にてパッケージ化できます。

[kintone プラグイン開発手順 – cybozu developer network](https://developer.cybozu.io/hc/ja/articles/203455680-kintone-%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E9%96%8B%E7%99%BA%E6%89%8B%E9%A0%86)

### プラグインのインストール

利用する際には、まずプラグインをインストールします。[plugin.zip](https://github.com/blastengineMania/kintone-plugin/raw/main/plugin.zip)をダウンロードした上、kintoneにアップロードします。詳細はkintoneのドキュメントが役立つはずです。

[プラグインを追加／削除する（システム管理） | kintone ヘルプ](https://jp.cybozu.help/k/ja/admin/add_plugin/plugin.html)

プラグインをアップロードしたら、アプリ側の設定でプラグインを追加します。これもドキュメントを読んでもらう方が早いです。

[プラグインを追加／削除する（アプリ設定） | kintone ヘルプ](https://jp.cybozu.help/k/ja/user/app_settings/plugin.html)

これでkintoneプラグインが利用できます。

## まとめ

blastengineでは一通あたりのメール送信の他、一括配信もサポートしています。kintoneにある顧客リストに対してメールを一括配信すると言った仕組みも実現できます。

ぜひkintoneプラグインを使って、kintoneとメール送信を絡めた業務アプリを実現してください。

[エンジニア向けメール配信システム「ブラストエンジン（blastengine）」](https://blastengine.jp/)