GASを使ってボタン一つでOutlookでメールを送信したいんじゃ！

## 概要
私の所属しているチームでは、出退勤報告をいくつかの所属組織に対してする必要があるのですが、毎回色々なところに報告をしていると、「あれ、報告したっけ？」みたいことが起こります。
そしてその報告の中には、Outlookでメールを送信する必要があるものがあります。


メーラー立ち上げて、メール書いて、送信して…
これを出退勤のたびにやるのです。

<br>
<br>
<br>
<br>

え、面倒くさくね？
簡単にOutlookでメールが送信したいんじゃ！

<br>
<br>
<br>
<br>

今回はGASを使って1クリックでOutlookを使ってメール送信する方法をまとめました。


## 今回使うもの

- **Microsoft Graph API の Outlook メール REST API**

https://learn.microsoft.com/ja-jp/graph/api/resources/mail-api-overview?view=graph-rest-1.0

- **Google Apps Script**

https://developers.google.com/apps-script/reference

- **Microsoft Azure**

https://azure.microsoft.com/ja-jp/

- **Outlook(事前にアカウントを作っておいてくださいm(_ _)m)**

https://www.microsoft.com/ja-jp/microsoft-365/outlook/email-and-calendar-software-microsoft-outlook

### 今回説明しないもの
- GAS
- ターミナル

## 実装
### 1. Microsoft Azureでアプリケーションを作成する

#### ログインする
以下より作成済みのOutlookアカウントでログインしてください。

https://portal.azure.com/#home

![スクリーンショット 2022-12-16 14.52.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/73f812a3-5fe2-72a9-35bd-cc6217c2ef5d.png)


#### アプリケーションを登録する
ログインできたら、アプリケーションの登録を行います。
まずは以下にアクセスしてください。

https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade

↓こんな画面が表示されるので、左上の「新規追加」をクリックします。
![スクリーンショット 2022-12-14 13.12.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/7c1749b8-37c2-334b-b0d4-53cf6a3866cc.png)

↓こんな感じで登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/6474f5fe-e8d3-a4e1-cb51-0c7e854b56f6.png)

#### 認証を追加する
左メニューから「認証」をクリックすると↓の画面が表示されるので、「プラットフォームを追加」をクリックします
![スクリーンショット 2022-12-14 13.52.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/1d69cd2d-57fa-5aa1-c36c-db50e96516ad.png)

プラットフォーム構成の追加フォームが表示されるので、それぞれ以下のように設定します
- Webアプリケーション: Web
- リダイレクトURI: `http://localhost:8888/authorized`
- 暗黙的な許可およびハイブリッド フロー: すべてチェック


#### クライアントシークレットを追加する
左メニューから「証明書とシークレット」をクリックすると↓の画面が表示されるので、「新しいクライアントシークレット」をクリックします。
![スクリーンショット 2022-12-14 13.55.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/07eaeef3-7c0a-8a99-35a1-0ea571e0a084.png)

右からシュッとモーダルが出るので、適当な説明書きをつけて追加すると↓のように追加されます。
![スクリーンショット 2022-12-14 13.56.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/946dd874-01fe-b007-0802-cd11b9fd3bc5.png)

このとき、**追加したクライアントシークレットの「値」を絶対に保存しておくようにしてください。**
ここで値を保存しないと二度と確認できなくなります。
**絶対に保存してください。**
大事なことなので2回言いました。

#### APIのアクセス許可を追加する
左メニューから「APIのアクセス許可」を選択すると↓の画面に遷移するので「アクセス許可の追加」をクリックします。
![スクリーンショット 2022-12-14 13.17.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/58080a2b-20d2-3cfa-de68-f2e3606db6da.png)


右からシュッと↓が表示されるので、今回使う「Microsoft Graph」をクリックします。
![スクリーンショット 2022-12-14 13.17.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/20e8923d-e8eb-4940-6056-0dbe2413451a.png)

「委任されたアクセス許可」をクリックすると、↓が表示されるので、「Mail.Send」にチェックを入れてアクセス許可の追加をします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/f76b79f3-10dc-41f6-b268-62fc9d103c7b.png)

#### APIを公開する
左メニューから「APIの公開」をクリックすると↓が表示されるので「アプリケーションIDのURI」の右にある「設定」をクリックしてURIを設定します
![スクリーンショット 2022-12-14 13.35.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/9cd5ad89-de52-d967-b9c1-093b27eab9f6.png)

URIを設定するとこんな感じでURIが表示されるようになります
![スクリーンショット 2022-12-14 13.36.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/8fe3cf6f-7601-304c-f51c-c75780f958f0.png)

次に「Scopeの追加」をクリックするとスコープの追加モーダルが表示されるので、↓みたいな感じでスコープを追加します
![スクリーンショット 2022-12-14 13.37.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/86376cb0-3da6-195b-5f02-eb62bbc6f616.png)

全部できるとこんな感じ↓
![スクリーンショット 2022-12-16 15.56.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/0af4ca8f-a3e7-3a27-cf6b-807883fc5630.png)


#### 概要を確認
左メニューの「概要」をクリックすると登録内容の概要が確認できます
すべての登録が完了するとこんな感じになります↓
![スクリーンショット 2022-12-16 16.10.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/c666610d-af81-aca5-6f17-0619aab3dddd.png)


### 2. アプリケーションのアクセストークンを取得する


#### 承認コードの取得
まずはアクセストークンを取得するための承認コードを取得します。

エンドポイント: `login.microsoftonline.com/common/oauth2/v2.0/authorize`
パラメータ:
| パラメータ | 解説 |
|:-:|:-:|
| client_id | 「概要」に表示される「アプリケーション (クライアント) ID」 |
| response_type | `code`を固定で入れる |
| redirect_uri | [認証を追加する](#認証を追加する) で追加したリダイレクトURI<br>今回は`http://localhost:8888/authorized` |
| scope | [APIのアクセス許可を追加する](#APIのアクセス許可を追加する) で指定したAPIのアクセス許可<br>今回は`https://graph.microsoft.com/Mail.Send` |
| response_mode | 今回は`query`を指定する |
| state | 任意で指定する<br>内部での乱数の生成にも使われるらしい |

以下のURLをブラウザに入力してアクセスします。
```
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=<アプリケーション（クライアント）ID>&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8888%2Fauthorized&response_mode=query&scope=https%3A%2F%2Fgraph.microsoft.com%2Fmail.send+offline_access&state=1234
```
アカウント選択ページに遷移するので、今回使用しているOutlookのアカウントを選択します。
すると作成したアプリのサインイン画面↓に遷移するので「続行」をクリックします。
![スクリーンショット 2022-12-16 16.41.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/000c3bfe-a437-eec1-ccd4-81eb423e214c.png)

設定したリダイレクトURIに遷移します。
エラーページが表示されますが、URLをよく見るとパラメータに`code`が含まれています。
![スクリーンショット 2022-12-16 16.44.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/740cf321-265d-2628-f45f-1e2d6849fcd9.png)
これが認証コードです。
```
http://localhost:8888/authorized?code=<認証コード>&state=1234
```

### アクセストークンの取得
次に、先程の認証コードを利用してアクセストークンを取得します。
取得にはターミナルを利用するのが一番手っ取り早いです。

エンドポイント: `login.microsoftonline.com/common/oauth2/v2.0/token`
メソッド: `POST`
ヘッダー: `Content-Type: application/x-www-form-urlencoded`
パラメータ:
| パラメータ | 解説 |
|:-:|:-:|
| client_id | さっきと一緒 |
| scope | さっきと一緒だけど今回は`mail.send`だけでおｋ |
| code | さっき取得した認証コード |
| redirect_uri | さっきと一緒 |
| grant_type | `authorization_code`を指定する |
| client_secret | [クライアントシークレットを追加する](#クライアントシークレットを追加する) で取得したクライアントシークレット<br>2回も言ったからちゃんと保存してるよね？？？  |

以下をターミナルに入力してエンターをｶﾁｬｶﾁｬｯﾀｰﾝしてください

```
curl -X POST \
https://login.microsoftonline.com/common/oauth2/v2.0/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'client_id=<アプリケーション (クライアント) ID>&scope=mail.send%20offline_access&code=<認証コード>&redirect_uri=http%3A%2F%2Flocalhost%3A8888%2Fauthorized&grant_type=authorization_code&client_secret=<クライアントシークレット>' | jq
```

↑jqコマンドを使用しているので、使う場合はインストールしておいてください。
所得したjsonデータを自動で整形してくれるので便利です。
使わない場合は最後の` | jq`を削除してください。

https://qiita.com/ponsuke0531/items/aa405a0f897cd0a78a8c

レスポンスはこんな感じ↓です

```
  % Total % Received % Xferd  Average Speed   Time    Time     Time  Current Dload  Upload   Total   Spent    Left  Speed
100  1887  100  1611  100   276   2746    470 --: --: -- --: --: -- --: --: --3231
{
  "token_type": "Bearer",
  "scope": "Mail.Send Mail.ReadWrite",
  "expires_in": 3600,
  "ext_expires_in": 3600,
  "access_token": <アクセストークン>,
  "refresh_token": <リフレッシュトークン>
}
```

ちなみに、認証コードを取得してしばらく時間置くと認証コードの期限切れになるので注意してください。

#### アクセストークン取得の公式ドキュメント

https://learn.microsoft.com/ja-jp/graph/auth/auth-concepts

### 3. メール送信のGASを実装する
こんな感じのコードを実装します。
```javascript:code.gs
var API = 'https://graph.microsoft.com/v1.0/me/sendMail';
var ACCESS_TOKEN = '<アクセストークン>';
function sendEmail() {
    // 送信内容作成
    var payload = {
        message: {
            subject: 'タイトル',  // メールタイトル
            body: {
                contentType: 'HTML',
                content: '本文'  // メール本文
            },
            toRecipients: [
                {
                    emailAddress: {
                        address: '<送信先のメールアドレス>'
                    }
                }
            ]
        }
    };
    // ヘッダー作成
    var header = {
        Authorization: 'Bearer ' + ACCESS_TOKEN,
        'Content-Type': 'application/json'
    };
    // オプション作成
    var options = {
        method: 'POST',
        headers: header,
        payload: JSON.stringify(payload),
    };
    // 送信
    UrlFetchApp.fetch(API, options);
}
```
↑sendEmail関数を実行すると、`<送信先のメールアドレス>`に設定したメールアドレスにメールが届きます。

#### メール送信リファレンス
https://learn.microsoft.com/ja-jp/graph/api/user-sendmail?view=graph-rest-1.0&tabs=http

### 4. スプレッドシートから1クリックでメールを送信できるようにする
最後に、スプレッドシートから1クリックでメールを送信できるようにします。

#### スプレッドシートのメニューにボタンが表示されるようにGAS実装
先程のGASファイルに、以下のような記述を追記します。
```javascript:code.gs
function onOpen() {
    var ui = SpreadsheetApp.getUi();
    var menu = ui.createMenu("スクリプト");
    menu.addItem("メール送信", "sendEmail");
    menu.addToUi();
}
```

#### トリガーを設定
トリガーに`onOpen()`がスプレッドシート起動時に実行されるように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/bb157646-6d52-97e6-f85d-70039b087d11.png)

スプレッドシートを開くと、メニューに「メール送信」が出現します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/3f5cbbd4-c0c7-3098-34d9-815251715a01.png)

#### メール送信
「メール送信」をクリックすると…
簡単にOutlookでメールが送信できたんじゃ！
（迷惑メールに振り分けられてしまいました…）
![スクリーンショット 2022-12-16 19.47.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982152/d954fdb6-5798-970c-eb98-05230bf447f8.png)


## 参照

https://qiita.com/utsuki/items/159e13f113cf0fb9396e