Sending Automated Emails with Cron Jobs

It is nice to be able to automate something, and have programmatic data pulls. Then wrangle the results and email them to key stakeholders. This is a quick tutorial on how to do that with R and cron jobs, especially with cronR package.

Peter Higgins https://higgi13425.github.io/medical_r/
01-23-2024

Getting Started with Emails and Blastula

There is a super-helpful YouTube video from ggnot, which goes over how to do this with GitHub Actions.

For some variety, I decided to do this with cron jobs. I have a server that I can use to automate this.

I am going to use the blastula package to send emails. It is a great package, but it needs some setup.

I set up a new project on the higginslab-server.

Then I created an R script named ‘auto-email with blastula.R’ and saved it in the project folder.

Jumping out to outlook.com

I needed an outgoing email address and credentials. I created a new email address on outlook.com. I used the email address and password to create a new file in the project folder called ‘outlook_server_creds’.

I did this in the R script. First, I loaded {blastula} and {here} Then I created the credentials file.

library(blastula)
library(here)

# create_smtp_creds_file(file = "outlook_server_creds",
                       # user = "higgins-server@outlook.com",
                      # provider = "outlook")

This prompts me to enter the password for the email address. I did that, and it created the file in the same project folder.

Creating the email

Now I use an Rmarkdown file to create the email. I could also use quarto to create the email. I am going to use the {here} package to make sure that the email is created in the project folder.

This is pretty standard R markdown.
The YAML header looks like this:
---
title: "blastula_email"
output: blastula::blastula_email
date: "2024-01-24"
---
Error: <text>:6:0: unexpected end of input
4: date: "2024-01-24"
5: ---
  ^

Then I use a setup chunk and load the packages I need.

knitr::opts_chunk$set(echo = TRUE)

Then the rest of the email can be anything in Rmarkdown.

Example email starts here

Including Code

This is a test. I can run code

summary(cars)
     speed           dist       
 Min.   : 4.0   Min.   :  2.00  
 1st Qu.:12.0   1st Qu.: 26.00  
 Median :15.0   Median : 36.00  
 Mean   :15.4   Mean   : 42.98  
 3rd Qu.:19.0   3rd Qu.: 56.00  
 Max.   :25.0   Max.   :120.00  

Including Plots

Or plots

Example email ends here

Test Email

I am going to test the email by sending it to myself. I am going to use the {blastula} package to do this, from the new outlook email with credentials, to my junk yahoo email.

I add the following lines to the R script, auto-email with blastula.R

First, I generate the email OBJECT using blastula render_email()

my_email_object <- render_email("blastula_email.Rmd")
Error in abs_path(input): The file 'blastula_email.Rmd' does not exist.

Then I send the email using the credentials file I created earlier, with smtp_send()

smtp_send(my_email_object,
          from = "higgins-server@outlook.com",
          to = "higgi13425@yahoo.com",
          subject = "test email",
          credentials = creds_file("outlook_server_creds"))
Error in eval(expr, envir, enclos): object 'my_email_object' not found

I ran the script, and I got the email in my yahoo email. It worked! That is great for a one-time, manual email.

But to repeat it, you need cron

Cron Jobs

This is the weird part, where everything is done in the terminal, and is not stored in (visible) files.

Load cronR in the Console.

Then build a cron job with cronR::cron_rscript() and then add it to your cron list

cmd <- cron_rscript("~/data_space/phiggins/R/cronR_scripts/auto-email with blastula.R")
Error in cron_rscript("~/data_space/phiggins/R/cronR_scripts/auto-email with blastula.R"): file.exists(rscript) is not TRUE
cron_add(cmd, at = '9:35PM', id = '0002', description = 'test email')
Error in eval(expr, envir, enclos): object 'cmd' not found

Then you can list your cron jobs with cronR::cron_ls()

cronR::cron_ls()

And remove cron jobs with cronR::cron_rm(id = id_number)

cronR::cron_rm(id = 1)
Error in parse_crontab(user = user): No crontab available

As an Automation Alternative - GitHub Actions

You can follow along with ggnot’s YouTube video, which is a great tutorial. The link is https://www.youtube.com/watch?v=_QQGW_RUw_I

Steps:

  1. Create a new R repository on GitHub (should be private because of credentials file)
  2. Make sure to comment out the code that creates the credentials file. You only need to run this once.
  3. Push the files (credentials, Rmd email document, and script) to the repository.
  4. Create a new folder in your repository named ‘.github’, then within that, create a new folder called ‘workflows’. Use the Add File button/Create file to create each new folder in turn.
  5. Create the workflow file in the .github/workflows folder. I named mine ‘schedule-email.yml’

The contents of the file are (no surprise) a lot of YAML

name: 'schedule_email'
on: 
  schedule:
    - cron: '0 9 * * *' # 9:00 am UTC every day
jobs:
  render:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: r-lib/actions/setup-r@v2
      with:
        r-version: '4.0.3'
    - uses: r-lib/actions/setup-pandoc@v2
    - uses: r-lib/actions/setup-tinytex@v2
    - uses: r-lib/actions/setup-r-dependencies@v2
       with:
        cache-version: 2
        extra-packages:
          any::blastula
          any::here
          any::cronR
      run: Rscript auto_email_blastula.R
      run:    
            git config --local user.name github-actions
            git config --local user.email "actions@github.com"
            git add output/*
            git commit -am "commit on $(date)"
            git push origin main 
        env:
          REPO_KEY: ${{secrets.GITHUB_TOKEN}}
          username: github-actions
Error: <text>:22:20: unexpected symbol
21:           any::cronR
22:       run: Rscript auto_email_blastula.R
                       ^

Citation

For attribution, please cite this work as

Higgins (2024, Jan. 23). Medical R: Sending Automated Emails with Cron Jobs. Retrieved from https://higgi13425.github.io/medical_r/posts/2024-01-23-automatic-emails-with-cron-jobs-from-a-server/

BibTeX citation

@misc{higgins2024sending,
  author = {Higgins, Peter},
  title = {Medical R: Sending Automated Emails with Cron Jobs},
  url = {https://higgi13425.github.io/medical_r/posts/2024-01-23-automatic-emails-with-cron-jobs-from-a-server/},
  year = {2024}
}