r-lib / gmailr

Access the Gmail RESTful API from R.
https://gmailr.r-lib.org
Other
229 stars 56 forks source link

Unable to confirm Google credentials for `Gmailr` when running via Windows Task Scheduler #175

Closed JeffreyCHoover closed 1 year ago

JeffreyCHoover commented 1 year ago

Hello,

I'm cross-posting from 3-4 week old posts on StackOverflow: https://stackoverflow.com/questions/75514060/unable-to-confirm-google-credentials-for-gmailr-when-running-via-windows-task and Posit: https://community.rstudio.com/t/unable-to-confirm-google-credentials-for-gmailr-when-running-via-windows-task-scheduler/161217

I'm trying to schedule an R script to run through Windows Task Scheduler, and I'd like this script to send an automated email through gmailr when it has finished running. Currently, I have the task scheduled to run in Task Scheduler, and it will run and save output into a folder. The file path for the output directory contains the run date, so I know that the script is running as scheduled. The problem is that the email isn't sent after the output is saved.

To troubleshoot, I've run the script manually in RStudio, and it runs successfully. The output is saved, and the email will be sent through gmailr. This makes me think the code is ok and that I have some sort of higher-level authentication issue when running a non-interactive session.

When I look at Task Scheduler, the "Last Run Result" for the task is "Incorrect function. (0x800700001)." I've saved the error log when running this script through Task Scheduler, and it contains:

"Error: Can't get Google credentials.
Are you running gmailr in a non-interactive session? Consider:
  * Call `gm_auth()` directly with all necessary specifics.
Execution halted"

After systematically attempting to run the script through Task Scheduler when certain lines of code are missing, the error message appears to be due to gm_auth(cache = here(".secret"), email = "[SENDER_EMAIL]")

I've included a reprex of my code below.

here::i_am("[PROJ_DIR]/test-automated-email.R")

library(tidyverse)
library(here)
library(glue)
library(gmailr)
library(gargle)

options(gargle_verbosity = "debug")

pass_body <- glue("Everything worked great!")

gm_auth_configure(path = here("[MY_JSON_FILE]"))
gm_auth(cache = here(".secret"), email = "[SENDER_EMAIL]")

email <- gm_mime() %>%
  gm_from("[SENDER_EMAIL]") %>%
  gm_to("[RECIPIENT_EMAIL]") %>%
  gm_subject("Success") %>%
  gm_html_body(pass_body)
gm_send_message(email)

The output from Gargle debug is

trying `token_fetch()`
trying `credentials_service_account()`
Error caught by `token_fetch()`:
Argument 'txt' must be a JSON string, URL or file.
trying `credentials_external_account()`
aws.ec2metadata not installed; can't detect whether running on EC2 instance
trying `credentials_app_default()`
trying `credentials_gce()`
trying `credentials_byo_oauth()`
Error caught by `token_fetch()`:
inherits(token, "Token2.0") is not TRUE
trying `credentials_user_oauth2()`
Gargle2.0 initialize
adding "userinfo.email" scope
loading token from the cache
no matching token in the cache
initiating new token
Error caught by `token_fetch()`:
OAuth2 flow requires an interactive session.
Error: Can't get Google credentials.
Are you running gmailr in a non-interactive session? Consider:
  * Call `gm_auth()` directly with all necessary specifics.
Execution halted

For whatever reason, it seems like the token can't be found when initiating the script through Task Scheduler.

Some other (hopefully helpful) info:

Does anyone have any thoughts on how to resolve this? Any and all help is appreciated!

Thanks!

jennybc commented 1 year ago

I would add options(gargle_verbosity = "debug") to your debugging strategy, just to expose more information.

One hypothesis is that the user associated with the Task Scheduler job doesn't have permission to use the token. I would add some print debugging around: does the token (file) I need exist? what are my permissions with respect to that file?

JeffreyCHoover commented 1 year ago

Hi Jenny, thanks for your help on this!

I used file.access() with the Task Scheduler job to check the permissions of the token file. It indicated that the token file existed and that I had read, write, and execute access to the token file.

I deleted the .secret cache folder and manually ran the script to re-authenticate gmailr, but I'm still having the same issue.

One thing I keep noticing in the debugging output with options(gargle_verbosity = "debug") is that it appears gm_auth() isn't able to find a matching token in the cache.

[removed preceding code for readability]
no matching token in the cache
initiating new token
Error caught by `token_fetch()`:
OAuth2 flow requires an interactive session.
Error: Can't get Google credentials.
Are you running gmailr in a non-interactive session? Consider:
  * Call `gm_auth()` directly with all necessary specifics.
Execution halted

I'm not really sure why that would be. It finds a match when I run the script manually. It finds a match when I provides the cache, scopes, and email to token_fetch(). But for whatever reason, it's not finding a match whenever I run the script through Task Scheduler.

jennybc commented 1 year ago

If add more debugging to gargle, are you in a position to install a dev version of gargle so we can dig into the cache miss?

JeffreyCHoover commented 1 year ago

We can. Let me know which dev version to install, and I can use that to provide more info on the cache miss.

jennybc commented 1 year ago

The current dev version of gargle has more debugging statements that reveal the pieces of info that go into the strings used to key the tokens. Hopefully that will reveal what is different when you are making the token vs. when you are trying to retrieve it.

I would install with pak::pak("r-lib/gargle") but you could also use remotes::install_github("r-lib/gargle") or whatever your preferred method is for installing dev packages from GitHub.

JeffreyCHoover commented 1 year ago

Thanks for providing that dev version! When I installed the dev version, I was able to successfully run the job through Task Scheduler, and the email was sent as intended. Just to double check, I re-installed the version of gargle from Cran (gargle 1.4.0), and I got the same error message that I was getting before. It looks like something included in the dev version has addressed the issue.

For whatever it's worth, the new debugging info that's included in the dev version looks really good. Even though I didn't get to use it to troubleshoot the problem, it looks like it would have been really helpful.

jennybc commented 1 year ago

Well, that's very interesting!

There is no change in dev gargle that I explicitly expected to address/fix this. But I guess there's one that might be related (https://github.com/r-lib/gargle/commit/0b4502615377d5ba967e4fe7d543c2145f233564). I guess we'll just take the win!

I plan to release gargle very soon. Can this be closed now?

JeffreyCHoover commented 1 year ago

I think we're good to close. Thank you again for all of your help on this!