blastula icon indicating copy to clipboard operation
blastula copied to clipboard

{gt} table missing colours in Outlook Desktop due to missing PR_HTML MAPI property

Open leungi opened this issue 5 years ago • 13 comments

gt table renders as designed when viewed in mobile devices and Outlook365, but loses colour in Outlook Desktop.

Reprex

library(blastula)
library(glue)
library(tidyverse)
library(gt)

# create raw data
df <- tibble(`Non Risky` = c(9, 12, 21), `Risky` = c(1, 0, 1)) %>%
  mutate(
    Total = `Non Risky` + Risky,
    `At Risk Percentage` = round(Risky / Total * 100, 2)
  )

# create table object for email attachment
tbl <- df %>%
  gt() %>%
  tab_style(
    style = cell_text(color = "#f8f8ff"),
    locations = cells_column_labels(columns = everything())
  ) %>%
  tab_options(
    row.striping.include_table_body = FALSE,
    column_labels.font.weight = "bold",
    column_labels.background.color = "#000000"
  ) %>%
  # fmt_percent(vars(`At Risk Percentage`), decimals = 1) %>%
  data_color(
    columns = vars(Risky),
    colors = scales::col_bin(
      c("#ff0000", "#458B00"),
      bins = 2,
      domain = c(0, 100)
    ),
    alpha = 0.8
  ) %>%
  as_raw_html()

date_time <- add_readable_time()

email <-
  compose_email(
    body = tbl,
    footer = md(c("Email sent on ", date_time, "."))
  )

email

Outlook365

image

Outlook Desktop

image

Issue

According to Microsoft support team:

The MAPI Property PR_HTML is missing on the attached message.

Without it, the Outlook application is unable to load the "HTML" message and actually display it, this means that we will rely on the PR_BODY_W property to display the body, which in this case is not going to be able to perform as we expect. Applying the PT_HTML content of the message to the message, it now displays correctly.

This MAPI property needs to be created when generating the email message.

References

Outlook MAPI

leungi avatar May 23 '20 06:05 leungi

It looks like the mail should be sent not using the body attribute, but as a html attachment and that is used for the body currently.

https://stackoverflow.com/questions/15828226/sending-messages-with-html-contents-using-the-mapi-control-in-vb6

yonicd avatar Oct 29 '20 21:10 yonicd

It looks like the mail should be sent not using the body attribute, but as a html attachment and that is used for the body currently.

https://stackoverflow.com/questions/15828226/sending-messages-with-html-contents-using-the-mapi-control-in-vb6

@yonicd : thanks for comment; seems like you may have a solution 😆 Any guidance would be 🙏

I tried the below previously, but with no success; when tested on mobile and desktop mail client, attachment doesn't render on its own, like some .html would.

library(ggplot2)
library(blastula)

plot <-
  ggplot(
    data = mtcars,
    aes(
      x = disp, y = hp,
      color = wt, size = mpg
    )
  ) +
  geom_point()

plot_html <-
  add_ggplot(plot_object = plot)

htmltools::save_html(plot_html, "plot_html")

email <-
  compose_email(
    body = ""
  )

email <- add_attachment(email,
  "plot_html",
  content_type = mime::guess_type("plot_html")
)

email %>%
  smtp_send(
    to = "[email protected]",
    from = "[email protected]",
    subject = "Test",
    credentials = creds_key("me")
  )

leungi avatar Oct 29 '20 22:10 leungi

looks like this is a more basic problem.

The email is sent out internally by curl::send_mail which converts the message into a format called RF 2822

Searching for that format with HTML gave back this hit in wiki

Email software that complies with RFC 2822 is only required to support plain text, not HTML formatting. Sending HTML formatted emails can therefore lead to problems if the recipient's email client does not support it. In the worst case, the recipient will see the HTML code instead of the intended message.

In my case this was what happened with &percnt; that i made with gt::fmt_percent not being rendered in the outlook client.

Which is a long winded way of saying that this issue probably wont be resolved any time soon.

Maybe @jcheng5 or @jeroen the maintainers of {curl} would have more insight into this problem.

yonicd avatar Oct 29 '20 23:10 yonicd

option b would be to port the table to an image and embed the image in the mail a la {reprex}

yonicd avatar Oct 29 '20 23:10 yonicd

library(dplyr)
library(gt)

df <- tibble(`Non Risky` = c(9, 12, 21), `Risky` = c(1, 0, 1)) %>%
  mutate(
    Total = `Non Risky` + Risky,
    `At Risk Percentage` = round(Risky / Total, 2)
  )

# create table object for email attachment
img_file_html <- df %>%
  gt() %>%
  fmt_percent(vars(`At Risk Percentage`), decimals = 1)%>%
  gt::gtsave('tbl2.png')%>%
  add_image(file = 'tbl.png')

email <-
  compose_email(
    body = md(
      c(
        "Hello,

Here is an table:\n",
img_file_html
      )
    )
  )

email%>%
  blastula::smtp_send(
    to = '[email protected]',
    from = '[email protected]',
    subject = 'html test',
    credentials = blastula::creds_key('me')
  )

yonicd avatar Oct 29 '20 23:10 yonicd

option b would be to port the table to an image and embed the image in the mail a la {reprex}

I was thinking along the same line, similar to gt::gtsave(), somehow using webshot.

Just got to do more experimenting, since I'm generating the table from raw html in this case, not gt object.

leungi avatar Oct 29 '20 23:10 leungi

I don't think curl does any conversion? The manual just states that you need to use RFC2822 for the email header format, i.e. the from, to, cc, bcc, subject. But I think curl will send whatever body content that you give it....

jeroen avatar Oct 29 '20 23:10 jeroen

@leungi you can use snapper it gets around the need for selenium.

yonicd avatar Oct 29 '20 23:10 yonicd

@jeroen would converting the content to raw do anything to the formating? (that sounds implausible)

library(dplyr)
library(gt)

df <- tibble(`Non Risky` = c(9, 12, 21), `Risky` = c(1, 0, 1)) %>%
  mutate(
    Total = `Non Risky` + Risky,
    `At Risk Percentage` = round(Risky / Total, 2)
  )

# create table object for email attachment
tbl <- df %>%
  gt() %>%
  fmt_percent(vars(`At Risk Percentage`), decimals = 1)

email <-
  compose_email(
    body = tbl
    )

Output in Outlook Office 365

2020-10-29 19_48_53-Sent Items - Yoni Sidi@sagerx com - Outlook

If I open the email into the browser:

2020-10-29 19_52_49-mhtml_file___C__Users_jonathan sidi_AppData_Local_Microsoft_Windows_INetCache_Co

session info

- Session info ----------------------------------------------------------------------------
 setting  value                       
 version  R version 4.0.2 (2020-06-22)
 os       Windows 10 x64              
 system   x86_64, mingw32             
 ui       RStudio                     
 language (EN)                        
 collate  English_United States.1252  
 ctype    English_United States.1252  
 tz       America/New_York            
 date     2020-10-29                  

- Packages --------------------------------------------------------------------------------
 !  package       * version    date       lib source                             
 P  assertthat      0.2.1      2019-03-21 [?] CRAN (R 4.0.2)                     
    backports       1.1.10     2020-09-15 [1] CRAN (R 4.0.2)                     
 P  base64enc       0.1-3      2015-07-28 [?] CRAN (R 4.0.0)                     
 P  blastula      * 0.3.2      2020-05-19 [?] CRAN (R 4.0.2)                     
 P  callr           3.4.3      2020-03-28 [?] CRAN (R 4.0.2)                     
 P  cellranger      1.1.0      2016-07-27 [?] CRAN (R 4.0.2)                     
 P  checkmate       2.0.0      2020-02-06 [?] CRAN (R 4.0.2)                     
 P  cli             2.0.2      2020-02-28 [?] CRAN (R 4.0.2)                     
 P  clipr           0.7.0      2019-07-23 [?] CRAN (R 4.0.2)                     
 P  codetools       0.2-16     2018-12-24 [?] CRAN (R 4.0.2)                     
 P  colorspace      1.4-1      2019-03-18 [?] CRAN (R 4.0.2)                     
    commonmark      1.7        2018-12-01 [1] CRAN (R 4.0.2)                     
 P  crayon          1.3.4      2017-09-16 [?] CRAN (R 4.0.2)                     
 P  curl            4.3        2019-12-02 [?] CRAN (R 4.0.2)                     
 P  data.table      1.13.0     2020-07-24 [?] CRAN (R 4.0.2)                     
 P  desc            1.2.0      2018-05-01 [?] CRAN (R 4.0.2)                     
 P  details         0.2.1      2020-09-08 [?] local                              
    digest          0.6.27     2020-10-24 [1] CRAN (R 4.0.3)                     
 P  dplyr         * 1.0.2      2020-08-18 [?] CRAN (R 4.0.2)                     
 P  ellipsis        0.3.1      2020-05-15 [?] CRAN (R 4.0.2)                     
 P  evaluate        0.14       2019-05-28 [?] CRAN (R 4.0.2)                     
 P  fansi           0.4.1      2020-01-08 [?] CRAN (R 4.0.2)                     
 P  farver          2.0.3      2020-01-16 [?] CRAN (R 4.0.2)                     
 P  flextable       0.5.11     2020-09-09 [?] CRAN (R 4.0.2)                     
 P  forcats         0.5.0      2020-03-01 [?] CRAN (R 4.0.2)                     
 P  fs              1.5.0      2020-07-31 [?] CRAN (R 4.0.2)                     
 P  gdtools         0.2.2      2020-04-03 [?] CRAN (R 4.0.2)                     
 P  generics        0.0.2      2018-11-29 [?] CRAN (R 4.0.2)                     
 P  getPass         0.2-2      2017-07-21 [?] CRAN (R 4.0.2)                     
 P  ggplot2         3.3.2      2020-06-19 [?] CRAN (R 4.0.2)                     
 P  ggrepel         0.8.2      2020-03-08 [?] CRAN (R 4.0.2)                     
 P  glue          * 1.4.2      2020-08-27 [?] CRAN (R 4.0.2)                     
 P  gt            * 0.2.2      2020-08-05 [?] CRAN (R 4.0.2)                     
 P  gtable          0.3.0      2019-03-25 [?] CRAN (R 4.0.2)                     
 P  gtsummary       1.3.5      2020-09-29 [?] CRAN (R 4.0.2)                     
 P  haven           2.3.1      2020-06-01 [?] CRAN (R 4.0.2)                     
 P  here            0.1        2017-05-28 [?] CRAN (R 4.0.2)                     
 P  hms             0.5.3      2020-01-08 [?] CRAN (R 4.0.2)                     
 P  htmltools       0.5.0      2020-06-16 [?] CRAN (R 4.0.2)                     
 P  httr            1.4.2      2020-07-20 [?] CRAN (R 4.0.2)                     
 P  igraph          1.2.5      2020-03-19 [?] CRAN (R 4.0.2)                     
 P  jsonlite        1.7.1      2020-09-07 [?] CRAN (R 4.0.2)                     
 P  keyring         1.1.0      2018-07-16 [?] CRAN (R 4.0.3)                     
 P  knitr           1.30       2020-09-22 [?] CRAN (R 4.0.3)                     
 P  labelled        2.7.0      2020-09-21 [?] CRAN (R 4.0.3)                     
 P  lifecycle       0.2.0      2020-03-06 [?] CRAN (R 4.0.2)                     
 P  magrittr      * 1.5        2014-11-22 [?] CRAN (R 4.0.2)                     
 P  mime            0.9        2020-02-04 [?] CRAN (R 4.0.0)                     
 P  munsell         0.5.0      2018-06-12 [?] CRAN (R 4.0.2)                     
 P  officer         0.3.14     2020-09-07 [?] CRAN (R 4.0.2)                     
 P  pillar          1.4.6      2020-07-10 [?] CRAN (R 4.0.2)                     
 P  pkgconfig       2.0.3      2019-09-22 [?] CRAN (R 4.0.2)                     
 P  plyr            1.8.6      2020-03-03 [?] CRAN (R 4.0.2)                     
 P  png             0.1-7      2013-12-03 [?] CRAN (R 4.0.0)                     
 P  processx        3.4.3      2020-07-05 [?] CRAN (R 4.0.2)                     
 P  ps              1.3.4      2020-08-11 [?] CRAN (R 4.0.2)                     
 P  purrr           0.3.4      2020-04-17 [?] CRAN (R 4.0.2)                     
 P  qs              0.23.3     2020-10-05 [?] CRAN (R 4.0.3)                     
 P  R6              2.4.1      2019-11-12 [?] CRAN (R 4.0.2)                     
 P  RApiSerialize   0.1.0      2014-04-19 [?] CRAN (R 4.0.0)                     
 P  Rcpp            1.0.5      2020-07-06 [?] CRAN (R 4.0.2)                     
 PD RcppParallel    5.0.2      2020-06-24 [?] CRAN (R 4.0.2)                     
 P  readr           1.3.1      2018-12-21 [?] CRAN (R 4.0.2)                     
 P  readxl          1.3.1      2019-03-13 [?] CRAN (R 4.0.2)                     
 P  rematch2        2.1.2      2020-05-01 [?] CRAN (R 4.0.2)                     
 P  remedy          0.1.1      2020-08-26 [?] github (thinkr-open/remedy@eb8fbdd)
 P  renv            0.12.0     2020-08-28 [?] CRAN (R 4.0.2)                     
    rlang           0.4.8      2020-10-08 [1] CRAN (R 4.0.3)                     
    rmarkdown       2.4.4      2020-10-15 [1] Github (rstudio/rmarkdown@64e8307) 
 P  rprojroot       1.3-2      2018-01-03 [?] CRAN (R 4.0.2)                     
 P  rstudioapi      0.11       2020-02-07 [?] CRAN (R 4.0.2)                     
    sasdrive        0.0.1      2020-10-15 [1] Github (sagerx/sasdrive@a788cda)   
 P  sass            0.2.0      2020-03-18 [?] CRAN (R 4.0.2)                     
 P  scales          1.1.1      2020-05-11 [?] CRAN (R 4.0.2)                     
 P  sessioninfo     1.1.1      2018-11-05 [?] CRAN (R 4.0.2)                     
 P  snakecase     * 0.11.0     2019-05-25 [?] CRAN (R 4.0.2)                     
 P  stringfish      0.14.2     2020-09-05 [?] CRAN (R 4.0.3)                     
 P  stringi         1.4.6      2020-02-17 [?] CRAN (R 4.0.0)                     
 P  stringr         1.4.0      2019-02-10 [?] CRAN (R 4.0.2)                     
 P  systemfonts     0.3.2      2020-09-29 [?] CRAN (R 4.0.2)                     
    targets       * 0.0.0.9002 2020-10-27 [1] Github (wlandau/targets@fd9b7a4)   
 P  tibble          3.0.3      2020-07-10 [?] CRAN (R 4.0.2)                     
 P  tidyr           1.1.2      2020-08-27 [?] CRAN (R 4.0.2)                     
 P  tidyselect      1.1.0      2020-05-11 [?] CRAN (R 4.0.2)                     
 P  utf8            1.1.4      2018-05-24 [?] CRAN (R 4.0.2)                     
 P  uuid            0.1-4      2020-02-26 [?] CRAN (R 4.0.0)                     
 P  vctrs           0.3.4      2020-08-29 [?] CRAN (R 4.0.2)                     
 P  webshot         0.5.2      2019-11-22 [?] CRAN (R 4.0.2)                     
    withr           2.3.0      2020-09-22 [1] CRAN (R 4.0.2)                     
 P  xfun            0.18       2020-09-29 [?] CRAN (R 4.0.3)                     
 P  xml2            1.3.2      2020-04-23 [?] CRAN (R 4.0.2)                     
 P  yaml            2.2.1      2020-02-01 [?] CRAN (R 4.0.2)                     
 P  zip             2.1.0      2020-08-10 [?] CRAN (R 4.0.2)                     

[2] C:/Users/jonathan.sidi/AppData/Local/Temp/Rtmp0MRN9C/renv-system-library

 P -- Loaded and on-disk path mismatch.
 D -- DLL MD5 mismatch, broken installation.


yonicd avatar Oct 29 '20 23:10 yonicd

Hi all - any progress on resolving this, i'm running into the same issues with kable, kableExtra , and formattable. Using raw html seems to work for gt (and scales well) but not for the gtextras package of which the css is stripped on outlook. Would prefer not to add image as solution as this doesn't scale well on mobile.

rprops avatar Nov 03 '21 07:11 rprops

Still an issue for me too

munoztd0 avatar May 12 '22 09:05 munoztd0

Well after looking a lot into it, it seems that the issue is outlook 365 not rendering in html but in rich text files which don't have the same CSS propeties.

More here -> https://stackoverflow.com/questions/38890039/office365-outlook-mail-html-email-render

munoztd0 avatar Jun 30 '22 14:06 munoztd0

So following up on this in 2023, are there any R packages that reliably produce formatted tables (especially conditional formatting) that will render properly in outlook 365? My experiences so far:

  • Kable+KableExtra are semi-functional. Most things are broken (including spacing and separations) but you will get conditional formatting on what looks like plain text.
  • GT seems about the same.
  • xtable will produce something that actually looks like a table, but will be somewhat mangled in terms of spacing/wrapping and has very little customizability.

About the only thing I've found reliable with outlook365 is attaching an html file, or embedding a non-interactive image.

D3SL avatar Jul 24 '23 09:07 D3SL