こんにちは。リスペクトの木村です。
突然ですが、最近全社的にGoogleAppsに移行しました。
その時にメールも移行したためGmailを使うようになり、それによりGmail APIが利用可能になりました。
APIへのアクセスはAPI Client Libraryを利用するのが定石のようで、ここにはbetaながらもJavaScriptの文字もあります。
・・・という事は、Gmail APIを駆使すればJavaScriptだけでメールが送れるのでは?と考えましたので早速試してみました。
必要なもの
- JavasScriptの知識
- 今回は触れませんが、UI実装時は応じてHTML/CSSの知識も必要です
- HTTPサーバ環境
- API利用に必要な情報の発行時にURLを設定する必要があるためです
- xamppでも良いですし、pythonのSimpleHTTPServerでもOKです
- AmazonS3に設置するという手段もあります
事前準備
まずはGmail APIを有効にしておく必要があるので、Google Developer ConsoleのAPI ManagerからGmail APIを有効にしておきます。
有効でなければ「有効にする」になっているはずです。
その後、認証情報からOAuth クライアント IDを生成します。
アプリケーションの種類は「ウェブ アプリケーション」、「制限事項」の「承認済みのJavascript生成元」に実行するURIを入力します。
例えば、localhostの8080版ポート(PythonのSimpleHTTPServerとか)で実行する場合はhttp://localhost:8080
、S3上で実行する場合はhttps://s3-ap-northeast-1.amazonaws.com
という感じです。
設定例としては下記のようになります。
生成したらクライアントIDをメモしておきます。クライアントシークレットは利用しません。
実装
準備
必要な情報が揃ったら、本体の実装に移ります。
API Client LibraryはCDNから読み込む形になります。
<script src="https://apis.google.com/js/client.js?onload=onLoadCallbackFunction"></script>
読み込んだ後にonLoadCallbackFunction
の部分の関数が実行されます。
実装を進める前に、先ほど取得したクライアントIDと、行いたい作業に応じた適切なスコープを設定しておきます。
今回はメール送信をAPI経由で行うので、指定するスコープは「https://www.googleapis.com/auth/gmail.send」です。
Gmail APIのスコープはここに載っています。
下記のような感じになります。
var clientid = '~.apps.googleusercontent.com'; // 取得したクライアントID var scopes = ['https://www.googleapis.com/auth/gmail.send'].join(' '); // スコープを配列で指定して分解
自分のメールアドレスや名前を取得する場合など、他のスコープを追加する場合はscopesに追記します。
フルアクセス可能になる「https://mail.google.com/」でも良いのですが、適切なスコープがあればそれを指定するのが無難です。
認証部分
事前準備が終わったら、まずはonLoadCallbackFunction
部分の実装に入ります。
この部分では、「認証済みかどうか」のチェックを行っておきます。
function onLoadCallbackFunction() { gapi.auth.authorize({'client_id': clientid, 'scope': scopes, 'immediate': true}, handleAuthResult); }
この辺のドキュメントはこちらです。
クライアントIDとスコープを渡して、認証済みかどうかを確認しています。
immediate: true
がポイントで、ここがfalse
だといきなり認証画面(※)が表示されてしまうので、最初はtrue
にして抑制しています。
(※)この画面です。サービス名(myappの部分)が適当ですね。
ついでに、immediate: false
のパターンも実装しておきます。
function handleAuthClick(event) { gapi.auth.authorize({'client_id': clientid, 'scope': scopes, 'immediate': false}, handleAuthResult); return false; }
「認証する」のようなボタンのonclick
で呼び出す想定なのでこんな感じです。違いはimmediate: false
になっているだけです。
handleAuthResult
は処理後に実行される関数です。無名関数でも良いのですが、認証後にも再度呼び出すので別途関数を定義しておきます。
handleAuthResult
の実装はこうなります。
function handleAuthResult(authResult) { if (authResult && !authResult.error) { // 認証後の処理 } else { // 認証できていない時やエラーの時の処理 } }
簡単ですね。
メールアドレスや名前を取得したり、隠していたフォームを表示させたりする場合は「認証後の処理」に仕込むと良いと思います。
認証回りはここまでで完了です。
gapi.auth.authorize()
を実行してよしなにするだけなのでかなりお手軽でした。
メール送信
送信に限らず、Gmail API操作前は次の関数を呼び出します。
gapi.client.load('gmail', 'v1', callbackFunction());
ドキュメントはこちら。こちらも、最後の引数は無名関数でも大丈夫です。
関数の呼び出し先でGmail APIの操作処理を行います。
後はメール送信を行うだけですが、この辺は下記のようなクセがあり、想定している動作をしてくれるまで時間がかかってしまいました。
- メッセージの送信はRFC822形式でBase64エンコードする必要がある
- 要はToとかFromや本文を1つのテキストにして、base64エンコードする、というイメージ
- URLセーフなBase64にする必要があるので注意
- 件名が日本語の場合は、予めURLセーフ ではない Base64にしておく必要がある
このあたりはこちらが詳しいです。
下記のような実装になります。
var mimeData = ["To: example@example.com", "Subject: =?utf-8?B?" + window.btoa(unescape(encodeURIComponent("日本語の件名"))) + "?=", "MIME-Version: 1.0", "Content-Type: text/plain; charset=UTF-8", "Content-Transfer-Encoding: 7bit", "", "ここから本文"].join("\n").trim(); var raw = window.btoa(unescape(encodeURIComponent(mimeData))).replace(/\+/g, '-').replace(/\//g, '_');
ちなみに、From
が無いですが、ここは認証したユーザーのメールアドレスになります。
raw
に送信すべきデータが含まれますので、下記の関数を実行して送信します。
gapi.client.gmail.users.messages.send({ 'userId': 'me', 'resource': { 'raw': raw } }).execute(function() { // 送信後の処理 });
ドキュメントはこちら。
サンプルコードはmessages.raw
に送信するデータを渡すようになっていますが、resource.raw
に渡すのが正しいようです。
実際に送信してみると、認証したアカウントのGmail内送信済みメールに、Users.Messages.Sendで送信した内容が含まれているはずです。
おわり
ここまでで、Gmail APIを使ってJavascriptでメールの送信ができるようにになりました。
メール送信というとSMTP叩いたり色々準備しなければならないのが多くサーバサイドで行うイメージだったのですが、Javascriptだけで送信できるというのは感動ものです。Gmail API様々ですね。
API Client LibraryのGetting StartedやGmail APIのQuickStartを読んだときは取っつきにくそうだったのですが、試行錯誤して実装してみるとそうでもないというのがよく分かりました。
JavaScriptだけでメールが送れるというのは不思議な感じがしますので、皆さんも是非お試しください。
現場からは以上です。