Galaxy シリーズを中心としたAndroidのカスタマイズの覚書です。
現在のメイン機種はGalaxy Note 9(グローバル版)。
10年目を迎え、古い投稿を整理・改訂しました。
カスタマイズのまとめ(リンク集)はこちらです。

2014/12/05

Pushbullet APIでOutlookへの新規メール受信をAndroidにPush通知する


Last Update : 09/Jul/2015

Outlookへの新規メール受信時にPusubullet APIを使ってAndroid端末にPush通知するようにしてみました。


想定される環境
以下の様な環境下での使用を想定しています。

・職場のセキュリティ・ポリシーで受信メールそのものの自動転送は禁止されている。
・Gmail等のメールやSNSの使用もProxyで撥ねられる。
・モバイル端末からVPNやセキュアなクライアントアプリを利用したメール閲覧は許可されている。
・クライアントアプリへのメールのPushサービスが提供されていない。
・職場のメールはOutlook(Exchangeサーバー)でProxy環境下。

PCのバックグラウンドで動作しますので、PCは常に稼働したままで、Outlookも常に起動したままにしておく必要があります。

メール本文を通知する事も出来ますが、そうすると、実質、自動転送と同じになってしまいますので、表題と送信者名だけにしています。

(追記)ご要望がありましたので、Push通知に余計な空白文字や改行、改頁、タブ等を削除したメール本文を含めるオプションを追加しました。(本文の有無の設定や文字数の制限も可能です。)

*ご利用にあたっては各職場のセキュリティポリシーに抵触しないかをご確認ください。
全体の動作の流れ
・Outlookのマクロで新規メール受信時に表題・送信者名・本文をテキストファイルに書き出す
・Outlookのマクロからnodejsのスクリプトを起動
・nodejsのスクリプトでテキストファイルから表題・送信者名・本文を読み込む
・nodejsのスクリプトからPushbullet APIを使って端末にPush通知
必要なもの
・ nodejs本体
・ nodejs用Proxy tunnelモジュール (=tunnel:Proxy環境下で必要)
・ nodejs用encord/decodeモジュール(=iconv-lite:Unicode対応に必要)
・ Outlook用マクロ(自作、詳細下記)
・ nodejs用Pusubullet APIスクリプト(自作、詳細下記)
・ スクリプト起動用バッチファイル
・ スパムフィルタ用テキストファイル *2種類
・ Pushbulletアプリ(Android側:https://play.google.com/store/apps/details?id=com.pushbullet.android
事前に調べておくこと
・Pushbullet Access Token(https://www.pushbullet.com/#settings/account
・Pushbullet Device iden (https://www.pushbullet.com/?device_iden=)
・ProxyのURI(例:http://xxx.xx.xxx.x:8080)
nodejsの準備
1)nodeJS本体


nodejs
http://nodejs.org/

nodejsをインストールしたら、以下のコマンドでproxy環境下でもnpmが使えるようにしておきます。(XXX部分はProxyのURIに置き換えます。)

npm config set proxy http://xxx.xx.xxx.x:8080
npm config set https-proxy http://xxx.xx.xxx.x:8080
npm config set registry http://registry.npmjs.org/

2)nodejs用モジュール

2-1)Proxy通過用モジュール

tunnel
https://www.npmjs.org/package/tunnel
インストール方法:npm install tunnel

2-2)encode/decode用モジュール

iconv-lite
https://www.npmjs.org/package/iconv-lite
インストール方法:npm install iconv-lite

注)本家iconvやそのパッチ版のinconv-jsは当方の環境ではnpmからインストール出来ませんでしたので今回は使用しませんでした。

iconv
https://www.npmjs.org/package/iconv

iconv-js
https://www.npmjs.org/package/iconv-js
Outlook用マクロの作成
新規メール受信時にメールから表題・送信者名・本文をテキストファイルに書き出し、nodejsスクリプトを起動してその後の処理を引き継ぐマクロです。

' PushBullet連携マクロ Ver 1.08
Private Sub Application_NewMailEx(ByVal EntryIDCollection As String)
    Dim objItem
    Set objItem = Session.GetItemFromID(EntryIDCollection)
    If objItem.MessageClass = "IPM.Note" Then
        AutoForward objItem
    End If
End Sub

Private Sub AutoForward(ByVal objMail As MailItem)
    '
    Dim strFileName As String
    Dim fwMail As MailItem
'   Dim i As Integer
    Dim strSenderName As String
    Dim strSenderEmailAddress As String
    Dim strSubject As String
    Dim strbody As String
'
    ' 受信メールの自動仕分けルールや迷惑メールフィルタと併用した場合のエラー対策
    On Error GoTo ErrorTrap
    '
    ' 受信メールから表題、送信者名、本文を取得
    strSubject = objMail.Subject    ' 表題を取得
    strSenderName = objMail.SenderName  ' 送信者名を取得
    strSenderEmailAddress = objMail.SenderEmailAddress  ' Emailアドレスを取得
    strbody = objMail.Body ' 本文を取得
    '
    ' 送信者名と送信者のEmailアドレスの表示処理
    ' 送信者名と送信者のEmailアドレスが同じ場合はEmailアドレスのみ表示
    If strSenderName = strSenderEmailAddress Then
        strSenderName = strSenderEmailAddress
    ' 送信者名と送信者のEmailアドレスが異なる場合は「送信者名+」で表示
    Else
        ' 送信者のメールアドレスがEmailの場合
        If InStr(strSenderEmailAddress, "@") Then
            strSenderName = strSenderName + "<" + strSenderEmailAddress + ">"
        ' 送信者のメールアドレスがExchangeの場合はSMTPアドレスを取得して表示
        Else
            strSenderEmailAddress = _
            objMail.Sender.PropertyAccessor.GetProperty("http://schemas." _
            & "microsoft.com/mapi/proptag/0x39FE001E")
            strSenderName = strSenderName + "<" + strSenderEmailAddress + ">"
        End If
    End If
    '
    ' ファイルの書込
    '
    ' 表題
    Dim txt1 As Object
    Set txt1 = CreateObject("ADODB.Stream")
    txt1.Type = adTypeText
    txt1.Charset = "utf-8"  ' 文字コードを指定
    txt1.Open
    txt1.WriteText strSubject, adWriteChar
    txt1.SaveToFile ("C:\Program Files\nodejs\titleutf8.txt"), adSaveCreateOverWrite
    txt1.Close
    Set txt1 = Nothing
    '
    ' 送信者名
    Dim txt2 As Object
    Set txt2 = CreateObject("ADODB.Stream")
    txt2.Type = adTypeText
    txt2.Charset = "utf-8"   ' 文字コードを指定
    txt2.Open
    txt2.WriteText strSenderName, adWriteChar
    txt2.SaveToFile ("C:\Program Files\nodejs\nameutf8.txt"), adSaveCreateOverWrite
    txt2.Close
    Set txt2 = Nothing
    '
    '本文
    Dim txt3 As Object
    Set txt3 = CreateObject("ADODB.Stream")
    txt3.Type = adTypeText
    txt3.Charset = "utf-8"   ' 文字コードを指定
    txt3.Open
    txt3.WriteText strbody, adWriteChar
    txt3.SaveToFile ("C:\Program Files\nodejs\mailutf8.txt"), adSaveCreateOverWrite
    txt3.Close
    Set txt3 = Nothing
    '
    ' Nodejsのスクリプトを起動
    Dim rc As Long
    rc = Shell("C:\Program Files\nodejs\Run.bat", vbHide)
'
ErrorTrap:
'
End Sub


このマクロは新規メール受信時に自動起動します。

Exchangeメールの場合はサーバーにアクセスして送信者のEmailアドレスを取得する処理も行っています。

日本語以外のUnicode文字(韓国語等)の文字化け防止の為、表題・送信者名・本文をテキストファイルに書き出す際に文字コードを指定する様にしています。

テキストファイルに書き出した後、マクロの最後の部分で実行用のバッチファイルからnodejsのスクリプトを実行して処理を引き継ぎます。

このマクロは初回実行時に"C:\Program Files\nodejs\"に以下の3つのテキストファイルを自動作成しす。

titleutf8.txt
nameutf8.txt
mailutf8.txt

OfficeのマクロからShift-JIS以外の文字コードでファイルを出力する為に、ADODB.Streamを使用しますので、Visual Basic Editorの[ツール][参照設定]から"Mctosoft Active data Object X.X Library"を有効にしておいてください。


マクロの登録やデジタル署名の仕方等は下記投稿を参照してください。(今回のマクロには下記のマクロの機能の一部を移植しました。)

Outlook自動転送マクロ
http://galaxy-shw-m110s.blogspot.kr/2013/02/outlook.html


Pushbullet API用のnodejsスクリプトの作成
以下のスクリプトを作成し、"Notify.js"というファイル名にして"C:\Program Files\nodejs\"に置きます。

このスクリプトではテキストファイルから表題・送信者名・本文を読み込んで、Pushbullet APIを使って端末にPush通知を送ります。


// Pushbullet連携スクリプト(本文サマリー転送) ver 1.13

// Proxy Tunnelの設定
var tunnel = require('tunnel');
var tunnelAg = tunnel.httpsOverHttp({
    proxy: {
        host: 'XXX.XX.XXX.X',
        port: 8080
    }
});

// PushBulletの設定
var https = require('https');
options = {
    host: 'api.pushbullet.com',
    port: 443,
    path: '/v2/pushes',
    method: 'POST',
    auth: 'XXXXX:',
    headers: { 'Content-Type': 'application/json' },
    agent: tunnelAg
};

var fs = require('fs');
var iconv = require('iconv-lite');

//送信者名をファイルから読み込みデコード
var name = fs.readFileSync('./nameutf8.txt');
var strname = iconv.decode(new Buffer(name), "utf8");

// 送信者名フィルタ
var strnamereplace = strname.replace(/(\s+)|(\(+)|(\)+)/g, "");
var spamlist = fs.readFileSync('./spamlist.txt');
var strspamlist = iconv.decode(new Buffer(spamlist), "utf8");
var strspamlistreplace = strspamlist.replace(/(\s+)|(\(+)|(\)+)/g, "");
var spamcheck = strspamlistreplace.search(strnamereplace);
if (spamcheck == -1) 
 {

//表題をファイルから読み込みデコード
var title = fs.readFileSync('./titleutf8.txt');
var strtitle = iconv.decode(new Buffer(title), "utf8");

//表題フイルタ
var strtitlereplace = strtitle.replace(/(\s+)|(\(+)|(\)+)/g, "");
var strtitlereplacesub = strtitlereplace.substring(0,8);
var keyword = fs.readFileSync('./keyword.txt');
var strkeyword = iconv.decode(new Buffer(keyword), "utf8");
var strkeywordreplace = strkeyword.replace(/(\s+)|(\(+)|(\)+)/g, "");
var keywordcheck = strkeywordreplace.search(strtitlereplacesub);
if (keywordcheck == -1) 
 {

// 表題と本文をファイルから読み込みデコード
var mail = fs.readFileSync('./mailutf8.txt');
var strmail = iconv.decode(new Buffer(mail), "utf8");

//本文から空白削除と文字数制限して送信者名と結合
var strsummary = strmail.substring(0,180);
var strsummaryreplace1 = strsummary.replace(/([ ]+)|(\r+)|(\t+)|(\n+)|(\f+)/g, "");
var strsummaryreplace2 = strsummaryreplace1.replace(/([  ]+)/g, " ");
var strbody = strname + strsummaryreplace2;

// Pushbullet APIに送信
var req = https.request(options, function (res) {
    body = ''
    res.on('data', function(chunk) {
        body += chunk;
    });
    res.on('end', function() {
    });
});
req.on('error', function (e) { console.error(e); });
var params = {
    device_id: "XXXXX",
    type: 'note',
    title: strtitle,
    body: strbody
};
req.write(JSON.stringify(params));
req.end();

}
else{
};
}
else{
};


以下の投稿を参考にさせて頂きましたが、pushbullet APIの仕様が変更されていますので、"hostname"と"path"の部分は修正しています。

Having trouble posting notifications with node.js
http://www.reddit.com/r/PushBullet/comments/18stku/having_trouble_posting_notifications_with_nodejs/

変更した箇所:
hostname: 'www.pushbullet.com', =>   host: 'api.pushbullet.com',
path: '/api/pushes', =>  path: '/v2/pushes',

また、"title"や"body"は外部テキストファイルから読み込む様に変更して、文字化け防止の為のdecode処理も追加しています。

簡易スパムフィルタ機能も追加しました。(設定方法等は【5】参照。)

以下の項目はご自分の環境に合わせて設定して下さい。

1)Proxy

"host: 'xxx.xx.xxx.x'"にお使いのProxyのURIを記入してください。

// Proxy Tunnelの設定
var tunnel = require('tunnel');
var tunnelAg = tunnel.httpsOverHttp({
    proxy: {
        host: 'xxx.xx.xxx.x',
        port: 8080


2)Pushbullet Access Token

"auth : 'xxxxx' "にPushbullet Access Token(32桁)を記入して下さい。

// PushBulletの設定
var https = require('https');
options = {
    host: 'api.pushbullet.com',
    port: 443,
    path: '/v2/pushes',
    method: 'POST',
    auth: 'xxxxx:',
    headers: { 'Content-Type': 'application/json' },Access Tokenは下記で確認出来ます。

Pushbullet Access Token
https://www.pushbullet.com/#settings/account


3)Device IDEN

"device_id:"xxxxx""に端末のiden(22桁)を記入してください。

// Pushbullet APIに送信
var req = https.request(options, function (res) {
    body = ''
    res.on('data', function(chunk) {
        body += chunk;
    });
    res.on('end', function() {
    });
});
req.on('error', function (e) { console.error(e); });
var params = {
    device_id: "xxxxx",
    type: 'note',

端末idenは下記のページで端末名をクリックするとブラウザのURL欄に表示されます。

Pushbullet Device iden
https://www.pushbullet.com/


4)本文の有無と文字数制限

"var strsummary = strmail.substring(0,180);"でPush通知に含める本文の文字数を指定します。

//本文から空白削除と文字数制限して送信者名と結合
var strsummary = strmail.substring(0,180);
var strsummaryreplace1 = strsummary.replace(/([ ]+)|(\r+)|(\t+)|(\n+)|(\f+)/g, "");
var strsummaryreplace2 = strsummaryreplace1.replace(/([  ]+)/g, " ");
var strbody = strname + strsummaryreplace2;

本文は余計な空白文字や改行、改頁、タブ等を削除して送信しますので、この文字数はそれらを除いた文字数になります。

この部分を"0(ゼロ)"にするとPush通知に本文が含まれなくなります。

当方の環境では端末の通知領域に表示されるのは送信者名を含めて200文字迄でしたので、添付の例では送信者名を差し引いて180文字にしています。(200字を超える文字数を送信した場合も、Pushbulletアプリを開けば見ることは出来ます。)

注)nodejsからのPushbullet APIを使ったPush通知によく使われるpushbulletモジュールは、自宅PCからは使えましたが職場のProxy環境下では上手く動作しませんでしたので、今回は使用しませんでした。

pushbullet(nodejsモジュール)
https://www.npmjs.org/package/pushbullet
スクリプト実行用バッチファイルを用意
NodejsスクリプトをOutlookのマクロから実行する為に、下記の2行だけのバッチファイルを作成して"C:\Program Files\nodejs\"に置きます。

Run.bat
cd C:\Program Files\nodejs
node Notify.js
スパムフィルタ用バッチファイルを用意
簡易スパムフィルタ用の下記2つのテキストファイルを"C:\Program Files\nodejs\"に置きます。

spamlist.txt
keyword.txt

文字コードはutf-8にしてください。

1)spamlist.txt

送信者名をこのファイルに記入しておくと、その送信者からのメールについては端末にpush通知は送られません。(送信者名は完全に一致する必要があります。)

送信者名毎の改行の有無は問いませんが、改行があった方が見やすいと思います。

PCのブラウザでpushbulletを開き、不要な通知の送信者名をこのファイルにコピペしておくと良いでしょう。

2)keyword.txt

キーワードをこのファイルに記入しておくと、表題がキーワードで始まる場合は端末にPush通知を送りません。(前方一致に近い動作になります。)

キーワード毎の改行の有無は問いませんが、改行があった方が見やすいと思います。

デフォルトでは表題の頭9文字(空白削除後)をキーワードリストと比較していますが、お好みに合わせて"var strtitlereplacesub = strtitlereplace.substring(0,8);"の部分を調整して下さい。

//表題フイルタ
var strtitlereplace = strtitle.replace(/(\s+)|(\(+)|(\)+)/g, "");
var strtitlereplacesub = strtitlereplace.substring(0,8);
var keyword = fs.readFileSync('./keyword.txt');

全体のファイル構成
全体のフォルダ構成は下記の様になります。

C:\Program Files\nodejs
     └ node_modules
             └ iconv-lite
             └ npm
             └  tunnel
             └ (略)
     └ keyword.txt
     └ mailutf8.txt
     └ nameutf8.txt
     └ node.exe
     └ Notify.js
     └ Run.bat
     └ spamlist.txt
     └ titleutf8.txt
     └ (略)
問題点・今後の課題
Outlookの仕分けルールを使って受信時に自動的にフォルダーに移動しているメールについても、マクロが仕訳ルールよりも先に動作してしまう為、端末に通知が送られてしまいます。

必要に応じて例外処理を追加すると良いでしょう。


(追記)Ver 1.09で簡易スパムフィルタ機能を追加しました。

また、Android用のPushbulletアプリ(~ver 15.2.5)では受信したnoteの一括選択が出来ず、溜まったnoteの整理が不便です。

アプリ側が改善される迄は、PCのブラウザからPushbulletにアクセスしてマウスでXボタンを連打して消去するのが良いでしょう。(一番良いのは、Pushbullet APIに古いnoteを整理する機能が追加されて自動化出来るようになる事ですが。)

(追記)PC用のChromeの拡張機能で[Select All][Delete Selected][Refresh Boxes][Delete All]の4ボタンを追加するものがありました。





Pushbully: Bulk Delete Pushes

https://chrome.google.com/webstore/detail/pushbully-bulk-delete-pus/kamddpgihdoijjoekiambdmbngpgiaoi

(追記)Pushbulletサイトの改変により上記Chromeの拡張機能が動作しなくなりましたので、以下のスクリプトを作成しました。

PushbulletのPushをワンクリックで一括削除するスクリプト(Chrome用)
http://galaxy-shw-m110s.blogspot.jp/2015/07/pushbulletpushchrome.html


システムの改竄やカスタマイズには端末が起動しなくなったり保証の対象外となるリスクが伴います。自己責任にてお願い致します。