Messages: send (with HTML, attachments and large-message upload), reply and reply-all in thread, forward, list and search, get, label changes (one or many), trash and untrash, and attachment download.
Sending. send builds the MIME message with
::google::gmail::mime/build-message (header-injection safe). Up to
5 MiB it is sent as the JSON raw field; larger messages (up to
Gmail's 35 MB limit) go through the media-upload endpoint
(/upload/gmail/v1/users/me/messages/send?uploadType=multipart). The
From address is the authenticated user unless from names one of
their send-as aliases.
Scopes. Sending uses gmail.send; reading, listing and
attachments gmail.readonly; label changes, trash and untrash
gmail.modify. reply, reply-all and forward read the original
first, so they need gmail.readonly (or gmail.modify) as well as
gmail.send. Defaults only matter for service accounts; override
with google.scopes or opts.scopes.
Values
BATCH_LIMIT
BATCH_LIMIT: Int 1000
MAX_MESSAGE_BYTES
MAX_MESSAGE_BYTES: Int 36700160
MAX_PAGE_SIZE
MAX_PAGE_SIZE: Int 500
REPLY_HEADERS
REPLY_HEADERS: Vec [
"Subject",
"From",
"Reply-To",
"To",
"Cc",
"Message-ID",
"References"
]
SEND_LOCAL_KEYS
SEND_LOCAL_KEYS: Vec [
"thread-id",
"threadId",
"upload",
"self-email",
"boundary"
]
UPLOAD_THRESHOLD
UPLOAD_THRESHOLD: Int 5242880
Functions
archive-message
fn (id: Str): Map
fn (id: Str, opts: Map): Map
Remove the INBOX label (Gmail's Archive). Scope: gmail.modify.
attachment-bytes
fn (attachment: Map): Bytes
fn (attachment: Map, opts: Map): Bytes
The bytes of an Attachment (from ::google::gmail::parse/attachments
or Email.attachments): its inline data, or a get-attachment
call. Scope: gmail.readonly.
email ::google::gmail::messages/get-email(id)
pdf first(filter(email.attachments, (a) { eq(a.mime-type, "application/pdf") }))
bytes ::google::gmail::messages/attachment-bytes(pdf)
batch-modify
fn (ids: Vec, add-label-ids: Vec, remove-label-ids: Vec): Bool
fn (ids: Vec, add-label-ids: Vec, remove-label-ids: Vec, opts: Map): Bool
POST /users/me/messages/batchModify - change labels on many messages, 1000 ids per call (larger Vecs are split). Returns true. Scope: gmail.modify.
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."})
forward-subject
fn (subject: Str?): Str
"Fwd: <subject>", unless it already starts with Fwd: or Fw:.
get-attachment
fn (message-id: Str, attachment-id: Str): Bytes
fn (message-id: Str, attachment-id: Str, opts: Map): Bytes
GET /users/me/messages/{messageId}/attachments/{id} - an attachment's bytes (decoded from Gmail's base64url). Get ids from ::google::gmail::parse/attachments. Scope: gmail.readonly.
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
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).
label-changes
fn (add-label-ids: Vec?, remove-label-ids: Vec?): Map
The {addLabelIds, removeLabelIds} body (pure), omitting an empty or null side.
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-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.
list-params
fn (opts: Map): Map
The query parameters list-messages sends (pure): your Gmail
parameters (q, maxResults up to 500, pageToken, labelIds -
a Vec, sent repeated - and includeSpamTrash) with nulls and
credential keys dropped.
mark-read
fn (id: Str): Map
fn (id: Str, opts: Map): Map
Remove the UNREAD label. Scope: gmail.modify.
mark-unread
fn (id: Str): Map
fn (id: Str, opts: Map): Map
Add the UNREAD label. Scope: gmail.modify.
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.
page-size
fn (limit: Int?): Int
prepare-reply
fn (message-id: Str, reply: Map, all: Bool, opts: Map): Map
Fetch message-id's headers and return the reply message Map (reply-fields merged under your reply fields) with its thread-id. Used by reply, reply-all and ::google::gmail::drafts/create-reply-draft. Scope: gmail.readonly.
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
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.
reply-fields
fn (original: Map, self-email: Str?, all: Bool): Map
The addressing and threading fields for replying to original (a
message resource with headers), as a message Map (pure): to, cc,
subject, in-reply-to, references and thread-id.
- Replies go to
Reply-To, elseFrom; replying to a message you sent goes to its original recipients. - With
all, the originalToandCcare copied tocc, without duplicates and withoutself-email(your own address). In-Reply-Tois the originalMessage-ID;Referencesis the originalReferencesplus itsMessage-ID, so Gmail and other clients thread the reply.
reply-subject
fn (subject: Str?): Str
"Re: <subject>", unless the subject already starts with Re: (any case).
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 })} })
self-email
fn (opts: Map): Str?
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-body
fn (raw: Bytes, thread-id: Str?): Map
The JSON body for messages.send / drafts.create (pure): {raw, threadId?} with raw base64url encoded.
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.
send-raw
fn (raw: Any): Map
fn (raw: Any, opts: Map): Map
POST /users/me/messages/send - send a complete RFC 5322 message
(Bytes or Str, e.g. from ::google::gmail::mime/build-message).
Options: thread-id (add it to a thread), upload: true (force the
upload endpoint). Returns the sent message {id, threadId, labelIds}. Scope: gmail.send.
thread-id-of
fn (opts: Map): Str?
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.
untrash-message
fn (id: Str): Map
fn (id: Str, opts: Map): Map
POST /users/me/messages/{id}/untrash - restore a message from the trash. Scope: gmail.modify.
use-upload
fn (size: Int, opts: Map): Bool
True when a raw message of size bytes should use the media-upload endpoint: over 5 MiB, or opts.upload is true.