Sending an Email from R with Blastula to Groups of Students

One component when teaching is needing to send e-mails to students that contain announcements or provide feedback. Announcements serve as important reminders and a means to ensure resources are surfaced to students in a condensed way without interacting with a learning management system (LMS) that isn’t streamlined. Meanwhile, feedback is geared to provide insight on how the student is progressing on learning. Specifically, the feedback that is most troublesome to distribute is that with group-related projects.

With this being said, communications to students need to come from an official university e-mail account. Alas, setting up means to send e-mails outside of approved applications is problematic. Furthermore, R doesn’t offer many packages for working within the Exchange/Office365 oriented world.

Overview of E-mail Generation Packages for R

Unfortunately, that means that gmailr by Jim Hester – which connects only to Google’s GMail service – is out.

If we go further down the rabbit’s nest, we would find mailR and sendmailR. As I work mainly on a Mac, the first part of new package adoption is checking to see if there is a dependency on rJava. The rJava package is a headache to properly configure and, unlike C++, must be present for the CRAN package binary to work. If I even try to use the mailR package, I would get:

library("mailR")
# Error: package or namespace load failed for 'mailR':
#  .onLoad failed in loadNamespace() for 'rJava', details:
#   call: dyn.load(file, DLLpath = DLLpath, ...)
#   error: unable to load shared object
# '/Library/Frameworks/R.framework/Versions/3.6/Resources/library/rJava/libs/rJava.so':
#   dlopen(/Library/Frameworks/R.framework/Versions/3.6/Resources/library/rJava/libs/rJava.so, 6): Library not loaded: 
# /Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home/lib/server/libjvm.dylib
#   Referenced from: /Library/Frameworks/R.framework/Versions/3.6/Resources/library/rJava/libs/rJava.so
#   Reason: image not found

Then, we’re left with sendmailR. Alas, this just isn’t that powerful of a package.

Having said this, there is one more entrant: blastula by Richard Iannone. If you’ve ever tried to send automated e-mail before, this package revolutionizes the concept. Once you’ve used it, there is no going back.

Setup Credentials for Bastula

One of the first steps with bastula is to setup an SMTP credential. These credentials will allow for e-mail to be sent from R easily. Moreover, the overarching process is painless.

For UIUC, the approach taken is:

install.packages(c("blastula", "keyring"))

# Run once to generate credentials
blastula::create_smtp_creds_key(
  id = "UIUCExchange",          # Name the Credential
  user = "netid@illinois.edu",  # User E-mail Address
  provider = "office365",       # Provider
  use_ssl = TRUE                # Ensure SSL is used
)

Sample e-mail meta data

When sending e-mails to groups of students, the e-mail sent to each group will have a similar structure with only slight changes related to specific feedback. Approaching e-mail construction in this manner provides a way for automatically composing and sending uniform e-mails. Moreover, the feedback is no longer codified in a single LMS system and can easily be reference or added onto to future assignments.

For generating group e-mails, the most important part is the meta-data for each group alongside of a message. Metadata in this case is:

What is the group identifier? What is the group name? Who belongs to the group?

In practice, this can be structured like so:

# Randomly generate some data
n = 5

email_group_df = data.frame(
  group_id = seq_len(n),
  group_shortname = replicate(n, paste0(sample(letters, 10), collapse = "")),
  group_emails = replicate(n, paste0("netid",sample(10, 2), "@illinois.edu", collapse = ";")),
  group_msg = replicate(n, paste0("- name, netid",sample(10, 2), "@illinois.edu", collapse = "\n\n"))
)

email_group_df
group_id group_shortname group_emails group_msg
1 iqdhjngeut netid2@illinois.edu;netid3@illinois.edu - name, netid2@illinois.edu;- name, netid1@illinois.edu
2 lomsjetihu netid10@illinois.edu;netid2@illinois.edu - name, netid3@illinois.edu;- name, netid4@illinois.edu
3 qzbiutxosf netid4@illinois.edu;netid3@illinois.edu - name, netid1@illinois.edu;- name, netid9@illinois.edu
4 ulogyhbtms netid5@illinois.edu;netid8@illinois.edu - name, netid4@illinois.edu;- name, netid10@illinois.edu
5 otdqhvxurm netid6@illinois.edu;netid3@illinois.edu - name, netid5@illinois.edu;- name, netid9@illinois.edu

Templating and Sending E-mail

With the group data in hand and formatted nicely, the next step is to write an e-mail template. There are three ways to structure the template with: text, using markdown via blastula::md(), or using block-based HTML via blastula::blocks(). I haven’t explored yet the

For simplicity, I’ve opted to create a function that covers the template.

library(blastula)
library(glue)

group_email_template = function(group_data) {

  # Customize e-mail title
  title = group_data %>%
            glue_data("[STAT 430 - FDL] {group_id} {group_shortname} Roster")
            
  # Construct the e-mail for the Team.
  email = group_data %>% 
    glue_data(
      "Team **{group_shortname}**,\n\n\n\n",
      "Hope all is well! In this e-mail, we details of your team assignment. \n\n\n\n",
      "**Team ID**: {group_id} \n\n\n\n",
      "The following students are part of your team:\n\n\n\n",
      "{group_msg} \n\n\n\n"
    ) %>%
    md() %>%
    compose_email(title = title)
  
  out = list("email" = email, "title" = title)
  
  return(out)
}

Next, let’s construct and send the e-mail for each team.

for (i in seq_len(nrow(email_group_df))) {
  # Retrieve current team
  group_data = email_group_df[i, ] 
  
  # Construct the e-mail using our custom template.
  # Returns a list with `email` and `title`
  email_contents = group_email_template(group_data)

  # Generate a to-field
  to = strsplit(group_data$group_emails, ";")[[1]]

  # Send e-mail
  email_contents$email %>%
    smtp_send(
      from = "netid@illinois.edu",
      to = to,
      subject = email_contents$title,
      credentials = creds_key(id = "UIUCExchange")
    )
}

Fin

Voila! All the groups now have an e-mail with the same fundamental structure but specific content. This process was done seamlessly as blastula handled the difficulties with authentication and e-mail formatting.

comments powered by Disqus