Gmail organizes mail and user preferences around a single user (use the special value me for the authenticated account) and a small set of core resources: messages, threads, drafts, labels, attachments, and settings (filters, forwarding, send-as aliases, IMAP/POP, vacation, delegates, client-side encryption). Many operations are simple CRUD against those resource IDs; knowing where to get each ID and which operation changes state is the most important operational knowledge.
How the domain is modeled
Gmail treats mail at two granularities: individual messages and grouped threads. Labels attach to messages and threads. A draft contains a message that can be updated or sent. Attachments live inside a message’s payload parts and are referenced by an id inside the message. Settings and identity resources (filters, forwarding addresses, sendAs aliases, S/MIME info, client-side-encryption identity/keypair entries) are separate resources identified by email addresses or resource IDs.
Key relationships you will use repeatedly:
- Most mailbox operations are scoped to a user via
userId(commonlyme). messages.listandthreads.listare the canonical ways to obtainmessageIdandthreadIdvalues for later calls.- Labels are created/listed via
labels.list/labels.createand theiridvalues are used inmessages.list/messages.modify/threads.modifyand filtering parameters. - Attachments: fetch the message first (message payload includes attachment metadata and attachment
id), then call the attachment retrieval operation with thatmessageId+ attachmentid.
IDs and entry points
Start by listing the resource that naturally provides the ID you need. Common entry points:
- To act on mail:
users.messages.list→ getmessageId;users.threads.list→ getthreadId. - To operate on drafts:
users.drafts.list→ getdraftId;users.drafts.createreturns the newDraft. - To change labels or find label IDs:
users.labels.list→ getlabelIdused bymessages.modify,threads.modify, and list filters. - To read inbox state and incremental updates:
users.getProfile(for account metadata) andusers.history.list(requires a validstartHistoryIdobtained from message/threadhistoryIdor from previous responses). - To manage send aliases and cryptographic identities:
users.settings.sendAs.list,users.settings.cse.identities.list, andusers.settings.cse.keypairs.list.
Always check the list operation that logically contains the resource you need—most operations require those IDs and do not create them implicitly.
Common tasks and the sequences that accomplish them
Each sequence below uses the resource names and parameters shown in the operation signatures.
Read a message or thread
- Use
users.messages.get(orusers.threads.getfor all messages in a thread). Chooseformat:fullto get payload, headers, and parts.metadatawithmetadataHeadersto fetch only specific headers.rawto retrieve the raw message object as stored (useful when you need MIME source).
- To find attachments: inspect the message
payloadparts for parts with anattachmentId. Call the attachment retrieval operation withmessageId+id.
Search and list mail
- Use
users.messages.listorusers.threads.listwithq(Gmail search syntax) orlabelIds. The response returns IDs only; callusers.messages.getto fetch full content for any IDs returned. includeSpamTrashcontrols whether SPAM/TRASH are included. Note thatqcannot be used with thegmail.metadatascope.
Send mail
- To deliver mail immediately, call
users.messages.sendwith aMessagepayload (therawfield is the typical carrier for a full MIME message).messages.sendactually transmits the message. - To prepare and send later: create or update a draft (
users.drafts.create/users.drafts.update) and then callusers.drafts.sendto send that draft. - For migrations or injecting mail into a mailbox (without sending): use
users.messages.insertorusers.messages.import.importexposes flags likeneverMarkSpam,processForCalendar, andinternalDateSourcefor preserving original timestamps or handling calendar invites.
Modify labels and message state
- To add/remove labels on a single message use
users.messages.modify(passaddLabelIdsand/orremoveLabelIds). For threads, useusers.threads.modify. - For bulk operations:
users.messages.batchModifyaccepts a list of message IDs.users.messages.batchDeletedeletes multiple messages at once. - To move a message to Trash use
users.messages.trash; to remove from Trash useusers.messages.untrash.users.messages.deletepermanently removes the message.
Manage drafts
- Create:
users.drafts.createreturns aDraftwith anid. - Update an existing draft:
users.drafts.updateusing thatid. - Send a draft:
users.drafts.send(you can also send a freshly created draft directly). - Delete:
users.drafts.delete.
Threads
- Use
users.threads.getto fetch an entire thread. - Modify thread labels with
users.threads.modify. - Delete vs Trash:
users.threads.deletepermanently deletes;users.threads.trashmoves to Trash anduntrashrestores it.
Attachments
- Inspect message payload to find
attachmentIdvalues. - Retrieve contents with the attachments
getoperation usingmessageIdand the attachmentid.
Incremental sync with history
users.history.listrequires astartHistoryIdobtained from a message/threadhistoryIdor a prior response. History IDs advance chronologically but are not contiguous; an out-of-datestartHistoryIdtypically returns 404 — in that case a full sync is required (re-list messages/threads).- Limit and paging apply; when there is no
nextPageToken, there are no more history records and the returnedhistoryIdcan be stored for the next incremental request.
Settings, aliases, and identities
- Send-as aliases:
users.settings.sendAs.list→ getsendAsEmail; manage alias settings withget/patch/updateand remove withdelete. - Verifying a send-as alias:
users.settings.sendAs.verifytriggers a verification flow that requires accepting a verification email—verification cannot be completed through the API alone without action on that verification message. - S/MIME: manage with
users.settings.sendAs.smimeInfo.*operations; set the default S/MIME entry withsetDefault. - Filters, forwarding addresses, delegates: list/create/delete/get via
users.settings.filters.*,users.settings.forwardingAddresses.*,users.settings.delegates.*. - IMAP/POP/Auto-forwarding/Vacation/Language: get and set with the corresponding
getandupdateoperations underusers.settings.*. - Client-side encryption (CSE): identities and keypairs are first-class resources. Keypair operations include
create,list,enable,disable, andobliterate—obliterateis irreversible.
Watch (push notifications)
- Start a watch with
users.watch; the response containshistoryIdand an expiration. Useusers.stopto stop notifications. Watches require a valid push configuration in the request body (check the operation signature for required fields).
Non-obvious patterns and gotchas
- The special
userIdvaluemeis accepted everywhere and is the normal entry for the authenticated mailbox — you rarely need to pass an explicit address unless managing another account. - Many list endpoints are paginated. Each list response can include
nextPageToken; request that token to fetch the next page. The list operations are the canonical way to discover resource IDs you will use elsewhere. messages.listandthreads.listreturn only IDs and minimal metadata. You must callmessages.getorthreads.getto retrieve the message payload, headers, parts, and attachment IDs.- Attachment retrieval requires two IDs: the
messageIdand the attachmentidfound in the message parts. You will not get the attachment body frommessages.getwithout explicitly requesting it via the attachments endpoint. formatchoices matter:- Use
metadata+metadataHeaderswhen you only need a few headers to reduce payload size. - Use
rawwhen you need the original MIME source. - Some operations or scopes (e.g.,
gmail.metadata) restrict the use ofqor limit returned fields—check the operation signature for accepted parameters and scope implications.
- Use
history.listis fragile if the suppliedstartHistoryIdis too old — the API will return 404. If you get 404, perform a full listing (e.g.,messages.list) to re-synchronize and capture a freshhistoryId.- Difference between deleting and trashing:
messages.trashandthreads.trashmove items to the Trash label and are reversible viauntrash.messages.deleteandthreads.deletepermanently remove items.
- Bulk operations exist for scale:
users.messages.batchDeleteandusers.messages.batchModifyaccept lists of IDs for large changes. For per-message changes usemessages.modify. - Send-as verification cannot be completed purely through the API; it usually requires interacting with a verification email sent to the alias.
- CSE key operations include
obliterate— treat it as permanent removal. - Watch responses include expiration; watches must be renewed. Use
users.stopto cancel a watch.
Quick decision guide (pick the right operation)
- Need mail IDs to operate on mail: call
users.messages.listorusers.threads.list. - Need full content/header/attachments for a specific item: call
users.messages.get(orusers.threads.get). - Want to send mail now:
users.messages.send(orusers.drafts.sendfor drafts). - Want to stage and edit before sending:
users.drafts.create/users.drafts.updatethenusers.drafts.send. - Change labels on one message:
users.messages.modify. Change many messages:users.messages.batchModify. - Pull incremental mailbox changes:
users.history.listwith a validstartHistoryId; fall back to full listing on 404. - Manage aliases, filters, forwarding, or delegates: use the corresponding
users.settings.*list/get/create/delete calls to discover and then act on the resource IDs.
Follow these patterns and you will reach the IDs and resource representations every other operation needs. When in doubt, list the resource that naturally contains the ID you require, then call the single-resource get/modify/delete operation for the action you need.