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.

Context Vars: 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 alias 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 alias 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 alias 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 alias 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 alias 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 alias 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 alias 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 alias 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 alias 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 alias 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 alias 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 alias 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 alias 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 alias 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 alias 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).