knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
library(blastula)
library(ggplot2)
library(glue)

Before we get to the process of creating an HTML email message, it's a good idea to learn about the model of such a message in blastula. Here is a diagram, and it doesn't contain too many layout components (because simplicity in HTML email is a good thing).


knitr::include_graphics("html_email_model.svg", dpi = 300)


The main components (from top to bottom) are the header, the body, and the footer. The body content is inside of a wrapper that functions to differentiate the main content from whatever is in the header and footer (above and below the body).

Another thing to note is that the HTML used is responsive. Viewing the HTML in a viewport that is greater than or equal to 640 pixels will be different than seeing it with a viewport that's smaller. This is important because email on mobile devices will often take on the latter view, which is optimized for smaller display widths (e.g., larger font sizes, decreased vertical space between elements, resized images, etc.).

When using blastula, we don't have to worry much about either view since the API is designed to make emails look their best in both of them. Because we can preview the email message before sending it out, we have a chance to manually resize the browser and inspect the message in a variety of display widths.

Creating a Simple HTML Email Message

For those times where we'd only want to send a simple HTML email message, we can use the compose_email() function and focus on adding text content to the body component. So let's create a simple email message using some plain text inside body.

compose_email(
  body = 
"Hello,

I just wanted to let you know that the thing that you asked me for is ready to pick up. So, come over and do that.

Cheers
")
knitr::include_graphics("compose_simple-wide.png", dpi = 300)
knitr::include_graphics("compose_simple-narrow.png", dpi = 300)

This is how it looks, depending on the display width (wide at top, narrow below that).


A preview of the HTML email message should appear in the Viewer. Try resizing the Viewer to see how it responds to the different width thresholds.

More Sophisticated Email Text

A good strategy for longer and more complicated text inputs is to use the glue package. That package allows us to use string interpolation (and avoid the use of paste() or paste0()). Variables in the global workspace can be included in the curly braces of a glue() string expression, and, any R expressions in { } will be evaluated.

We can include longer R statements inside of the curly braces (like {paste0(format(Sys.time(), "%A, %B "), format(Sys.time(), "%d") %>% as.numeric(), ", ", format(Sys.time(), "%Y"))}), however, that would be unwieldy. It's better to generate local variables with R statements and just use those variables inside the { }.

Here is an example of the same email message body as in the last example, but using glue to preprocess our text:

what <- "thing"
salutation <- "Cheers"

body_text <-
  glue(
    "
Hello,

I just wanted to let you know that the {what}
that you asked me for is ready to pick up. So,
come over and do that.

{salutation}
"   
  )

compose_email(body = body_text)

Any literal quotation marks inside the braces should be escaped using a single \. Blank lines separating blocks of text result in new paragraphs.

Using Markdown Text via the md() Function

Markdown text can be used as input for the body, header, and footer arguments. To opt into using Markdown formatting, call the md() text helper function on any of these text elements. We can use the usual Markdown-formatting you know and you'll get italicized text, bold text, lists, links, etc. Have a look at this reference page to quickly understand how to use Markdown. The blastula package internally uses the commonmark R package to perform the conversion from Markdown to HTML.

A few notes on code style and options. It's good to left-align the text in the code example since it will reduce the risk of having four or more spaces after a line break, which will result in text like this when using Markdown formatting through md().

In the next example, let's first store the result of that statement in a local variable (sending_date). Then, the variable will be placed in the footer of the message (using the footer argument) along with leading text.

#
# Prepare the text inputs
#

sender_name <- "Shelly"

sending_date <-
  paste0(
    format(Sys.time(), "%A, %B "),
    format(Sys.time(), "%d") %>% as.numeric(),
    ", ",
    format(Sys.time(), "%Y")
  )

body_text <-
  glue(
    "
Hello,

I just wanted to let you know that the *thing* that
you asked me for is ready to pick up. So, come over
and do that.

Cheers,

{sender_name}
"    
  ) %>% md()

footer_text <- glue("Sent on {sending_date}.")

# Compose the email message
compose_email(
  body = body_text,
  footer = footer_text
)
knitr::include_graphics("compose_interpolation_stmt-wide.png", dpi = 300)

Complicated string formatting goes into variables, the variables go into the email components


Content in the footer and header sections is styled differently than body content (footer text will be somewhat smaller for one thing). The main message typically goes into the body whereas supplementary information works better in the footer.

Adding an External Image to an HTML Email

Although the rules for images in HTML email have changed often, the method that seems to work reasonably well these days is to use external images. There is a bit of upfront work in getting the image hosted somewhere but the payoff is fast page loads in email clients. The blastula package has a function which takes some of the pain out of getting images to a hosting service, it is the add_imgur_image() function. Imgur is a fun site for sure (gifs galore!) but did you know that they have an API to make image uploading easy? They do, and this function takes advantage of that.

Here's an example of an email that includes a local image that is deployed to Imgur (available at https://i.imgur.com/8uTB2Py.jpg) for indefinite hosting.

imgur_image <- 
  "<a href=\"#\"><img src=\"https://i.imgur.com/8uTB2Py.jpg\" style=\"max-width: 600px; width: 100% !important; display: block; padding: 0; border: 0 !important;\" border=\"0\"></a>"
# Send your image to Imgur with a Client Key;
# the result is specially-crafted <img> tag
# imgur_image <-
#   add_imgur_image(
#     image = "rickenbacker_4001_1972_fireglo.jpg",
#     client_id = "<YOUR CLIENT ID>"
#   )

#
# Create the `body_text` and then the
# email message with `compose_email()`
#

body_text <-
  glue(
    "
Hello,

I just wanted to let you know that the **1972 Rickenbacker
4001** is here to pick up. Here is a picture of it:

{imgur_image}

Cheers,

{sender_name}
"
  ) %>% md()

compose_email(body = body_text)
knitr::include_graphics("compose_imgur_local_image-wide.png", dpi = 300)

Once you get that Imgur Client ID, this is really easy


This is how you get the all-important Client ID from Imgur. First, get an account with Imgur! Once that's a thing accomplished, we can get the Client-ID key for the Imgur API. This can be easily done by going visiting the API registration page while signed-in to register an application. Give it a name---any name you can think of---and be sure to select the OAuth 2 authorization type without a callback URL radio button (the second in the list). After filling in the other necessary information bits and proving that you're not a robot, you'll receive the Client ID key! You'll then have unfettered access to use any images, including animated gifs, in an HTML email message.

Wait, there's more! Since this is R and we care about ggplot2, we can directly pass in a ggplot object to add_imgur_image() and expect a nice ggplot image to appear in the email message. Here's an example of how that works:

imgur_image <- 
  "<a href=\"#\"><img src=\"https://i.imgur.com/biMpEEA.png\" style=\"max-width: 600px; width:100% !important; display: block; padding: 0; border: 0 !important;\" border=\"0\"></a>"
# Create the plot data
variety <- rep(LETTERS[1:7], each = 40)
treatment <- rep(c("high", "low"), each = 20)
note <- seq(1:280) + sample(1:150, 280, replace = TRUE)
data <- data.frame(variety, treatment, note)

# Create the plot
the_plot <-
  ggplot(data, aes(x = variety, y = note, fill = treatment)) + 
  geom_boxplot()

# Send your ggplot to Imgur with a Client Key;
# again, you get an <img> tag that works for email
# imgur_image <-
#   add_imgur_image(
#     image = the_plot,
#     client_id = "<YOUR CLIENT ID>"
#   )

#
# Create the `body_text` and then the
# email message with `compose_email()`
#

body_text <-
  glue(
    "
Hello,

I just wanted to let you know that the *ggplot* you \\
wanted to see is right here, in this email:

{imgur_image}

Cheers,

{sender_name}
"
  ) %>% md()

compose_email(body = body_text)
knitr::include_graphics("compose_imgur_ggplot-wide.png", dpi = 300)

A ggplot in your email message


I don't know about you but I'd love to get a ggplot in my email.

Wrapping Up

We now know how to send really simple email messages with just some text, and, slightly more complex messages including those with images inside. Imgur really saves the day when it comes to hosting images as their API service is very permissive and getting access is not at all difficult!



rich-iannone/blastula documentation built on Dec. 10, 2019, 11:44 p.m.