Gmail API v1 bindings: send safe MIME email (HTML, attachments,
non-ASCII headers, large messages), reply and forward in thread,
search and read messages as plain records, threads, drafts, labels,
and incremental sync with Pub/Sub push notifications. Credentials and
scopes come from google-core.
Namespaces
::google::gmail::mime- build RFC 5322 messages as Bytes (header injection safe, RFC 2047 encoding, multipart, attachments)::google::gmail::messages- send, reply, reply-all, forward, list/search, get, modify labels, batch modify, trash, attachments::google::gmail::parse- read a message: headers, text and HTML bodies, attachment list,to-email::google::gmail::threads- list, get, modify, trash::google::gmail::drafts- create (or a reply draft), update, send, list, get, delete::google::gmail::labels- list, get, create, update, delete,ensure-label::google::gmail::sync- profile, history (incremental sync),watch/stop-watch, Pub/Sub push parsing and verification
Every function has an options arity taking an opts Map. Gmail query
parameters use Gmail's own names (q, maxResults, pageToken,
labelIds, format, ...); credential keys (token,
refresh-token, service-account, subject, scopes, retry) are
handled by google-core and override context for that call.
Service accounts. Gmail has no service-account mailboxes: a
service account must use domain-wide delegation and impersonate a
Workspace user (google.impersonate, or subject per call).
Quick start
::messages ::google::gmail::messages
::messages/send({to: "ada@example.com", subject: "Weekly report", text: "All green.", html: "<p>All <b>green</b>.</p>"})
unread ::messages/search-emails("is:unread newer_than:7d", 20)
first(unread).subject
Values
API_ROOT
API_ROOT: Str "https://gmail.googleapis.com"
BASE_URL
BASE_URL: Str "https://gmail.googleapis.com/gmail/v1/users/me"
COMPOSE_SCOPE
COMPOSE_SCOPE: Str "https://www.googleapis.com/auth/gmail.compose"
DRAFT
DRAFT: Str "DRAFT"
FULL_SCOPE
FULL_SCOPE: Str "https://mail.google.com/"
IMPORTANT
IMPORTANT: Str "IMPORTANT"
INBOX
INBOX: Str "INBOX"
LABELS_SCOPE
LABELS_SCOPE: Str "https://www.googleapis.com/auth/gmail.labels"
METADATA_SCOPE
METADATA_SCOPE: Str "https://www.googleapis.com/auth/gmail.metadata"
MODIFY_SCOPE
MODIFY_SCOPE: Str "https://www.googleapis.com/auth/gmail.modify"
READ_SCOPE
READ_SCOPE: Str "https://www.googleapis.com/auth/gmail.readonly"
SEND_SCOPE
SEND_SCOPE: Str "https://www.googleapis.com/auth/gmail.send"
SENT
SENT: Str "SENT"
SPAM
SPAM: Str "SPAM"
STARRED
STARRED: Str "STARRED"
TRASH
TRASH: Str "TRASH"
UNREAD
UNREAD: Str "UNREAD"
UPLOAD_URL
UPLOAD_URL: Str "https://gmail.googleapis.com/upload/gmail/v1/users/me"
Functions
api-root
fn (): Str
The API root, https://gmail.googleapis.com unless the google.gmail.api-root context variable points at a proxy or emulator.
google.gmail.api-root
compact
fn (body: Map): Map
Drop null values from a request body (Gmail bodies never carry JSON null for unset fields).
creds
fn (opts: Map): Map
The google-core part of opts (credentials, scopes, retry), passed through to ::google::api.
done
fn (result: Result): Bool
true for a successful call whose response has no useful body (delete, stop), or the call's Err.
encode-id
fn (id: Str): Str
URL-encode an id for a path segment.
forward of ::google::gmail::messages/forward
fn (message-id: Str, message: Map): Map
fn (message-id: Str, message: Map, opts: Map): Map
Forward a message: the original is attached whole (as
message/rfc822, with its attachments) to a new message built from
message (at least to; text/html for a note). The subject
defaults to Fwd: <original subject>. Scopes: gmail.readonly and
gmail.send.
::google::gmail::messages/forward(email.id, {to: "legal@example.com", text: "FYI, see below."})
get-email of ::google::gmail::messages/get-email
fn (id: Str): ::google::gmail::parse/Email
fn (id: Str, opts: Map): ::google::gmail::parse/Email
get-message (full format) flattened with ::google::gmail::parse/to-email. Scope: gmail.readonly.
get-message of ::google::gmail::messages/get-message
fn (id: Str): Map
fn (id: Str, opts: Map): Map
GET /users/me/messages/{id} - a message. Options: format (full,
the default: headers and decoded-able parts; metadata with
metadataHeaders as a Vec; minimal; raw: the whole RFC 5322
message base64url encoded). Read it with ::google::gmail::parse.
Scope: gmail.readonly (gmail.metadata allows metadata and
minimal only).
get-profile of ::google::gmail::sync/get-profile
fn (): Map
fn (opts: Map): Map
GET /users/me/profile - {emailAddress, messagesTotal, threadsTotal, historyId} for the authenticated user. Scope: gmail.readonly.
json
fn (scope: Str, method: Str, full-url: Str, body: Any, opts: Map): Any
::google::api/json with this package's conventions: credential opts and a JSON (or empty) body.
list-all-messages of ::google::gmail::messages/list-all-messages
fn (opts: Any): Vec
fn (opts: Any, limit: Int?): Vec
Follow nextPageToken and return every matching {id, threadId},
or at most limit. Takes the same opts as list-messages (a Str
is a search). Uses maxResults: 500 (or limit when smaller).
Scope: gmail.readonly.
list-labels of ::google::gmail::labels/list-labels
fn (): Map
fn (opts: Map): Map
GET /users/me/labels - every label in the mailbox: {labels: [{id, name, type, ...}]} (not paginated). Scope: gmail.readonly.
list-messages of ::google::gmail::messages/list-messages
fn (): Map
fn (query: Str): Map
fn (opts: Map): Map
GET /users/me/messages - one page of message ids: {messages: [{id, threadId}], nextPageToken?, resultSizeEstimate}. A Str argument is
a Gmail search ("from:boss is:unread newer_than:2d"). Follow
nextPageToken with {pageToken} or use list-all-messages. Scope:
gmail.readonly.
modify-message of ::google::gmail::messages/modify-message
fn (id: Str, add-label-ids: Vec, remove-label-ids: Vec): Map
fn (id: Str, add-label-ids: Vec, remove-label-ids: Vec, opts: Map): Map
POST /users/me/messages/{id}/modify - add and remove label ids: modify-message(id, ["STARRED"], ["UNREAD"]) stars and marks read. Returns the message. Scope: gmail.modify.
query-params
fn (defaults: Map, opts: Map): Map
fn (defaults: Map, opts: Map, local-keys: Vec): Map
Build a call's query parameters: defaults, overridden by the Gmail
parameters in opts (credential keys and the function's own
local-keys are removed), with nulls dropped. Pass a key as null in
opts to drop a default.
reply of ::google::gmail::messages/reply
fn (message-id: Str, reply: Map): Map
fn (message-id: Str, reply: Map, opts: Map): Map
Reply to a message, in its thread: fetches the original's headers,
addresses the reply to its sender (Reply-To first), sets Re:,
In-Reply-To and References, and sends reply (a message Map with
at least text or html; any field you set wins). Options:
self-email (skips a profile lookup), credentials. Scopes:
gmail.readonly and gmail.send.
::google::gmail::messages/reply(email.id, {text: "Thanks, merged."})
reply-all of ::google::gmail::messages/reply-all
fn (message-id: Str, reply: Map): Map
fn (message-id: Str, reply: Map, opts: Map): Map
Like reply, but also copies the original To and Cc (minus you) onto cc. Scopes: gmail.readonly and gmail.send.
search-emails of ::google::gmail::messages/search-emails
fn (query: Str): Vec
fn (query: Str, limit: Int): Vec
fn (query: Str, limit: Int, opts: Map): Vec
Search with Gmail syntax and return up to limit (default 25)
matching messages as Email records, newest first. Makes one call
per message after the search. Scope: gmail.readonly.
invoices ::google::gmail::messages/search-emails("from:billing@vendor.com has:attachment newer_than:30d", 10)
map(invoices, (e) { {subject: e.subject, files: map(e.attachments, (a) { a.filename })} })
send of ::google::gmail::messages/send
fn (message: Map): Map
fn (message: Map, opts: Map): Map
Build and send an email from a message Map: to, cc, bcc,
from, reply-to, subject, text, html, attachments,
headers, in-reply-to, references (see
::google::gmail::mime). Returns the sent message {id, threadId, labelIds}, or an Err for an invalid address, header or attachment.
Options: thread-id, upload, plus credentials. Scope: gmail.send.
::google::gmail::messages/send({
to: ["Ada <ada@example.com>"],
cc: "ops@example.com",
subject: "Deploy finished",
text: "v2.3 is live.",
html: "<p><b>v2.3</b> is live.</p>",
attachments: [{filename: "changelog.md", content: "- faster builds\n", mime-type: "text/markdown"}]
})
send-message of ::google::gmail::messages/send-message
fn (to: Any, subject: Str, text: Str): Map
fn (to: Any, subject: Str, text: Str, opts: Map): Map
Send a plain-text email: send-message("ada@example.com", "Hi", "Hello from Hot!"). to may be a list ("a@x.io, b@x.io" or a Vec). Scope: gmail.send.
to-email of ::google::gmail::parse/to-email
fn (message: Map): Email
Flatten a message resource into an Email.
email ::google::gmail::parse/to-email(::google::gmail::messages/get-message(id))
`${email.from-email}: ${email.subject}`
trash-message of ::google::gmail::messages/trash-message
fn (id: Str): Map
fn (id: Str, opts: Map): Map
POST /users/me/messages/{id}/trash - move a message to the trash (Gmail deletes it after 30 days; untrash-message restores it). Permanent deletion needs the full https://mail.google.com/ scope and is not wrapped. Scope: gmail.modify.
upload-url
fn (path: Str, params: Map): Str
A Gmail v1 media-upload URL (/upload/gmail/v1/users/me + path) with params.
url
fn (path: Str): Str
fn (path: Str, params: Map): Str
A Gmail v1 URL for the authenticated user (/gmail/v1/users/me + path) with non-null params as a query string (Vec values repeat the key).