Help us shape the future of Go! Take the 2026 Go Developer Survey

gmail

package
v1.11.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package gmail is a thin wrapper around the official Gmail API client (google.golang.org/api/gmail/v1) - unlike core/msgraph, there's a real SDK to build on here, so this package's job is the higher-level orchestration around it (history-based sync with bootstrap fallback, MIME parsing/translation, reply threading), not raw HTTP.

Shared, tenant-agnostic logic used two ways: seshat-backend wraps it in a real inbox.Connector (internal/inbox/gmail) for the local Inbox workflow, and seshat-server wraps it in a small self-hosted MCP server (internal/server/gmailmcp) so the workspace chat agent can call it as a tool, bridged through a per-employee OAuth-connected account the same way every other agent_action connector kind works. Neither side stores or manages OAuth tokens here - callers pass an already-token-bound oauth2.TokenSource, mirroring core/msgraph's Client.

Index

Constants

This section is empty.

Variables

View Source
var Scopes = []string{
	"https://www.googleapis.com/auth/gmail.modify",
	"https://www.googleapis.com/auth/gmail.send",
	"https://www.googleapis.com/auth/userinfo.email",
}

Scopes requested from Google, matching what this client actually does. gmail.modify is a documented superset of gmail.readonly (all read/write operations except immutable delete and settings) - needed once this client started doing more than read/send: trash/untrash, mark read/ unread, label CRUD and drafts CRUD all mutate existing mail. gmail.send stays alongside it since it's the scope Send/Reply/Compose actually rely on. These are all "restricted" scopes (Google's sensitive-scope review applies), which is also why each deployment registers its own Google Cloud OAuth client and consent screen rather than sharing a public one.

Functions

This section is empty.

Types

type Attachment

type Attachment struct {
	Filename          string
	ContentType       string
	Size              int64
	GmailAttachmentID string
}

Attachment is one attachment's metadata, not its bytes - see Client.FetchAttachment for the lazy download step.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client wraps the official Gmail API client.

func New

func New(ctx context.Context, tokenSource oauth2.TokenSource, opts ...option.ClientOption) (*Client, error)

New builds a Client from an oauth2.TokenSource - this package never sees a raw OAuth config or does its own token exchange. Extra opts are passed through to gmailapi.NewService, letting tests point at a fake server via option.WithHTTPClient/option.WithEndpoint.

func (*Client) Compose

func (c *Client) Compose(ctx context.Context, opts ComposeOptions) (string, error)

Compose sends a message with the full CC/BCC/threading header set ComposeOptions offers - the primitive both the richer "send" MCP tool and CreateDraft build on.

func (*Client) CreateDraft

func (c *Client) CreateDraft(ctx context.Context, opts ComposeOptions) (Draft, error)

CreateDraft saves a message as a draft instead of sending it.

func (*Client) CreateLabel

func (c *Client) CreateLabel(ctx context.Context, name string) (Label, error)

CreateLabel creates a new user label.

func (*Client) DeleteDraft

func (c *Client) DeleteDraft(ctx context.Context, draftID string) error

DeleteDraft discards a draft without sending it.

func (*Client) DeleteLabel

func (c *Client) DeleteLabel(ctx context.Context, id string) error

DeleteLabel deletes a user label (Gmail rejects deleting a system label with an API error, which this surfaces unchanged rather than special- casing).

func (*Client) FetchAttachment

func (c *Client) FetchAttachment(ctx context.Context, messageID, attachmentID string) ([]byte, error)

FetchAttachment downloads one attachment's bytes by the GmailAttachmentID captured on its Attachment metadata at sync time.

func (*Client) GetMessage

func (c *Client) GetMessage(ctx context.Context, id string) (Message, error)

GetMessage fetches one message by ID, fully MIME-parsed - unlike Sync, this targets a specific message the caller already knows about (e.g. from a prior Search/GetThread call), not "what's new".

func (*Client) GetProfile

func (c *Client) GetProfile(ctx context.Context) (Profile, error)

GetProfile returns the connected account's own mailbox summary.

func (*Client) GetThread

func (c *Client) GetThread(ctx context.Context, threadID string) ([]Message, error)

GetThread returns every message in a thread, in Gmail's own order (oldest first).

func (*Client) ListDrafts

func (c *Client) ListDrafts(ctx context.Context, maxResults int64) ([]Draft, error)

ListDrafts returns saved drafts. Gmail's Drafts.List response carries only each draft's ID/ThreadID/MessageID, not its subject or snippet - a per-draft Get call would be needed for that, which this deliberately doesn't do (N+1 for a list operation). maxResults <= 0 uses listDraftsLimit.

func (*Client) ListLabels

func (c *Client) ListLabels(ctx context.Context) ([]Label, error)

ListLabels returns every label in the mailbox, system and user-created.

func (*Client) MarkRead

func (c *Client) MarkRead(ctx context.Context, id string) error

MarkRead removes the UNREAD label from a message.

func (*Client) MarkThreadRead

func (c *Client) MarkThreadRead(ctx context.Context, threadID string) error

MarkThreadRead removes the UNREAD label from every message in a thread.

func (*Client) MarkThreadUnread

func (c *Client) MarkThreadUnread(ctx context.Context, threadID string) error

MarkThreadUnread adds the UNREAD label to every message in a thread.

func (*Client) MarkUnread

func (c *Client) MarkUnread(ctx context.Context, id string) error

MarkUnread adds the UNREAD label to a message.

func (*Client) ModifyLabels

func (c *Client) ModifyLabels(ctx context.Context, id string, addLabelIds, removeLabelIds []string) error

ModifyLabels adds and/or removes label IDs on a message in one call - the general primitive MarkRead/MarkUnread are built on, also usable directly for user-created labels (see ListLabels/CreateLabel).

func (*Client) ModifyThreadLabels

func (c *Client) ModifyThreadLabels(ctx context.Context, threadID string, addLabelIds, removeLabelIds []string) error

ModifyThreadLabels adds and/or removes label IDs on every message in a thread in one call - the thread-level counterpart to ModifyLabels.

func (*Client) Reply

func (c *Client) Reply(ctx context.Context, threadID, to, body string) (string, error)

Reply delivers a reply in the given Gmail thread (empty threadID sends an orphaned message instead). It first fetches the thread's most recent message (headers only) to build a properly threaded reply - matching Subject plus In-Reply-To/References - rather than sending a message that merely shares a ThreadId, which Gmail's own clients don't reliably group without those headers. Unlike Microsoft Graph's fire-and-forget reply action, Gmail's Send returns a real message ID synchronously.

func (*Client) Search

func (c *Client) Search(ctx context.Context, query string, maxResults int64) ([]Message, error)

Search runs a Gmail search query (the same syntax as the Gmail web UI's search box, e.g. "from:boss@company.com is:unread") and returns the matching messages, most recent first. maxResults <= 0 uses searchMessageLimit.

func (*Client) Send

func (c *Client) Send(ctx context.Context, to []string, subject, body string) (string, error)

Send delivers a fresh (non-reply) message to one or more recipients.

func (*Client) SendDraft

func (c *Client) SendDraft(ctx context.Context, draftID string) (string, error)

SendDraft sends a previously saved draft and returns the sent message ID.

func (*Client) Sync

func (c *Client) Sync(ctx context.Context, cursor string) ([]Message, string, error)

Sync pulls everything new since cursor and returns it plus the cursor value to persist for next time. An empty cursor bootstraps (a snapshot of recent messages); a history-expired cursor (Gmail only retains history for ~7 days) transparently falls back to a fresh bootstrap instead of surfacing an error the caller can't act on.

func (*Client) TrashMessage

func (c *Client) TrashMessage(ctx context.Context, id string) error

TrashMessage moves a message to Trash (Gmail permanently deletes trashed mail after ~30 days) - reversible via UntrashMessage until then.

func (*Client) TrashThread

func (c *Client) TrashThread(ctx context.Context, threadID string) error

TrashThread moves every message in a thread to Trash in one call - Gmail's own thread-level primitive (Outlook has no equivalent; a caller there must enumerate the conversation's messages and move each individually, see coremsgraph's ListMessagesInConversation).

func (*Client) UntrashMessage

func (c *Client) UntrashMessage(ctx context.Context, id string) error

UntrashMessage removes a message from Trash.

func (*Client) UntrashThread

func (c *Client) UntrashThread(ctx context.Context, threadID string) error

UntrashThread removes every message in a thread from Trash.

type ComposeOptions

type ComposeOptions struct {
	To, Cc, Bcc []string
	Subject     string
	Body        string
	// ThreadID, when set, sends within an existing thread - Gmail groups by
	// ThreadId server-side, unlike Reply which also rewrites Subject/
	// In-Reply-To/References from the thread's last message.
	ThreadID string
}

ComposeOptions is the full header set a caller-composed (non-reply) message can set - CC/BCC/threading, unlike Send's minimal to/subject/body (kept as-is since inbox/gmail's connector and Send's own existing callers only ever need that minimal shape).

type Draft

type Draft struct {
	ID        string
	MessageID string
	ThreadID  string
}

Draft is a saved-but-unsent message. Gmail's own Drafts.List only ever returns the ID/ThreadID/MessageID triple (no subject/snippet) without a separate per-draft Get call, so that's all this carries - see Client.ListDrafts's doc comment.

type EmailAddress

type EmailAddress struct {
	Address string
	Name    string
}

EmailAddress is a parsed "Name <address>" (or bare address) header value.

type Label

type Label struct {
	ID   string
	Name string
}

Label is a Gmail label (system or user-created) - see Client.ListLabels/CreateLabel/DeleteLabel.

type Message

type Message struct {
	ID          string
	ThreadID    string
	Subject     string
	From        EmailAddress
	To          EmailAddress
	BodyText    string
	Attachments []Attachment
	SentAt      time.Time
	// LabelIds are Gmail's own label IDs (both system, e.g. "UNREAD"/"INBOX"/
	// "TRASH", and user-created ones) - the raw source Unread and label-
	// management operations (Client.ModifyLabels et al.) read/write.
	LabelIds []string
	// Unread mirrors whether LabelIds contains "UNREAD", computed once at
	// translation time so callers don't need to know Gmail's label-based
	// read/unread convention themselves.
	Unread bool
}

Message is one email, already MIME-parsed. Deliberately has no "direction" field - inbound vs. outbound depends on which address is the connected account's own, an inbox-domain concept the caller (e.g. inbox/gmail.translateMessage) computes itself from From/To.

type Profile

type Profile struct {
	EmailAddress  string
	MessagesTotal int64
	ThreadsTotal  int64
}

Profile is the connected account's own mailbox summary.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL