rpandersendmailr

how do you convert a data frame to a table to send as an email body


I have this data frame:

library(sendmailR)
library(pander)

dput(s)
structure(list(Description = c("ServerA", "ServerB", "ServerC", 
"ServerD", "ServerE", "ServerF"), Value = c("2", "2", "100", 
"100", "80", "20")), .Names = c("Description", "Value"), row.names = c(NA, 
6L), class = "data.frame")

I would like to put this data frame in a nice looking table and email it to some people.

I tried it with pandoc but the table looks very plain:

 t<-pandoc.table.return(s, caption="Server CPU Utilization")

    from <- "user@example.com"
    to <- c("end_users@example.com")
    subject <- paste(Sys.time()," Servers CPU utilization")
    body <- t                
    mailControl=list(smtpServer="mailhost.example.net")

    sendmail(from=from,to=to,subject=subject,msg=body,control=mailControl)

Is there any other way to format a data frame into nice looking table to send as email? Table has to be in the email body, not as an attachment.


Solution

  • What do you mean under?

    the table looks very plain

    You may also opt for some other markdown format for the table, like passing style = 'grid' to pandoc.table.return, if you do not like the default multiline format. Or you mean the table falls apart/looks ugly with a non-monospace font? The result will depend on the e-mail client, so I would rather opt for sending a HTML mail and specifying a monospace font family, or render the table in HTML.


    A quick demo for the HTML version:

    1. Initialize the required R packages:

      library(sendmailR)
      library(xtable)
      
    2. Build a HTML body with concatenating the static part with dynamically created HTML table:

      msg <- mime_part(paste('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
      Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
      </head>
      <body>', print(xtable(s), type = 'html'), ',</body>
      </html>'))
      
    3. Override the content-type with an undocumented hack:

      msg[["headers"]][["Content-Type"]] <- "text/html"
      
    4. Send the mail to your specified recipient with the given subject:

      from    <- '<foo@example.com>'
      to      <- '<bar@example.com>'
      subject <- 'HTML table in the body'
      body    <- list(msg)
      sendmail(from, to, subject, body)
      

    Combining the markdown and HTML versions:

    msg <- mime_part(paste('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
    Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    </head>
    <body><div style="font-family: monospace;">', gsub(' ', '&nbsp;', paste(pander.return(s, caption = "Server CPU Utilization", style = 'grid'), collapse = '<br>')), '</div></body>
    </html>'))
    msg[["headers"]][["Content-Type"]] <- "text/html"
    sendmail(from, to, subject, list(msg))
    

    The trick here is to set the font-family to monospace with inline CSS, also replacing all spaces in the document with non-breaking space. Another (and rather more elegnat) workaround might be to put the markdown between pre HTML tags:

    msg <- mime_part(paste('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
    Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    </head>
    <body><pre>', paste(pander.return(s, caption = "Server CPU Utilization", style = 'grid'), collapse = '\n'), '</pre></body>
    </html>'))
    msg[["headers"]][["Content-Type"]] <- "text/html"
    sendmail(from, to, subject, list(msg))