This vignette describes how roreviewapi sends
editor-search emails through the Gmail API, sending “from” the
reviewbot@ropensci.org alias but authorized under a single
Google account. Set that account once as an environment variable, and
every later step refers back to it:
This vignette complements the admin setup vignette, covering only the Gmail-specific pieces of the editor volunteer search workflow.
Prerequisites
- A Google Cloud Console project owned by the rOpenSci Workspace’s Cloud Identity org
- A local machine with a browser, for the one-time OAuth authorization
- SSH access to the Digital Ocean droplet
1. Google Cloud Console
In the ro-auto-email project:
- Enable the Gmail API.
- Configure the OAuth consent screen with
Audience: Internal (requires the project to be owned by
the Workspace’s Cloud Identity org). Internal governs who can
authorize the app, not who receives mail — it skips Google
verification and the 7-day refresh-token expiry that applies to
unverified External apps. Request scope
https://www.googleapis.com/auth/gmail.send. - Create an OAuth 2.0 Client ID, type Desktop
app. Download
client_secret_<id>.apps.googleusercontent.com.json.
2. Authorize once, locally
Run this on a local machine, not the droplet (it needs a browser and
a localhost redirect):
library (gmailr)
gm_auth_configure (path = "client_secret_<id>.apps.googleusercontent.com.json")
gm_auth (
email = Sys.getenv ("USER_EMAIL"),
scopes = c ("gmail.modify", "gmail.settings_basic"),
cache = "gmailr_token"
)Log in as $USER_EMAIL and grant consent. This caches a
refresh token to the gmailr_token/ directory, which is
portable to the droplet afterward since it is tied to the Google
account, not the machine.
Always pass the same scopes used here in any later
gm_auth() call — a mismatch forces a fresh interactive
re-authorization, which does not work headless on the droplet.
3. Send-as alias
Add reviewbot@ropensci.org as a “Send mail as” address
under $USER_EMAIL’s Gmail settings (Settings → Accounts →
Send mail as). No separate authorization is needed, as the
gmail.send scope already covers sending as any verified
alias of that account. This is set via gm_from() on each
outgoing message.
4. Code
-
gmail_auth()configures and authorizesgmailrfrom the cached credentials. -
gmail_send(to, subject, html_body)builds and sends one message viagm_mime()/gm_from()/gm_to()/gm_subject()/gm_html_body()/gm_send_message(). -
gmail_send_batch(emails, links, subject, repo, issue_id)loopsgmail_send()once per recipient withSys.sleep(0.1)between sends, since there is no Gmail equivalent of a batch-send endpoint for personalized messages.
The send_search and handle_click endpoints
each take an injectable sender parameter (default
gmail_send_batch / gmail_send) for
testing.
5. Environment variables
| Variable | Value |
|---|---|
GMAIL_SENDER |
reviewbot@ropensci.org |
GMAIL_OAUTH_CLIENT_SECRET |
/data/email/client_secret_<id>.apps.googleusercontent.com.json |
GMAIL_TOKEN_CACHE |
/data/email/gmailr_token |
GMAIL_AUTH_EMAIL |
$USER_EMAIL |
Set these in a local .env file for local runs. In
production they are baked into the image via Dockerfile
ENV placeholders plus a
RUN echo ... >> ~/.Renviron line — fill in the real
values directly in the Dockerfile on the droplet before
building. Do not add them to
docker-compose.yml’s environment: block: the
droplet has no .env, so ${VAR} there resolves
to an empty string and overrides the Dockerfile’s baked-in value.
6. Deploy credentials to the droplet
Copy
client_secret_<id>.apps.googleusercontent.com.json
and the gmailr_token/ directory to
/srv/roreviewapi/data/ (bind-mounted into the container at
/data/email). That directory is Docker/root-owned, so
scp to your home directory first, then move into place:
scp client_secret_<id>.apps.googleusercontent.com.json youruser@droplet:~/
scp -r gmailr_token youruser@droplet:~/
# on the droplet:
sudo mv ~/client_secret_<id>.apps.googleusercontent.com.json /srv/roreviewapi/data/
sudo mv ~/gmailr_token /srv/roreviewapi/data/
sudo chmod 600 /srv/roreviewapi/data/client_secret_<id>.apps.googleusercontent.com.json
sudo chmod 700 /srv/roreviewapi/data/gmailr_token
sudo chmod 600 /srv/roreviewapi/data/gmailr_token/*7. Verify
- Call
send_search()against a real/test issue; confirm delivery fromreviewbot@ropensci.org. - Click a tracking link; confirm the notify-email arrives via
gmail_send(). - Run the test suite.
8. Transfer maintenance
Operations only (a new person deploys/debugs, auth
stays as $USER_EMAIL) — nothing about the token
changes:
- Add them to the
ro-auto-emailGoogle Cloud project’s IAM. - Add their SSH key / sudo access on the droplet.
- Add them to the
roreviewapiGitHub repo. - Hand over this document.
Authorizing identity itself (needed if
mark@ropensci.org becomes unusable, e.g. leaving the
org):
- Add
reviewbot@ropensci.orgas a “Send mail as” alias under the new maintainer’s Gmail account. - They run the authorization in Section 2 as themselves, with the same
client_secret_....json, producing their owngmailr_token/. - Update
GMAIL_AUTH_EMAIL(local.envandDockerfileplaceholder) to their address;GMAIL_SENDERstaysreviewbot@ropensci.org. - Deploy their
client_secret_....jsonandgmailr_token/to/srv/roreviewapi/data/, replacing the old ones (Section 6). - Rebuild and redeploy (
restart.sh). - Revoke the old grant from the departing account’s Google Account → Security → “Third-party apps with account access”.
