R Shiny sending user-uploaded file via email attachment - r

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:
name
size
type
datapath
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.

Related

Error when using using reticulate with shiny

I am trying to use a python package inside shiny app to extract the maintext from a webpage: https://newspaper.readthedocs.io/en/latest/
what I mean by main text is the body of the article, without any adds, links, etc... (very similar to the "reader view" in safari on iphone).
To my knowledge, there is no similar package in r, if you know one please let me know.
The goal of this app is to allow the user to insert a web address, click submit and get the clean text as output.
please find the code below as well as the error message. I am using rstudio cloud.
This is the error:
Using virtual environment 'python3_env' ...
Warning in system2(python, c("-c", shQuote(command)), stdout = TRUE, stderr = TRUE) :
running command ''/cloud/project/python3_env/bin/python' -c 'import sys; import pip; sys.stdout.write(pip.__version__)' 2>&1' had status 1
Warning in if (idx != -1) version <- substring(version, 1, idx - 1) :
the condition has length > 1 and only the first element will be used
Warning: Error in : invalid version specification ‘’, ‘ ’
52: stop
51: .make_numeric_version
50: numeric_version
49: pip_version
48: reticulate::virtualenv_install
47: server [/cloud/project/python in shiny.R#42]
Error : invalid version specification ‘’, ‘ ’
and this is the code:
# Python webpage scraper followed by r summary:
library(shiny)
library(reticulate)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
textInput("web", "Enter URL:"),
actionButton("act", "Submit")
),
mainPanel(br(),
tags$head(tags$style(HTML("pre { white-space: pre-wrap; word-break: keep-all; }"))),
verbatimTextOutput("nText"),
br()
)
)
)
server <- function(input, output){
#1) Add python env and packages:
reticulate::virtualenv_install('python3_env', packages = c('newspaper3k', 'nltk'))
py_run_string("from newspaper import Article")
py_run_string("import nltk")
py_run_string("nltk.download('punkt')")
#2) Pull the webpage url:
webad <- eventReactive(input$act, {
req(input$web)
input$web
})
observe({
py$webadd = webad
py_run_string("article = Article('webadd')")
py_run_string("article.download()")
py_run_string("article.parse()")
py_run_string("article.nlp()")
py_run_string("ztext =article.text")
py_run_string("r.ntexto = ztext")
output$nText <- renderPrint({
r.ntexto
})
})
}
shinyApp(ui = ui, server = server)

Store user-upload file to specified local folder

I want to create an app where User A uploads a file to server and User B can download it to a local folder.
I am first implementing the actions of uploading the file, and then immediately store that file to my own specified folder (since I am the sole User here). This is the code:
library(shiny)
ui <- fluidPage(
fileInput('file1', 'Choose csv File',
accept=c('text/csv'))
)
server <- function(input , output){
rootDir <- 'C:/RShiny/Dir'
inFile <- reactive({input$file1})
file.copy(inFile()$datapath,
file.path(rootDir, inFile()$name, fsep = .Platform$file.sep))
}
shinyApp(ui = ui , server = server)
However, I keep receiving this error message:
Warning: Error in .getReactiveEnvironment()$currentContext: Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
53: stop
52: .getReactiveEnvironment()$currentContext
51: getCurrentContext
50: .dependents$register
49: inFile
47: server [C:\RShiny\.../app.R#12]
Error in .getReactiveEnvironment()$currentContext() :
Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
And the app just closes right away. Not sure what it means and how to fix it. If someone could help explaining?
Thanks,
Please try the below:
library(shiny)
ui <- fluidPage(
fileInput('file1', 'Choose csv File',
accept=c('text/csv'))
)
server <- function(input , output){
rootDir <- 'C:/RShiny/Dir'
inFile <- reactive({input$file1})
observe({
file.copy(inFile()$datapath,
file.path(rootDir, inFile()$name, fsep = .Platform$file.sep))
})
}
shinyApp(ui = ui , server = server)
You need to put the file.copy() code in an observe ("a reactive expression or observer").

How to remove tags in textOutput - RShiny

I am new to R and I am actually developing a page where a directory (string characters like "xx/xx") is given in the server and I want to take back this directory to include it in the source of my ui app.
UI:
library(shiny)
file<-textOutput("paramfile")
source(file(file), local = TRUE, encoding = 'UTF-8')
SERVER :
filedir<-renderText({
"entries/5429_param.R"
})
output$paramfile<-renderText({
filedir()
})
I then have an error :
"Warning in file(filename, "r", encoding = encoding) : cannot open
file '< div id="paramfile" class="shiny-text-output">< /div>':
Invalid argument
Error in file(filename, "r", encoding = encoding) :
cannot open the connection"
Do you know how can I remove those tags or if there is another function that can allow me to take a string in the server and to include it into a source.
Here is a basic example of a ShinyApp:
# Example of UI with fluidPage
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
textInput("dir", label = "Enter a directory")
),
mainPanel(
verbatimTextOutput("dirPrint"),
verbatimTextOutput("lsFiles")
)
)
)
# Server logic
server <- function(input, output) {
output$dirPrint <- renderPrint({
print(input$dir)
})
output$lsFiles <- renderPrint({
fls <- list.files(input$dir)
print(fls)
})
}
# Complete app with UI and server components
shinyApp(ui, server)
If you enter the path of a directory in the textinput, the second renderPrint function is showing all files, that are found at that path.
I would suggest you go over the Shiny-Tutorials, as there seem to be some syntax-problems in your code and I am not sure what exactly you want to achieve.

shinyFiles defining a web directory as the root

I am trying to create a simple shiny app using shineFiles that allows users to select a file for download from a directory on the web.
library(shiny)
library(shinyFiles)
ui <- fluidPage(
shinyFilesButton('files', label='File select', title='Please select a file', multiple=FALSE)
)
server <- function(input, output) {
shinyFileChoose(input, 'files',
roots = (root = c('http://mirrors.vbi.vt.edu/mirrors/ftp.ncbi.nih.gov/blast/db/')),
filetypes=c('', 'txt' , '.gz' , '.md5'))
}
shinyApp(ui = ui , server = server)
However, I am getting the below error:
Listening on http://127.0.0.1:6772
Warning: Error in fileGet: Roots must be a named vector or a function returning one
Stack trace (innermost first):
60: fileGet
59: do.call
58: observerFunc
1: runApp
ERROR: [on_request_read] connection reset by peer
I need help in defining the directory as: http://mirrors.vbi.vt.edu/mirrors/ftp.ncbi.nih.gov/blast/db/

mailR: Sending mail to multiple addresses from shiny

I am trying to send a mail from my Shiny app. I have created text input boxes for to address, subject and body of the mail. The app sends mail when I my input in textInput box is a single email Id. When I add the second email id, it fails. However, the same code when I try to run it from RStudio instead of a shiny app, I am able to send the emails. How do I make my textInput parse the email id correctly so that mailR sends mail to them?
My current code:
library(shiny)
library(mailR)
ui =fluidPage(
fluidRow(
div(id = "login",
wellPanel(title = "Mail your report",
textInput("to", label = "To:", placeholder = "To:"),
textInput("sub","Subject:"),
textInput("msg","Message:"),
actionButton("mailButton",label = "Send mail")
)
))
)
server = function(input, output, session) {
observeEvent(input$mailButton,{
isolate({
send.mail(from = "myemail#gmail.com",
to = input$to,
subject = input$sub,
body = input$msg,
smtp = list(host.name = "smtp.gmail.com", port = 465, user.name = "myemail#gmail.com", passwd = "mypasword", ssl = TRUE),
authenticate = TRUE,
html = TRUE,
send = TRUE)
})
})
}
runApp(list(ui = ui, server = server))
I am getting the following error:
Listening on http://127.0.0.1:3499
javax.mail.internet.AddressException: Illegal address in string ``email1#gmail.com, email2#gmail.com''
at javax.mail.internet.InternetAddress.<init>(InternetAddress.java:114)
NULL
Warning: Error in : AddressException (Java): Illegal address
Stack trace (innermost first):
83: <Anonymous>
82: signalCondition
81: doWithOneRestart
80: withOneRestart
79: withRestarts
78: message
77: value[[3L]]
76: tryCatchOne
75: tryCatchList
74: tryCatch
73: .jTryCatch
72: .valid.email
71: send.mail
64: isolate
63: observeEventHandler [#3]
1: runApp
ERROR: [on_request_read] connection reset by peer
Try this, assuming the separator between emails is the semicolon:
to = unlist(strsplit(input$to, ";", fixed = TRUE))

Resources