gmail

package
v1.5.0 Latest Latest
Warning

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

Go to latest
Published: Oct 12, 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