Note of Pediatric Surgery

腸内細菌、R、ときどき小児外科

Rの計算終了時に{mailR}を使って通知を飛ばして生産性を上げる

はじめに

時間がかかるスクリプトを走らせてる間、僕はついTwitterを見てしまうのですが、いつも処理が終わったのに気づかず、ダラダラとTwitterを見続けてしまっていました。計算が終わった時点で通知がくればいいなと思って、方法をいろいろ調べてみたのですが、結局、{mailR}で自分にメールを飛ばすという方法がいいのではないかと思ったので記事を書きます。

計算終了時に通知を鳴らす方法

計算終了時に通知を鳴らす方法はいくつかあって、こちらによくまとまっていました。

www.slideshare.net

これと他の方法をまとめると、

  1. 音だけを鳴らす
  2. メールを自分に送る
  3. pushoverというアプリを使う
  4. terminal-notifierを使う

という方法があるようです。ただ1.は超簡単だけどMacをサイレントにしていると気づかない。家ならいいですけどね。3.は有料なので却下。4.に関しては

qiita.com

こちらに記事がまとまっており、実装も簡単なのですが、通知のポップアップが出ない…。通知センターを開くと、通知は来てるんですが、何故かポップアップが出ないので気づけない…RStudioでもnative Rでも同じでした。一応、同じ現象は他の人にも起きているようで、

github.com

GitHubにスレッドが立っていましたが、どうやら解決はしていなさそうで諦めました。というわけでメールで通知する方法を考えます。これだと出先でも通知を受け取れるのでいいかもしれません。

{mailR}を使ってメールで通知する

{gmailr}というパッケージもあるようですが、僕は最後のGoogleの認証がうまく行かずに断念しました。なので{mailR}でいいんじゃないかと思います。

cran.r-project.org

{mailR}に関しては、からだにいいものにまとめられています (なんでもあるな、ほんとに…)。ファイルを添付したり、一斉送信などもできるようです。

www.karada-good.net

install.packages("mailR", dep = T)
library("mailR")

mailR::send.mail(from = "自分のメールアドレス",
         to = "自分のメールアドレス",
         subject = "件名",
         body = "本文",
         encoding = "utf-8",
         smtp = list(host.name = "smtp.gmail.com",
                     port = 587,
                     user.name = "自分のメールアドレス",
                     passwd = "パスワード",
                     ssl = T),
         authenticate = TRUE,
         send = TRUE)

こんな感じで動きます。僕は

ntf <- function(passwd){mailR::send.mail(from = "自分のメールアドレス",
         to = "自分のメールアドレス",
         subject = "件名",
         body = "本文",
         encoding = "utf-8",
         smtp = list(host.name = "smtp.gmail.com",
                     port = 587,
                     user.name = "自分のメールアドレス",
                     passwd = passwd,
                     ssl = T),
         authenticate = TRUE,
         send = TRUE)}

という自作関数を作っておいて、ntf()にパスワードだけ入力すれば動くものを作っています。ただし、{mailR}を使うには下記のエラーメッセージを解決する必要があります。

java.activationを追加する

上記のスクリプトを実行しようとすると

Error: NoClassDefFoundError (Java): javax/activation/DataHandler

とエラーが出ると思います。この原因は下記のQiita記事によると、

qiita.com

OracleJDK 8 から OpenJDK 11 に変更したところ、JavaMail で以下の例外が発生するようになりメール送信が一切できなくなりました。 JavaMail では内部で java.activation パッケージを使用していますが、OpenJDK 11 以降では JEP 320: Remove the Java EE and CORBA Modules によって以下のパッケージが削除されています。 java.activation パッケージが削除されたことにより JavaMail で参照するクラスが見つからなくなり概要で示した例外が発生しています。

ということでした。ただ、この記事の対処法ではうまく行かず、最終的にはStackOverflowの下記の記事が参考になりました。

stackoverflow.com

  1. 下記の2つのURLに飛んで、.jarファイルをダウンロードする https://mvnrepository.com/artifact/javax.activation/javax.activation-api/1.2.0 https://mvnrepository.com/artifact/com.sun.activation/javax.activation/1.2.0

  2. mailRが格納されているディレクトリのjavaフォルダに2つの.jarファイルをコピペする

ちなみに僕のケースでは、mailRはここ

/Library/Frameworks/R.framework/Versions/3.6/Resources/library/mailR/java

にありました。

Gmailのセキュリティを変更する

JavaMailのエラーを解決すると今度は、

Error: EmailException (Java): Sending the email to the following server failed : smtp.gmail.com:465

というエラーが出るかもしれません。その場合は、Gmailのセキュリティを変更する必要があります。

https://myaccount.google.com/lesssecureapps?pli=1

にアクセスして、安全性の低いアプリのアクセスを許可するように変更しましょう。計算時間の長いスクリプトを実行した後に、send.mail()を実行しておけば、計算終了時にRからメールで通知を送ることができます!

追記

他の環境で試したらまたエラーが出たので追記しておきます。

Error: .onLoad failed in loadNamespace() for 'rJava', details:
  call: fun(libname, pkgname)
  error: JVM could not be found 

まずこのエラーが出てきました。これをぐぐると、

stackoverflow.com

この記事にたどり着きます。ここに

「あなたが使ってる環境は64-bitバージョンのOSとRで、それに対応してないJavaがインストールされてないからだ。下記のリンクからインストールしなさい」

と書いてあるので、Javaのページから従う。

www.java.com

しかし動かず、同じエラーが出てくる。そう言えば、{tabulizar}をインストールするときに異常に苦労した{rJava}がまたエラーになってるなあと気づきました。その時の記事はこちら。

www.pediatricsurgery.site

試しに

library(rJava)

を実行すると

Install Java and/or check JAVA_HOME (if in doubt, do NOT set it, it will be detected)

というエラーが。これをググると、この記事にたどり着きました。

docs.oracle.com

  1. こちらのページにアクセスして、適切なJDKのバージョンをダウンロードしてインストールする
  2. 下記のスクリプトをターミナルで実行し、JAVA_HOMEをセットする
export JAVA_HOME=jdk-install-dir
export PATH=$JAVA_HOME/bin:$PATH

これでもう一つの環境でも{mailR}が実行できました。この内のどのステップが有効だったのかはわかりませんが、もしよかったら試してみてください。