This vignette describes how
roreviewapi sends editor-search emails through the Gmail
API, sending “from” the [email protected] alias but
authorized under a single Google account. Set that account once as an
environment variable, and every later step refers back to it:
export USER_EMAIL=[email protected]This vignette complements the admin setup vignette, covering only the Gmail-specific pieces of the editor volunteer search workflow.
In the ro-auto-email project:
https://www.googleapis.com/auth/gmail.send.client_secret_<id>.apps.googleusercontent.com.json.Add [email protected] 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.
gmail_auth() configures and authorizes
gmailr from the cached credentials.gmail_send(to, subject, html_body) builds and sends one
message via
gm_mime()/gm_from()/gm_to()/gm_subject()/gm_html_body()/
gm_send_message().gmail_send_batch(emails, links, subject, repo, issue_id)
loops gmail_send() once per recipient with
Sys.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.
| Variable | Value |
|---|---|
GMAIL_SENDER |
[email protected] |
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 |
On the droplet, set these in the untracked .env file, as
described in the admin
setup vignette; use a local .env file for local runs.
The two file paths are inside /data/email/, the container
side of the bind-mounted data directory, so the files themselves go in
/srv/roreviewapi/data/ on the droplet (Section 6).
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/*send_search() against a real/test issue; confirm
delivery from [email protected].gmail_send().This section covers the Gmail-specific parts of transferring maintenance. Access, tokens for other services, the cron job, and the general redeployment steps are in the admin setup vignette.
Operations only (a new person deploys/debugs, auth
stays as $USER_EMAIL) — nothing about the token changes.
The only Google step is to add them to the ro-auto-email
Google Cloud project’s IAM.
Authorizing identity itself (needed if
[email protected] becomes unusable, e.g. leaving the
org). The .env values affected are
GMAIL_AUTH_EMAIL (the new maintainer’s address) and the
contents of the GMAIL_TOKEN_CACHE directory (a new token).
GMAIL_SENDER stays [email protected], and
GMAIL_OAUTH_CLIENT_SECRET is unchanged as long as the same
Cloud project and OAuth client are kept.
ro-auto-email Google
Cloud project’s IAM, so they can download the
client_secret_....json. Because the consent screen audience
is Internal, their account must belong to the rOpenSci
Google Workspace; an account outside it cannot authorize the app.[email protected] as a “Send mail as” alias
under the new maintainer’s Gmail account (Section 3).USER_EMAIL set to their own address), using the same
client_secret_....json, producing their own
gmailr_token/. The scopes must be unchanged
from those in gmail_auth().gmailr_token/ (and
client_secret_....json, if it changed) to
/srv/roreviewapi/data/, replacing the old ones (Section 6).
Remove the old gmailr_token directory first, so that stale
files do not remain.GMAIL_AUTH_EMAIL in the droplet’s
.env to their address.restart.sh, then verify as in
Section 7.Four endpoints support the volunteer editor search workflow. All
require the shared secret token.
GET /send_searchFetches current editor email addresses from AirTable and GitHub, inserts a search record into the database, and dispatches personalised click-link emails via Gmail. The submission type (standard vs. stats) is determined automatically from the GitHub issue template.
Parameters: repourl, repo (org/repo),
issue_id, secret.
GET /click/<token>Records a volunteer response. Returns an HTTP 200 confirmation page, an “already used” page on duplicate clicks, or an “expired” page if the search has been deactivated. Sends a notification email to the current editor-in-chief on the first valid click.
No authentication required — the token itself is the credential.
GET /list_searchesReturns a data frame of all active and inactive searches with
recipient totals and click counts. Use this to find the
repourl value needed to deactivate a search.
Parameters: secret.
GET /deactivate_searchMarks the search inactive (preventing further click responses) and permanently deletes all recipient rows and the search record from the database.
Parameters: repourl, secret.
At startup, serve_api() fetches the current
editor-in-chief email address from AirTable and writes it to
/data/email/notify_email.txt (alongside the SQLite
database). This cache is refreshed every 24 hours via a background
timer. If the AirTable call fails, the existing cached value is
preserved and an error is logged.
The cached address is used as the notification recipient whenever a volunteer clicks a search link.