Une question sur stackoverflow a motivé ce billet : https://stackoverflow.com/q/54845375/3315962. Répondre à la question m’a permis plusieurs choses : confirmer qu’il est possible d’envoyer par email des tableaux HTML réalisés avec flextable et réviser mes connaissances du package sendmailR
.
L’objet du post est de montrer comment envoyer des emails contenant des tableaux de reporting depuis R.
On utilise ici deux packages R:
sendmailR
, qui va nous permettre d’envoyer des emails depuis R. Le package est stable (sa dernière mise à jour date de 2014!), il presente un nombre limité de fonctionnalités et est très simple à utiliser.flextable
, la référence en terme de reporting tabulaire avec R :). Le package permet la production de tableaux simples et de tableaux complexes, l’utilisateur peut récupérer la sortie au format HTML mais aussi au format Word, PowerPoint et PDF. On va utiliser un exemple basique afin de ne pas complexifier les illustrations. Le code ci-dessous créé le tableau qu’on va envoyer :
library(flextable)
myft <- flextable(head(iris, n = 10))
myft <- autofit(myft)
myft
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species |
5.1 | 3.5 | 1.4 | 0.2 | setosa |
4.9 | 3.0 | 1.4 | 0.2 | setosa |
4.7 | 3.2 | 1.3 | 0.2 | setosa |
4.6 | 3.1 | 1.5 | 0.2 | setosa |
5.0 | 3.6 | 1.4 | 0.2 | setosa |
5.4 | 3.9 | 1.7 | 0.4 | setosa |
4.6 | 3.4 | 1.4 | 0.3 | setosa |
5.0 | 3.4 | 1.5 | 0.2 | setosa |
4.4 | 2.9 | 1.4 | 0.2 | setosa |
4.9 | 3.1 | 1.5 | 0.1 | setosa |
Solution 1 : Composer le HTML
On peut créer un contenu HTML assez simplement à condition de connaître les bases du HTML…
On va composer le contenu HTML et y insérer le résultat de la fonction
flextable::format(myft, type = "html")
qui retourne le code HTML d’un
flextable sous forme d’une chaîne de caractères.
raw_html <- paste(
"<!DOCTYPE html>",
"<html>",
"<head>",
"<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />",
"<meta name='viewport' content='width=device-width, initial-scale=1.0'/>",
"<title>your report title</title>",
"</head>",
"<body>",
format(myft, type = "html"),
"</body>",
"</html>"
)
Le contenu à afficher étant défini, il faut maintenant l’intégrer dans un
email et l’envoyer avec la fonction sendmailR::sendmail
.
Attention, il faut bien sûr aussi connaître les paramètres de serveur de mail que vous devez utiliser, pour l’illustration, j’utilise le service de google.
Si vous êtes dans une entreprise et que vous n’avez aucune idée de quoi je parle (serveur SMTP, quel port utiliser, existe t-il un compte pour l’envoi d’email automatique?), je vous invite à prendre un café avec quelqu’un de votre service informatique et de lui demander de vous expliquer ce qu’est un serveur SMTP.
Dans un premier temps, on définit notre contenu HTML comme tel en précisant
un Content-Type
à la valeur "text/html"
. Ce contenu doit être dans une
liste (mail_message
dans notre exemple) comme indiqué dans la documentation
de sendmail
.
library(sendmailR)
# un contenu mime
body_message <- mime_part(raw_html)
body_message$headers$`Content-Type` <- "text/html"
# le message sera composé d'un seul contenu : body_message
mail_message <- list(body_message)
Il reste à appeler la fonction principale pour envoyer l’email :
sendmail(
from = "<arthur.dent@gmail.com>",
to = "<ford.prefect@gmail.com>",
subject = "this is not a towel",
msg = mail_message,
control = list(smtpServer = "ASPMX.L.GOOGLE.COM")
)
Voici ce que peut lire Ford Prefect :
Solution 2 : Utiliser R Markdown
La technique est à peu près la même - en revanche, on ne créé pas le HTML directement, on utilise un document R Markdown. Cela offre de nombreux avantages mais ce n’est pas l’objet du billet - le sujet est trop vaste… Retenons ici que je n’ai plus à comprendre le HTML en travaillant avec R Markdown et que je peux facilement créer des contenus plus riches.
Pour l’illustration, on va utiliser un fichier R Markdown existant dans le package flextable.
an_rmd_example <- system.file(package = "flextable", "examples/rmd/demo.Rmd")
Le contenu du fichier est le suivant:
fpeek::peek_head(an_rmd_example, n = 100)
## ---
## title: "flextable example"
## ---
##
## ```{r setup, include=FALSE}
## library(knitr)
## library(flextable)
## library(officer)
## library(magrittr)
## library(data.table)
## opts_chunk$set(echo = FALSE, message = FALSE)
## ```
##
## ```{r}
## col_palette <- c("#D73027", "#F46D43", "#FDAE61", "#FEE08B",
## "#D9EF8B", "#A6D96A", "#66BD63", "#1A9850")
## cor_matrix <- cor(mtcars)
## mycut <- cut( cor_matrix,
## breaks = c(-1, -0.75, -0.5, -0.25, 0, 0.25, 0.5, 0.75, 1),
## include.lowest = TRUE, label = FALSE)
## mycolors <- col_palette[mycut]
## data <- data.frame(rowname = row.names(cor_matrix), stringsAsFactors = FALSE) %>%
## cbind(cor_matrix)
## ```
##
## ## An example
##
## ```{r}
## flextable(data) %>%
## bg(j = colnames(cor_matrix), bg = mycolors) %>%
## align(align = "center", part = "all") %>%
## compose(i = 1, j = 1, value = as_paragraph(""), part = "header") %>%
## colformat_num(j = colnames(cor_matrix), digits = 2) %>%
## autofit()
## ```
##
## ## Another example
##
## ```{r}
## ft <- flextable(head(iris))
##
## # measure column widths but only for the body part
## w_body <- dim_pretty(ft, part = "body")$widths
## # measure column widths only for the header part and get the max
## # as height value for rotated text
## h_header <- max( dim_pretty(ft, part = "header")$widths )
##
## ft <- rotate(ft, j = 1:4, rotation="btlr",part="header")
## ft <- rotate(ft, j = 5, rotation="tbrl",part="header")
##
## ft <- valign(ft, valign = "center", part = "header")
## ft <- align(ft, align = "center", part = "all")
##
## # Manage header height
## ft <- height(ft, height = h_header * 1.1, part = "header")
## # ... mainly because Word don't handle auto height with rotated headers
## ft <- hrule(ft, i = 1, rule = "exact", part = "header")
##
## ft <- set_caption(ft, caption = "iris dataset", autonum = run_autonum(bkm = "iris"))
## ft
## ```
##
##
## ## flextable - demo as_grouped_data
##
## ```{r tab.cap='mean of carbon dioxide uptake in grass plants', tab.id='CO2-id', label='CO2-label'}
## data_CO2 <- dcast(as.data.table(CO2),
## Treatment + conc ~ Type, value.var = "uptake", fun.aggregate = mean)
## data_CO2 <- as_grouped_data(x = data_CO2, groups = c("Treatment"))
##
## as_flextable( data_CO2 ) %>%
## bold(j = 1, i = ~ !is.na(Treatment), bold = TRUE, part = "body" ) %>%
## bold(part = "header", bold = TRUE ) %>%
## width(width = 1.5) %>%
## compose(i = ~ !is.na(conc), j = "conc",
## value = as_paragraph(
## as_chunk(conc, formatter = function(x) sprintf("%.0f", x))
## )
## ) %>% add_footer_lines("dataset CO2 has been used for this flextable") %>%
## bg(bg = "#FFFFFF", part = "footer") %>%
## set_header_labels(conc = "Concentration") %>%
## width(width = c(1.5, 1, 1))
## ```
On génère le fichier HTML avec la fonction rmarkdown::render
puis le contenu
de ce fichier est stocké dans une chaîne de caractère :
out <- tempfile(fileext = ".html")
rmarkdown::render(an_rmd_example, output_file = out)
raw_html <- paste(readLines(out), collapse = "")
On peut désormais reprendre les mêmes opérations que précédemment :
body_message <- mime_part(raw_html)
body_message$headers$`Content-Type` <- "text/html"
mail_message <- list(body_message)
sendmail(
from = "<arthur.dent@gmail.com>",
to = "<ford.prefect@gmail.com>",
subject = "this is not a towel",
msg = mail_message,
control = list(smtpServer = "ASPMX.L.GOOGLE.COM")
)
Complément : ajouter une pièce jointe
Pour l’illustration, on va envoyer aussi le fichier R Markdown comme pièce attachée. Dans la pratique, on a le plus souvent envie de joindre un fichier de données, la démarche est la même.
Il faut définir une nouvelle partie MIME et l’ajouter dans la liste mail_message
:
rmd_attachment <- mime_part(x = an_rmd_example, name = "demo_html.Rmd")
mail_message <- list(body_message, rmd_attachment)
sendmail(
from = "<arthur.dent@gmail.com>",
to = "<ford.prefect@gmail.com>",
subject = "this is not a towel",
msg = mail_message,
control = list(smtpServer = "ASPMX.L.GOOGLE.COM")
)
Commentaires
Attention à ne pas abuser de l’outil sendmailR
- nous recevons déjà tous
beaucoup TROP de mails - n’hésitez pas à regarder aussi du côté de slackr
écrit par Bob Rudis et beaucoup d’autres. Egalement, faites attention à la taille
du message que vous souhaitez envoyer (par exemple, n’envoyez pas des emails de 10 Mo).
Utilisez R Markdown pour aider à la composition de vos contenus depuis R. Si vous avez peu de contenu à envoyer, ce n’est pas vraiment critique ; mais si vous devez envoyer des tableaux, du texte, tout en prenant en compte des paramètres - R Markdown sera votre ami.
Ce post ne couvre qu’une petite partie d’un vaste sujet. Il faudrait idéalement couvrir aussi les problèmes engendrés par l’insertion de javascript, parler des pixels qui permettent de savoir si votre email est consulté, expliquer comment insérer des images… Peut-être une autre fois :)
Aller plus loin
Vous souhaitez aller plus loin dans la dissémination de vos reporting ; contactez nous et nous échangerons sur vos besoins.
Suivez nous: - Sites recommandés: R-bloggers R weekly Twitter #rstats Jobs for R-users