library(Microsoft365R)
<- get_business_outlook() outlook
Sending individualized Outlook emails using R
This note describes how to send emails through Outlook directly from R using the Microsoft365R
package. In particular, it shows how you can easily send formatted personalized emails, including with attachments, using this package and a few other tools in R.
The R package Microsoft365R
makes it easy to send email via your personal or business (e.g., university) Outlook email from inside R. For example, to send an Outlook email from my university account using R, I would first do the following:
The first time I run get_business_outlook
function, it will open a web browser at my university’s usual Microsoft365 sign-in page, where I sign in as normal, which may include using two-factor authentication. Once authenticated, I can use the outlook
object in R to send an email. As a very simple example, I could send a one-line email (to myself, in this case) as follows:
<- outlook$create_email(
email body = "This email is sent from R",
subject = "Message sent from R",
to = "mark.andrews@ntu.ac.uk"
)
$send() email
This email is sent just as it would have been had you used the Outlook mail client. For example, if you go to your Sent folder in your Outlook client, if will have a copy of the email. This particular email will be plain text, while most emails nowadays are formatted html. Below, we will see how we can send formatted html emails just as easily as plain text ones.
If you have to send the same email to more than one recipient, you can use a vector of email address as the value of the to
argument in create_email
. But as you can imagine, because this is just regular R code, you also have endless options for sending separate individualized or personalized emails to multiple different recipients. As an example, I will show how you could send assessment feedback to a set of students. Obviously, these emails would need to be individualized; each student needs to be sent a separate email whose contents are specific to just that one student.
Although not necessary, let’s assume all the information about the students — names, email addresses, etc. — and the grades or other feedback that we want to send to them is in data frame. As a minimal example, we could have a tibble data frame named mailmerge_df
like this:
mailmerge_df
# A tibble: 7 × 5
firstname lastname email grade feedback
<chr> <chr> <chr> <chr> <chr>
1 Alice Ayers alice@uni.edu A+ alice_ayers.pdf
2 Bob Katt bob@uni.edu A+ bob_katt.pdf
3 Carol Singer carol@uni.edu A- carol_singer.pdf
4 Dorothy Oz dorothy@uni.edu B+ dorothy_oz.pdf
5 Jane Doe jane@uni.edu B jane_doe.pdf
6 Mary Betts mary@uni.edu B- mary_betts.pdf
7 Joe Bloggs joe@uni.edu C joe_bloggs.pdf
As you can see, the feedback
column gives the name of a pdf document. This contains the detailed feedback to the student and we will attach this file to the email.
The easiest way, at least from my perspective, to iterate through the mailmerge_df
data frame and send an email based on the details in each row is to use pwalk
, which is a functional that is part of the purrr
package (and is also loaded when we load tidyverse
). To use pwalk
in this way, we need supply a function that will use the values on each row and then create and send the email. For example, we could write a send_email
function like this:
<- function(firstname, grade, feedback, email, ...) {
send_email
# create a personalized email message
<- glue::glue('
msg Hi {firstname},
Your grade on the exam is {grade}.
best,
Mark
')
# create the email object
<- outlook$create_email(
email body = markdown::markdownToHTML(msg, fragment.only = TRUE),
subject = "Exam grade and feedback",
content_type = "html",
to = email
)
# add an attachment to the email
$add_attachment(feedback)
email
# send it
$send()
email }
When used with pwalk
, this function will take the value of firstname
, grade
, feedback
, and email
on each row of mailmerge_df
. With this information, it does the following things:
- It uses the value of
firstname
andgrade
to create a personalized email message. It does this using theglue
command fromglue
R package, which is for string interpolation. Theglue
command will substitute{firstname}
and{grade}
with the values offirstname
andgrade
that are provided as input arguments. - Creates the email object with the email recipient being the value of the
email
input argument, and thebody
being a html formatted version ofmsg
. For this, we use themarkdownToHTML
function from themarkdown
package. It is not necessary to do this, but the message will usually look better if it is converted into html. More generally, because themarkdownToHTML
will convert any markdown code to html, this allows us to use all the features of markdown to format the message. For example, we could add section labels, bulleted or enumerated list, hyper-links, bold or italics formatting, and so on. - Attaches the file given by the value of
feedback
using theadd_attachment
function. - Finally, it sends the email.
Note that the send_email
function has named arguments firstname
, grade
, feedback
, and email
, which are the only variables we need from mailmerge
. But because mailmerge
has more variables than just these three, we need to add an ellipsis to capture these. Nothing is done with these additional variables, but an error will be raised by pwalk
if we don’t have a function that captures them.
Now we can send all the emails as follows:
library(purrr)
pwalk(mailmerge_df, send_email)
And that’s it.
As a final point, a word of warning. When sending personalized emails, especially when the content is private or confidential, you don’t want to make a mistake and send anything to the wrong person. When writing and testing your code, it is probably wise to use your own email address as the value of to
in the create_email
function. This way, the emails will be all sent to you. When you are sure everything is working correctly, you can revert to to = email
like we see in the send_email
function above.
Reuse
Citation
@online{andrews2024,
author = {Andrews, Mark},
title = {Sending Individualized {Outlook} Emails Using {R}},
date = {2024-12-19},
url = {https://www.mjandrews.org/notes/outlook_mail_using_R/},
langid = {en}
}