I am trying to build a Shiny app that will accept a user-uploaded file as well as some other user-input information (textInput inputs), then send me an email using the textInput objects to fill out the subject, body, etc. while taking the file and attaching it to the email with a specific name, using the mailR package. I've posted the code I'm using below (with email addresses, usernames, and passwords changed).
Code
# load packages
library(shiny)
library(rJava)
library(mailR)
library(timeDate)
##############
##### ui -----
##############
ui = fluidPage(
fluidRow(
wellPanel(title = "Submit Data to the Database",
textInput("name", label = "Name:", placeholder = "Name"),
textInput("email","Email Address:"),
textInput("inst","Institution:"),
textInput("notes","Notes:", placeholder = ""),
fileInput("userdata", label = "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")),
actionButton("submitdata",label = "Submit Data")
)
))
##################
##### server -----
##################
server <- function(input, output) {
observeEvent(input$submitdata, {
isolate({
send.mail(from = "myemail@gmail.com",
to = "myotheremail@gmail.com",
subject = paste("New data submitted to WoodDAM from", input$name, sep = " "),
body = paste(input$name, "from institution:", input$inst, "with email:", input$email,
"has submitted data to the wood jam dynamics database.",
"This data is attached to this email",
input$name, "sent the following note accompanying this data:", input$note, collapse = ","),
smtp = list(host.name = "smtp.gmail.com", port = 465, user.name = "myusername", passwd = "mypassword", ssl = TRUE),
authenticate = TRUE,
send = TRUE,
attach.files = input$userdata,
file.names = paste(timeDate(Sys.time(), FinCenter = "America/Denver"), input$name, "WooDDAM_user_data", sep = "_", collapse = ","), # optional parameter
debug = T)
})
})
}
shinyApp(ui = ui, server = server)
When I run this app in an external viewer (chrome browser), I can input text and get an email to send just fine, but when I upload a test .csv file and click the submit button, it returns the error shown below.
Error
Listening on http://127.0.0.1:3587
Warning: Error in .createEmailAttachments: If not NULL, length of argument 'file.names' must equal length of argument 'file.paths'
Stack trace (innermost first):
77: .createEmailAttachments
76: send.mail
69: isolate
68: observeEventHandler [#3]
4: <Anonymous>
3: do.call
2: print.shiny.appobj
1: <Promise>
When I remove the file.names argument by commenting it out, thinking that will fix things, I get the following error:
2nd Error
Warning: Error in file.exists: invalid 'file' argument
Stack trace (innermost first):
78: file.exists
77: .createEmailAttachments
76: send.mail
69: isolate
68: observeEventHandler [#3]
4: <Anonymous>
3: do.call
2: print.shiny.appobj
1: <Promise>
Does anyone have any suggestions as to how to get this app to send the uploaded csv file without throwing an error? I suspect I'm doing something wrong when I try to feed input$userdata to the attach.files argument of send.mail, but I'm not sure how else to make that input be the email attachment. Although the file names issue is annoying, I could live with not being able to change the file name, as long as the uploaded file gets attached to the email.
Thanks for any help you can provide!
The reason why it doesn't work is that you're providing the object input$userdata
to the send.mail
function instead of the filepath
.
If you print out the contents of input$userdata
you can see that it contains the following attributes:
You should pass the datapath like this: attach.files = input$userdata$datapath
.
With this the syntax is corrected, however you may still need to enable less secure apps on your google account if you're keen on using gmail.