sendmailRで画像付きHTMLメールを送る

前回は、R Advent Calendar 2012 : ATNDに間に合わせるために、現バージョンではHTMLメールが送れない問題と、画像が表示されない問題について苦肉の策をとらざるを得なかった。

さすがにあのままじゃちょっと残念な感じなので、これらの問題に対応してみた。

sendmailRパッケージの修正

今回の対応で、sendmailRパッケージ自体をいじる必要があったので、いじって開発者の方にpatchを送ってみた。
次のバージョンとかで反映されてると良いな〜

  • yokkuns/sendmailR:Compare View
    • パッケージの内部の関数でContent-Typeがベタ書きされてるので、これを引数headersで指定出来るように変更
    • 添付ファイルのContent-IDが設定されていないので、内部で自動で設定するように変更
      • この時、添付画像として指定しやすいように、IDを<ファイル名>とした
  • インストール

上記の変更を行ったsendmailRパッケージは、以下のようにインストールが可能です。

$ git clone git@github.com:yokkuns/sendmailR.git
$ cd sendmailR
$ sudo make install

または、パッケージを作成して普通に、install.packagesでインストール

$ make package

> install.packages("sendmailR_1.1-2.tar.gz")

本文で画像を表示

markdownは、デフォルトでは、画像をbase64エンコードしたものを直接htmlに埋め込むようになっている。
これは、htmlファイル一個で完結することで、依存ファイルとか気にしなくて良いよって配慮なのだが、HTMLメールはこれに対応していない。

そこで、画像ファイルは、添付して、その画像を読み込むように変更する

  • imgタグの画像へのリンクになるように変更
## デフォルトで、base64_imagesが設定されるので外す
markdownToHTML(file=md.file,output=mail.html.file,
                   stylesheet="/usr/lib/rstudio-server/resources/markdown.css",
                   options=c("hard_wrap","use_xhtml","smartypants"))
  • 出力されたhtmlに関して、figure/を、cid:に置換する
## figure/xxx.pngというリンクになるので、これを添付ファイル用のcid:に置き換える
html.str <- gsub("figure/","cid:",html.str)
  • 出来上がった修正版 sendStockAnomalyDetectionReport.R
#!/usr/bin/env Rscript
library(knitr)
library(markdown)
library(sendmailR)

main <- function(){
  mail.from    <- "yokkuns@tkul.jp"
  mail.to      <- "yokkuns@tkul.jp"
  mail.subject <- "Sample Report from R server"
  rmd.file     <- "stock_anomaly_detection_sample.Rmd" #RStudioで作成したRmdファイル                                                   

  ## HTMLレポート送信                                                                                                              
  sendHtmlReport(rmd.file,mail.from,mail.to,mail.subject)
}

sendHtmlReport <- function(rmd.file,from,to,subject,headers=list(),control=list()){
    f <- rmd.file
    md.file <- paste(f,"md",sep=".")
    mail.html.file <- paste(f,".html",sep="") ## メール用
    web.html.file <- paste("~/public_html/",f,".html",sep="") ## Web用

    knit(input=rmd.file,output=md.file)
    markdownToHTML(file=md.file,output=web.html.file,
                   stylesheet="/usr/lib/rstudio-server/resources/markdown.css")
    markdownToHTML(file=md.file,output=mail.html.file,
                   stylesheet="/usr/lib/rstudio-server/resources/markdown.css",
                   options=c("hard_wrap","use_xhtml","smartypants"))


    html.str <- paste(readLines(mail.html.file),collapse="\n")
    html.str <- gsub("figure/","cid:",html.str)

    imgs <- sapply(list.files("figure"),
                   function(f){
                     mime_part(paste("figure",f,sep="/"),f)
                   })

    body <- unlist(list(list(html.str),imgs))
    headers <- list("Content-Type"="text/html; charset=\"utf-8\"")
    ## control <- list(smtpServer="hogehoge.com",smtpPort=25)                                                                                      
    sendmail(from,to,subject,body,headers=headers,control)
  }

## 実行                                                                                                                                            
main()

HTMLメール送信!

以上で、画像も表示されるhtmlメールの送信が出来るようになった。

$ ./sendStockAnomalyDetectionReport.R

  • 結果

http://gyazo.com/5e18127bf9738d96a4bcaf9736cd6a40.png