library(glue)
library(dplyr)
library(RDCOMClient)
library(purrr)
I recently needed to send out an email to many recipients, with only slight changes in the text. And I figured – this must be something we can do with R
, right?
Luckily enough, there’s the RDCOMClient
library which lets R
access some programs, including Outlook. So if you have Outlook set up on your computer, this approach will work like a charm. Actually, it was kind of scary for me: this really works, and real emails get sent. 😱
This approach only works on Windows computers.
Preparation
What do we need?
- the
RDCOMClient
library - a
data.frame
including the email addresses and the bit we want changed - a template text
So let’s start by loading the needed libraries. We already talked about RDCOMClient
. dplyr
and glue
make pasting our template and our information together easier, and purrr
will allow us to loop over our info data.frame
.
Let’s start with our template! We’ll make it nice and short.
<- "Good morning!
template Do you enjoy {food}?
Have a great day."
Next, we’d load our data.frame
; for this showcase purpose, we’ll just make it up from scratch. We’ll combine our template and our bit of information into a new column, text
.
<- tibble::tribble(
info ~email, ~info,
"anna@example.com", "apples",
"bernardo@example.com", "bananas",
"charlie@example.com", "chocolate",
"donald@example.com", "donuts"
|>
) ::mutate(text = glue::glue(template, food = info)) dplyr
|> kableExtra::kbl() info
info | text | |
---|---|---|
anna@example.com | apples | Good morning! Do you enjoy apples? Have a great day. |
bernardo@example.com | bananas | Good morning! Do you enjoy bananas? Have a great day. |
charlie@example.com | chocolate | Good morning! Do you enjoy chocolate? Have a great day. |
donald@example.com | donuts | Good morning! Do you enjoy donuts? Have a great day. |
Mail function
Next, let’s set up the function which we will map over to send our mails! Let’s start by understanding what RDCOMClient
does for us.
Open Outlook
The first thing we want to do – and just once – is to open the Outlook app.
<- COMCreate("Outlook.Application") Outlook
Create an email
We need to start off by creating an email – just like when you’re in Outlook, you click on Create
. We’re telling RDCOMClient
that it’s Outlook we want to use by putting it first, and we put the command we want executed after the $
sign.
Let’s also save this email to an object, so that we can work on it again after.
<- Outlook$CreateItem(0) Email
Set recipient, subject and body
What’s the next thing you’d do when writing an email? You’d type in who you want to send the email to and what it’s about – recipient and subject. Then, you’d enter the text – the body.
We can do that using attributes of the Email
object we’ve created.
<- info |> head(1)
first_info
"to"]] <- first_info$email
Email[["subject"]] <- "Hello!"
Email[["body"]] <- first_info$text Email[[
Sending the email
Lastly, we need to click on Send
. This is, again, an Outlook$
function, not an attribute.
$Send() Email
Piecing together the pieces
This is our final function, where we have incorporated everything we need. Note that we don’t include opening Outlook – this is something we only need to do once. We can now take this function and map over it.
Note that in our approach, we’re using the same subject for all emails. You could, however, also map over this part.
<- function(to = "",
send_mail body = "",
subject = "Hello from R"){
= Outlook$CreateItem(0)
Email "to"]] = to
Email[["subject"]] = subject
Email[["body"]] = body
Email[[$Send()
Email }
Mapping over the function
Let’s now take purr
to map over this! We’ll need the walk2
function, since we have two inputs for every mail that change:
- body/text
<- COMCreate("Outlook.Application")
Outlook walk2(.x = info$email,
.y = info$text,
.f = ~ send_mail(to = .x, body = .y))
And there we have it – we can send out an email to Anna, Bernardo, Charlie and Donald all at once! You can check in your Outlook outbox that these emails actually sent.
Approaches without Outlook
Using RDCOMClient
to access Outlook is a bit hacky, but was exactly the right thing for me. However, we could use a more direct approach, without using the Outlook user interface.
This blogpost by mailtrap goes into detail about how you can achieve this.
Citation
@online{zeller2025,
author = {Zeller, Sarah},
title = {Sending Automated Emails},
date = {2025-02-12},
url = {https://sarahzeller.github.io/blog/posts/sending-automated-emails/},
langid = {en}
}