jmap

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 11, 2026 License: MIT Imports: 18 Imported by: 0

README

jmap-go

CI Go Reference Go Version

Go client library implementing all 13 JMAP specifications from jmap.io. Uses Go generics for type-safe method invocations instead of global registries.

Supported specifications

RFC Specification Package
RFC 8620 JMAP Core jmap (root)
RFC 8887 JMAP WebSocket jmap (root)
RFC 9749 VAPID Push jmap (root)
RFC 9404 Blob Management blob/
RFC 9425 Quotas quota/
RFC 9670 Sharing sharing/
RFC 8621 JMAP Mail mail/
RFC 9007 MDN mail/
RFC 9219 S/MIME Verification mail/
RFC 9661 Sieve Scripts sieve/
RFC 9610 JMAP Contacts contacts/
RFC 9553 JSContact contacts/
draft-ietf-jmap-calendars-26 JMAP Calendars calendar/
draft-ietf-calext-jscalendarbis-15 JSCalendar calendar/
Stalwart Management schema (urn:stalwart:jmap) stalwart/

Installation

go get github.com/pr0ton11/jmap-go

Import sub-packages as needed:

import (
    jmap "github.com/pr0ton11/jmap-go"
    "github.com/pr0ton11/jmap-go/mail"
    "github.com/pr0ton11/jmap-go/contacts"
    "github.com/pr0ton11/jmap-go/calendar"
    "github.com/pr0ton11/jmap-go/stalwart"
)

Quick start

Register capabilities

Before making requests, register the capabilities and method response types your application uses. Each sub-package provides a Register() function. The root package provides RegisterAll() for its own types (Core, Push, WebSocket, VAPID).

// Register root capabilities (Core, Push, WebSocket, VAPID)
jmap.RegisterAll()

// Register sub-package capabilities as needed
mail.Register()
contacts.Register()
calendar.Register()

// Register Stalwart management object methods as needed
stalwart.RegisterTypes("Account", "Domain")
Create a client
client := &jmap.Client{
    SessionEndpoint: "https://mail.example.com/.well-known/jmap",
}

// Authenticate with Basic auth
client.WithBasicAuth("user@example.com", "password")

// Or with a Bearer token
client.WithAccessToken("your-oauth2-token")

// Or discover the session endpoint via DNS SRV
endpoint, err := jmap.Discover("example.com")
if err != nil {
    log.Fatal(err)
}
client.SessionEndpoint = endpoint
Fetch mailboxes
req := &jmap.Request{}
jmap.Invoke[*mail.MailboxGet, *mail.MailboxGetResponse](req, &mail.MailboxGet{
    AccountID: accountID,
})

resp, err := client.Do(req)
if err != nil {
    log.Fatal(err)
}

mailboxes, err := jmap.GetInvocation[*mail.MailboxGetResponse](resp, 0)
if err != nil {
    log.Fatal(err)
}

for _, mb := range mailboxes.List {
    fmt.Printf("%s: %s (%d total, %d unread)\n",
        mb.ID, mb.Name, mb.TotalEmails, mb.UnreadEmails)
}
Query emails
req := &jmap.Request{}
jmap.Invoke[*mail.EmailQuery, *mail.EmailQueryResponse](req, &mail.EmailQuery{
    AccountID: accountID,
    Filter: &mail.EmailFilter{
        InMailbox: &inboxID,
    },
    Sort: []*mail.EmailSort{{
        Property:    "receivedAt",
        IsAscending: false,
    }},
    Limit: 10,
})

resp, err := client.Do(req)
if err != nil {
    log.Fatal(err)
}

result, err := jmap.GetInvocation[*mail.EmailQueryResponse](resp, 0)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Found %d emails\n", result.Total)
Batch requests

JMAP supports multiple method calls in a single request. Each Invoke call appends to the request and returns a call ID that maps to the response index.

req := &jmap.Request{}

// Call 0: get mailboxes
jmap.Invoke[*mail.MailboxGet, *mail.MailboxGetResponse](req, &mail.MailboxGet{
    AccountID: accountID,
})

// Call 1: query emails
jmap.Invoke[*mail.EmailQuery, *mail.EmailQueryResponse](req, &mail.EmailQuery{
    AccountID: accountID,
    Limit:     50,
})

resp, err := client.Do(req)
if err != nil {
    log.Fatal(err)
}

// Retrieve each response by index
mailboxes, _ := jmap.GetInvocation[*mail.MailboxGetResponse](resp, 0)
emails, _ := jmap.GetInvocation[*mail.EmailQueryResponse](resp, 1)
Upload and download blobs
// Upload a file
upload, err := client.Upload(accountID, fileReader)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Uploaded blob: %s (%d bytes)\n", upload.BlobID, upload.Size)

// Download a blob
reader, err := client.Download(accountID, blobID)
if err != nil {
    log.Fatal(err)
}
defer reader.Close()
Stalwart management objects

Stalwart exposes management and configuration objects through the urn:stalwart:jmap capability. Object method names use an x: prefix on the wire, for example x:Domain/get.

stalwart.RegisterTypes("Domain")

req := &jmap.Request{}
jmap.Invoke[*stalwart.Get, *stalwart.GetResponse](req,
    stalwart.NewGet("Domain", "example.com"))

resp, err := client.Do(req)
if err != nil {
    log.Fatal(err)
}

domains, err := jmap.GetInvocation[*stalwart.GetResponse](resp, 0)
if err != nil {
    log.Fatal(err)
}

for _, domain := range domains.List {
    fmt.Println((*domain)["name"])
}
WebSocket transport
ctx := context.Background()

ws := &jmap.WebSocketClient{
    Client: client,
    PushHandler: func(change *jmap.StateChange) {
        fmt.Printf("State change: %+v\n", change)
    },
}
if err := ws.Connect(ctx); err != nil {
    log.Fatal(err)
}
defer ws.Close()

// Send a request over WebSocket
resp, err := ws.Do(ctx, req)
if err != nil {
    log.Fatal(err)
}

// Enable push notifications
err = ws.EnablePush(ctx, []jmap.EventType{"Email", "Mailbox"}, "")
if err != nil {
    log.Fatal(err)
}
EventSource push
es := &jmap.EventSource{
    Client:          client,
    Events:          []jmap.EventType{"Email", "Mailbox"},
    CloseAfterState: true,
    Handler: func(change *jmap.StateChange) {
        fmt.Printf("State change: %+v\n", change)
    },
}
if err := es.Listen(); err != nil {
    log.Fatal(err)
}

Architecture

Session (GET)
  → discover capabilities + account URLs
    → build Request with Invoke[M, R]
      → POST JSON to APIURL (or send over WebSocket)
        → typed Response with GetInvocation[R]

The library uses Go generics (Invoke[M Method, R MethodResponse] and GetInvocation[R MethodResponse]) for compile-time type safety. Internal registries exist only for deserializing polymorphic server JSON responses.

Sub-packages export Register() functions that must be called explicitly before making requests — there are no init() side effects.

Extending with custom types

The generic architecture makes it straightforward to add custom JMAP method types (e.g. for vendor-specific extensions):

// Define your method and response types
type MyCustomGet struct {
    AccountID jmap.ID `json:"accountId"`
}

func (m *MyCustomGet) Name() string      { return "MyCustom/get" }
func (m *MyCustomGet) Requires() []jmap.URI { return []jmap.URI{"urn:vendor:custom"} }

type MyCustomGetResponse struct {
    List []MyCustomObject `json:"list"`
}

func (r *MyCustomGetResponse) Name() string { return "MyCustom/get" }

// Register for deserialization
func init() {
    jmap.RegisterMethod("MyCustom/get", func() jmap.MethodResponse {
        return &MyCustomGetResponse{}
    })
}

// Use with full type safety
req := &jmap.Request{}
jmap.Invoke[*MyCustomGet, *MyCustomGetResponse](req, &MyCustomGet{
    AccountID: accountID,
})

Development

All commands use just:

just              # default: lint + test + build
just build        # build all packages
just test         # run tests with -race
just test-single Name  # run a single test
just test-verbose # verbose test output
just lint         # gofmt + go vet + go fix + golangci-lint
just vulncheck    # check for known vulnerabilities
just coverage     # print test coverage
just check        # full CI gate (lint + test + vulncheck)
just tidy         # go mod tidy
just clean        # remove build artifacts

License

MIT

Documentation

Overview

Package jmap implements the JMAP Core protocol as defined in RFC 8620, along with all JMAP extension specifications.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Discover

func Discover(domain string) (string, error)

Discover finds the JMAP Session Endpoint for a domain using DNS SRV lookup for _jmap._tcp (RFC 8620 Section 2.2).

func GetAccountCapability

func GetAccountCapability[C Capability](a *Account, uri URI) C

GetAccountCapability retrieves a typed capability from an Account. Returns nil if the capability is not present.

func GetCapability

func GetCapability[C Capability](s *Session, uri URI) C

GetCapability retrieves a typed capability from a Session. Returns nil if the capability is not present.

func GetInvocation

func GetInvocation[R MethodResponse](resp *Response, index int) (R, error)

GetInvocation retrieves a typed response from a Response at the given index. Returns the typed response and true if successful, or zero value and false if the index is out of range or the type assertion fails.

func Invoke

func Invoke[M Method, R MethodResponse](req *Request, method M) string

Invoke adds a typed method call to a request and returns the call ID. This is the generic, type-safe way to build JMAP requests.

callID := jmap.Invoke[*mail.EmailGet, *mail.EmailGetResponse](req, emailGet)

func RegisterAll

func RegisterAll()

RegisterAll registers all capabilities and methods defined in the root jmap package (Core, Push, WebSocket, VAPID). Sub-packages have their own Register() functions that should be called separately.

func RegisterCapability

func RegisterCapability(c Capability)

RegisterCapability registers a capability for JSON deserialization of session and account data. Sub-packages should call this from their Register() function.

func RegisterCore

func RegisterCore()

RegisterCore registers the Core capability and Core/echo method. Must be called before using these types.

func RegisterMethod

func RegisterMethod(name string, factory MethodResponseFactory)

RegisterMethod registers a method response factory for JSON deserialization of server responses. The name should match the method name (e.g. "Email/get") or "error" for MethodError.

func RegisterPush

func RegisterPush()

RegisterPush registers PushSubscription methods.

func RegisterVAPID

func RegisterVAPID()

RegisterVAPID registers the VAPID capability.

func RegisterWebSocket

func RegisterWebSocket()

RegisterWebSocket registers the WebSocket capability.

Types

type Account

type Account struct {
	// Name is a user-friendly string for presenting this account,
	// e.g. the email address of the account owner.
	Name string `json:"name"`

	// IsPersonal is true if this account belongs to the authenticated user.
	IsPersonal bool `json:"isPersonal"`

	// IsReadOnly is true if the account is read-only.
	IsReadOnly bool `json:"isReadOnly"`

	// Capabilities maps capability URIs to their typed per-account config.
	// Populated during JSON unmarshalling from RawCapabilities.
	Capabilities map[URI]Capability `json:"-"`

	// RawCapabilities holds the unparsed JSON for each account capability.
	RawCapabilities map[URI]json.RawMessage `json:"accountCapabilities"`
}

Account represents a JMAP account (RFC 8620 Section 1.6.2). An account is a collection of data the authenticated user has access to.

func (*Account) UnmarshalJSON

func (a *Account) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes the Account and resolves registered capabilities.

type AddedItem

type AddedItem struct {
	ID    ID     `json:"id"`
	Index uint64 `json:"index"`
}

AddedItem represents an item added to query results, returned by /queryChanges methods.

type Capability

type Capability interface {
	// URI returns the capability identifier, e.g. "urn:ietf:params:jmap:core".
	URI() URI

	// New returns a pointer to a new zero-value instance of this capability,
	// suitable for JSON unmarshalling.
	New() Capability
}

Capability represents a JMAP capability advertised by the server. Each capability has a unique URI and can be deserialized from JSON.

type Client

type Client struct {

	// HTTPClient is the underlying HTTP client used for all requests.
	// Set via WithBasicAuth or WithAccessToken for authentication.
	HTTPClient *http.Client

	// SessionEndpoint is the URL of the JMAP Session Resource.
	SessionEndpoint string

	// Session holds the current JMAP Session object, fetched automatically
	// on first request or via Authenticate().
	Session *Session
	// contains filtered or unexported fields
}

Client is a JMAP HTTP client that manages authentication, session discovery, and API requests.

func (*Client) Authenticate

func (c *Client) Authenticate() error

Authenticate fetches the JMAP Session object from the SessionEndpoint. It is called automatically by Do if the Session is nil, but can be called explicitly to access Session data before the first request.

func (*Client) Do

func (c *Client) Do(req *Request) (*Response, error)

Do performs a JMAP API request and returns the response. If the session has not been fetched yet, Authenticate is called automatically.

func (*Client) Download

func (c *Client) Download(accountID, blobID ID) (io.ReadCloser, error)

Download retrieves binary data by blob ID from the server.

func (*Client) DownloadWithContext

func (c *Client) DownloadWithContext(ctx context.Context, accountID, blobID ID) (io.ReadCloser, error)

DownloadWithContext retrieves binary data by blob ID with a context.

func (*Client) Upload

func (c *Client) Upload(accountID ID, blob io.Reader) (*UploadResponse, error)

Upload sends binary data to the server and returns the upload metadata.

func (*Client) UploadWithContext

func (c *Client) UploadWithContext(ctx context.Context, accountID ID, blob io.Reader) (*UploadResponse, error)

UploadWithContext sends binary data to the server with a context.

func (*Client) WithAccessToken

func (c *Client) WithAccessToken(token string) *Client

WithAccessToken configures the client to use Bearer token authentication.

func (*Client) WithBasicAuth

func (c *Client) WithBasicAuth(username, password string) *Client

WithBasicAuth configures the client to use HTTP Basic authentication.

type CollationAlgo

type CollationAlgo string

CollationAlgo represents a collation algorithm identifier.

const (
	// ASCIINumeric is the i;ascii-numeric collation (RFC 4790).
	ASCIINumeric CollationAlgo = "i;ascii-numeric"

	// ASCIICasemap is the i;ascii-casemap collation (RFC 4790).
	ASCIICasemap CollationAlgo = "i;ascii-casemap"

	// UnicodeCasemap is the i;unicode-casemap collation (RFC 5051).
	UnicodeCasemap CollationAlgo = "i;unicode-casemap"
)

type CoreCapability

type CoreCapability struct {
	// MaxSizeUpload is the maximum file size in bytes for uploads.
	MaxSizeUpload uint64 `json:"maxSizeUpload"`

	// MaxConcurrentUpload is the max number of concurrent upload requests.
	MaxConcurrentUpload uint64 `json:"maxConcurrentUpload"`

	// MaxSizeRequest is the max size in bytes the server accepts for a request.
	MaxSizeRequest uint64 `json:"maxSizeRequest"`

	// MaxConcurrentRequests is the max number of concurrent API requests.
	MaxConcurrentRequests uint64 `json:"maxConcurrentRequests"`

	// MaxCallsInRequest is the max number of method calls in a single request.
	MaxCallsInRequest uint64 `json:"maxCallsInRequest"`

	// MaxObjectsInGet is the max number of objects in a /get call.
	MaxObjectsInGet uint64 `json:"maxObjectsInGet"`

	// MaxObjectsInSet is the max number of objects in a /set call.
	MaxObjectsInSet uint64 `json:"maxObjectsInSet"`

	// CollationAlgorithms lists the supported collation algorithms.
	CollationAlgorithms []CollationAlgo `json:"collationAlgorithms"`
}

CoreCapability represents the urn:ietf:params:jmap:core capability (RFC 8620 Section 2).

func (*CoreCapability) New

func (c *CoreCapability) New() Capability

New implements Capability.

func (*CoreCapability) URI

func (c *CoreCapability) URI() URI

URI implements Capability.

type Echo

type Echo struct {
	// Data can contain any JSON-serializable fields.
	Data map[string]any `json:"-"`
}

Echo is the Core/echo method (RFC 8620 Section 4). The server echoes the data back unchanged. Useful for testing connectivity.

func (*Echo) Name

func (e *Echo) Name() string

Name implements Method.

func (*Echo) Requires

func (e *Echo) Requires() []URI

Requires implements Method.

type EchoResponse

type EchoResponse struct {
	Data map[string]any `json:"-"`
}

EchoResponse is the response to Core/echo.

func (*EchoResponse) Name

func (e *EchoResponse) Name() string

Name implements MethodResponse.

type EventSource

type EventSource struct {
	// Client is the JMAP client to use for the connection.
	Client *Client

	// Handler is called for each StateChange event received.
	Handler func(*StateChange)

	// Events lists the event types to subscribe to. Defaults to AllEvents.
	Events []EventType

	// Ping is the requested ping interval in seconds. The server may ignore
	// this value. Set to 0 to disable pinging.
	Ping uint

	// CloseAfterState causes the connection to close after receiving a
	// state event.
	CloseAfterState bool
	// contains filtered or unexported fields
}

EventSource connects to a JMAP server's Server-Sent Events endpoint for receiving push notifications (RFC 8620 Section 7.3).

func (*EventSource) Close

func (e *EventSource) Close()

Close terminates the EventSource connection.

func (*EventSource) Listen

func (e *EventSource) Listen() error

Listen connects to the server and blocks until the stream ends or Close is called. StateChange events are dispatched to Handler.

type EventType

type EventType string

EventType is the name of a type provided by a capability which may be subscribed to using a PushSubscription or EventSource connection.

const AllEvents EventType = "*"

AllEvents subscribes to all event types.

type ID

type ID string

ID is a unique identifier assigned by the server. It MUST be between 1 and 255 characters and contain only ASCII alphanumeric, hyphen, or underscore.

func (ID) MarshalJSON

func (id ID) MarshalJSON() ([]byte, error)

MarshalJSON validates the ID before marshalling.

func (ID) Valid

func (id ID) Valid() (bool, error)

Valid checks whether the ID conforms to the JMAP specification: 1-255 characters, matching [A-Za-z0-9\-_]+.

type Invocation

type Invocation struct {
	// Name is the method name, e.g. "Email/get".
	Name string

	// Args contains the method arguments (request) or response data.
	Args any

	// CallID is a client-specified identifier echoed back in responses.
	CallID string
}

Invocation represents a JMAP method call or response as a JSON 3-tuple: ["methodName", {args}, "callId"].

func (*Invocation) MarshalJSON

func (i *Invocation) MarshalJSON() ([]byte, error)

MarshalJSON encodes the Invocation as a JSON 3-tuple array.

func (*Invocation) UnmarshalJSON

func (i *Invocation) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a JSON 3-tuple array into an Invocation. The method name is looked up in the method registry to determine the concrete type for Args.

type Method

type Method interface {
	// Name returns the method name, e.g. "Email/get".
	Name() string

	// Requires returns the capability URIs required by this method.
	Requires() []URI
}

Method represents a JMAP method call that can be included in a request.

type MethodError

type MethodError struct {
	// Type is the error type, e.g. "invalidArguments", "serverFail".
	Type string `json:"type"`

	// Description provides additional detail about the error.
	Description *string `json:"description,omitempty"`
}

MethodError is returned as an Invocation response when method processing fails. It replaces the normal method response in the response array.

func (*MethodError) Error

func (m *MethodError) Error() string

Error implements the error interface.

func (*MethodError) Name

func (m *MethodError) Name() string

Name implements MethodResponse so MethodError can appear in response arrays.

type MethodResponse

type MethodResponse interface {
	// Name returns the response method name, e.g. "Email/get".
	Name() string
}

MethodResponse represents a response to a JMAP method call.

type MethodResponseFactory

type MethodResponseFactory func() MethodResponse

MethodResponseFactory creates a new zero-value MethodResponse for JSON unmarshalling.

type Operator

type Operator string

Operator is used in FilterOperator objects. Must be "AND", "OR", or "NOT".

const (
	// OperatorAND requires all conditions to match.
	OperatorAND Operator = "AND"

	// OperatorOR requires at least one condition to match.
	OperatorOR Operator = "OR"

	// OperatorNOT requires none of the conditions to match.
	OperatorNOT Operator = "NOT"
)

type Patch

type Patch map[string]any

Patch is a JMAP PatchObject used in /set update calls. Keys are JSON Pointer paths (RFC 6901), values are the values to set at those paths.

type PushKeys

type PushKeys struct {
	// Public is the P-256 ECDH public key, base64url-encoded.
	Public string `json:"p256dh"`

	// Auth is the authentication secret, base64url-encoded.
	Auth string `json:"auth"`
}

PushKeys contains the P-256 ECDH encryption keys for push notifications.

type PushSubscription

type PushSubscription struct {
	// ID is the server-assigned identifier for this subscription.
	ID ID `json:"id,omitempty"`

	// DeviceClientID is a client-supplied identifier for the device.
	DeviceClientID string `json:"deviceClientId,omitempty"`

	// URL is the endpoint to deliver push notifications to.
	URL string `json:"url,omitempty"`

	// Keys contains the encryption keys for push delivery.
	Keys *PushKeys `json:"keys,omitempty"`

	// VerificationCode is set by the client after receiving a
	// PushVerification request.
	VerificationCode string `json:"verificationCode,omitempty"`

	// Expires is when this subscription will expire.
	Expires *time.Time `json:"expires,omitempty"`

	// Types lists the event types to subscribe to.
	Types []string `json:"types,omitempty"`
}

PushSubscription represents a server-side push notification subscription (RFC 8620 Section 7.2).

type PushSubscriptionGet

type PushSubscriptionGet struct {
	IDs        []ID     `json:"ids,omitempty"`
	Properties []string `json:"properties,omitempty"`
}

PushSubscriptionGet retrieves push subscription details (RFC 8620 Section 7.2.1).

func (*PushSubscriptionGet) Name

func (m *PushSubscriptionGet) Name() string

Name implements Method.

func (*PushSubscriptionGet) Requires

func (m *PushSubscriptionGet) Requires() []URI

Requires implements Method.

type PushSubscriptionGetResponse

type PushSubscriptionGetResponse struct {
	List     []*PushSubscription `json:"list,omitempty"`
	NotFound []ID                `json:"notFound,omitempty"`
}

PushSubscriptionGetResponse is the response to PushSubscription/get.

func (*PushSubscriptionGetResponse) Name

Name implements MethodResponse.

type PushSubscriptionSet

type PushSubscriptionSet struct {
	Create  map[ID]*PushSubscription `json:"create,omitempty"`
	Update  map[ID]*Patch            `json:"update,omitempty"`
	Destroy []ID                     `json:"destroy,omitempty"`
}

PushSubscriptionSet creates, updates, or destroys push subscriptions (RFC 8620 Section 7.2.2).

func (*PushSubscriptionSet) Name

func (m *PushSubscriptionSet) Name() string

Name implements Method.

func (*PushSubscriptionSet) Requires

func (m *PushSubscriptionSet) Requires() []URI

Requires implements Method.

type PushSubscriptionSetResponse

type PushSubscriptionSetResponse struct {
	Created      map[ID]*PushSubscription `json:"created,omitempty"`
	Updated      map[ID]*PushSubscription `json:"updated,omitempty"`
	Destroyed    []ID                     `json:"destroyed,omitempty"`
	NotCreated   map[ID]*SetError         `json:"notCreated,omitempty"`
	NotUpdated   map[ID]*SetError         `json:"notUpdated,omitempty"`
	NotDestroyed map[ID]*SetError         `json:"notDestroyed,omitempty"`
}

PushSubscriptionSetResponse is the response to PushSubscription/set.

func (*PushSubscriptionSetResponse) Name

Name implements MethodResponse.

type PushVerification

type PushVerification struct {
	// Type MUST be "PushVerification".
	Type string `json:"@type"`

	// PushSubscriptionID is the ID of the subscription being verified.
	PushSubscriptionID string `json:"pushSubscriptionId"`

	// VerificationCode must be set on the subscription to confirm ownership.
	VerificationCode string `json:"verificationCode"`
}

PushVerification is sent by the server to the push subscription URL to verify ownership.

type Request

type Request struct {
	// Context is used for the HTTP request. Not serialized to JSON.
	Context context.Context `json:"-"`

	// Using lists the capability URIs required by the method calls.
	Using []URI `json:"using"`

	// Calls contains the method invocations to be processed sequentially.
	Calls []*Invocation `json:"methodCalls"`

	// CreatedIDs maps client-specified creation IDs to server-assigned IDs.
	CreatedIDs map[ID]ID `json:"createdIds,omitempty"`
}

Request represents a JMAP API request containing one or more method calls.

func (*Request) Invoke

func (r *Request) Invoke(m Method) string

Invoke adds a method call to the request and returns the assigned call ID. The call ID is the hex representation of the call's index (e.g. "0", "1"). Required capabilities from the method are automatically merged into Using.

type RequestError

type RequestError struct {
	// Type is the error type URI, e.g. "urn:ietf:params:jmap:error:limit".
	Type string `json:"type"`

	// Status is the HTTP status code of the response.
	Status int `json:"status"`

	// Detail is a human-readable description of the error.
	Detail string `json:"detail"`

	// Limit is present when Type is "urn:ietf:params:jmap:error:limit",
	// containing the name of the exceeded limit.
	Limit *string `json:"limit,omitempty"`
}

RequestError occurs when there is an error with the HTTP request itself, before any method processing occurs.

func (*RequestError) Error

func (e *RequestError) Error() string

Error implements the error interface.

type Response

type Response struct {
	// Responses contains the method responses in the same order as the
	// request's method calls.
	Responses []*Invocation `json:"methodResponses"`

	// CreatedIDs maps client-specified creation IDs to server-assigned IDs.
	CreatedIDs map[ID]ID `json:"createdIds,omitempty"`

	// SessionState is the current state string of the Session object.
	SessionState string `json:"sessionState"`
}

Response represents a JMAP API response containing method responses.

type ResultReference

type ResultReference struct {
	// ResultOf is the method call ID of the previous invocation.
	ResultOf string `json:"resultOf"`

	// Name is the required name of the response to that method call.
	Name string `json:"name"`

	// Path is a JSON Pointer (RFC 6901) into the response arguments,
	// with support for * to map through arrays.
	Path string `json:"path"`
}

ResultReference is a back-reference to a previous method call's result, used for chaining method calls within a single request.

type Session

type Session struct {
	// Capabilities maps capability URIs to their typed configuration.
	// Populated during JSON unmarshalling from RawCapabilities.
	Capabilities map[URI]Capability `json:"-"`

	// RawCapabilities holds the unparsed JSON for each capability.
	RawCapabilities map[URI]json.RawMessage `json:"capabilities"`

	// Accounts maps account IDs to Account objects.
	Accounts map[ID]Account `json:"accounts"`

	// PrimaryAccounts maps capability URIs to the primary account ID
	// for that capability.
	PrimaryAccounts map[URI]ID `json:"primaryAccounts"`

	// Username is the username associated with the authenticated credentials.
	Username string `json:"username"`

	// APIURL is the URL to use for JMAP API requests.
	APIURL string `json:"apiUrl"`

	// DownloadURL is the URL template for downloading blobs.
	DownloadURL string `json:"downloadUrl"`

	// UploadURL is the URL template for uploading blobs.
	UploadURL string `json:"uploadUrl"`

	// EventSourceURL is the URL for Server-Sent Events push.
	EventSourceURL string `json:"eventSourceUrl"`

	// State is a string representing the current state of this Session.
	State string `json:"state"`
}

Session represents the JMAP Session Resource (RFC 8620 Section 2). It is retrieved via GET on the session endpoint and describes the server's capabilities, accounts, and API URLs.

func (*Session) UnmarshalJSON

func (s *Session) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes the Session and resolves registered capabilities.

type SetError

type SetError struct {
	// Type is the error type, e.g. "invalidProperties", "notFound".
	Type string `json:"type"`

	// Description provides a debugging explanation of the problem.
	Description *string `json:"description,omitempty"`

	// Properties lists the invalid properties (for "invalidProperties" errors).
	Properties *[]string `json:"properties,omitempty"`
}

SetError is returned in /set responses for individual record failures.

func (*SetError) Error

func (e *SetError) Error() string

Error implements the error interface.

type StateChange

type StateChange struct {
	// Type MUST be the string "StateChange".
	Type string `json:"@type"`

	// Changed maps account IDs to their changed type states.
	Changed map[ID]TypeState `json:"changed"`
}

StateChange is sent to the client via push mechanisms to notify when data has changed (RFC 8620 Section 7.1).

type TypeState

type TypeState map[string]string

TypeState maps object type names (e.g. "Mailbox", "Email") to their current state strings.

type URI

type URI string

URI is an identifier of a capability, e.g. "urn:ietf:params:jmap:core".

const (
	// CoreURI is the core JMAP capability required by all requests.
	CoreURI URI = "urn:ietf:params:jmap:core"

	// MailURI is the JMAP Mail capability (RFC 8621).
	MailURI URI = "urn:ietf:params:jmap:mail"

	// SubmissionURI is the JMAP Email Submission capability (RFC 8621).
	SubmissionURI URI = "urn:ietf:params:jmap:submission"

	// VacationResponseURI is the JMAP VacationResponse capability (RFC 8621).
	VacationResponseURI URI = "urn:ietf:params:jmap:vacationresponse"

	// ContactsURI is the JMAP Contacts capability (RFC 9610).
	ContactsURI URI = "urn:ietf:params:jmap:contacts"

	// CalendarsURI is the JMAP Calendars capability.
	CalendarsURI URI = "urn:ietf:params:jmap:calendars"

	// WebSocketURI is the JMAP WebSocket capability (RFC 8887).
	WebSocketURI URI = "urn:ietf:params:jmap:websocket"

	// BlobURI is the JMAP Blob Management capability (RFC 9404).
	BlobURI URI = "urn:ietf:params:jmap:blob"

	// QuotaURI is the JMAP Quotas capability (RFC 9425).
	QuotaURI URI = "urn:ietf:params:jmap:quota"

	// SieveURI is the JMAP Sieve Scripts capability (RFC 9661).
	SieveURI URI = "urn:ietf:params:jmap:sieve"

	// SharingURI is the JMAP Sharing capability (RFC 9670).
	SharingURI URI = "urn:ietf:params:jmap:principals"

	// ShareNotificationURI is the JMAP Share Notification capability (RFC 9670).
	ShareNotificationURI URI = "urn:ietf:params:jmap:principals:owner"

	// MDNURI is the JMAP MDN capability (RFC 9007).
	MDNURI URI = "urn:ietf:params:jmap:mdn"

	// SMIMEURI is the JMAP S/MIME capability (RFC 9219).
	SMIMEURI URI = "urn:ietf:params:jmap:smimeverify"

	// VAPIDURI is the JMAP VAPID push capability (RFC 9749).
	VAPIDURI URI = "urn:ietf:params:jmap:vapid"
)

Common JMAP capability URIs.

type UploadResponse

type UploadResponse struct {
	// AccountID is the account used for the upload.
	AccountID ID `json:"accountId"`

	// BlobID is the identifier for the uploaded binary data.
	BlobID ID `json:"blobId"`

	// Type is the media type of the uploaded file.
	Type string `json:"type"`

	// Size is the size of the uploaded file in octets.
	Size uint64 `json:"size"`
}

UploadResponse is returned by the server after a successful blob upload.

type VAPIDCapability

type VAPIDCapability struct {
	// ApplicationServerKey is the VAPID public key (base64url-encoded).
	ApplicationServerKey string `json:"applicationServerKey"`
}

VAPIDCapability represents the urn:ietf:params:jmap:vapid capability (RFC 9749) which provides the server's VAPID application server key for Web Push authentication.

func (*VAPIDCapability) New

func (c *VAPIDCapability) New() Capability

New implements Capability.

func (*VAPIDCapability) URI

func (c *VAPIDCapability) URI() URI

URI implements Capability.

type WebSocketCapability

type WebSocketCapability struct {
	// URL is the WebSocket endpoint URL.
	URL string `json:"url"`

	// SupportsPush indicates whether the server supports push over WebSocket.
	SupportsPush bool `json:"supportsPush"`
}

WebSocketCapability represents the urn:ietf:params:jmap:websocket capability (RFC 8887).

func (*WebSocketCapability) New

New implements Capability.

func (*WebSocketCapability) URI

func (c *WebSocketCapability) URI() URI

URI implements Capability.

type WebSocketClient

type WebSocketClient struct {

	// Client is the JMAP client used for session discovery.
	Client *Client

	// PushHandler is called when a StateChange push is received.
	PushHandler func(*StateChange)
	// contains filtered or unexported fields
}

WebSocketClient provides a JMAP client using the WebSocket transport defined in RFC 8887.

func (*WebSocketClient) Close

func (ws *WebSocketClient) Close() error

Close closes the WebSocket connection.

func (*WebSocketClient) Connect

func (ws *WebSocketClient) Connect(ctx context.Context) error

Connect establishes a WebSocket connection to the JMAP server. The session must already contain the WebSocket capability.

func (*WebSocketClient) DisablePush

func (ws *WebSocketClient) DisablePush(ctx context.Context) error

DisablePush sends a WebSocketPushDisable message.

func (*WebSocketClient) Do

func (ws *WebSocketClient) Do(ctx context.Context, req *Request) (*Response, error)

Do sends a JMAP request over the WebSocket and waits for the response.

func (*WebSocketClient) EnablePush

func (ws *WebSocketClient) EnablePush(ctx context.Context, dataTypes []EventType, pushState string) error

EnablePush sends a WebSocketPushEnable message to start receiving push notifications over the WebSocket connection.

type WebSocketPushDisable

type WebSocketPushDisable struct {
	Type string `json:"@type"` // Must be "WebSocketPushDisable"
}

WebSocketPushDisable disables push notifications over WebSocket (RFC 8887 Section 4.3).

type WebSocketPushEnable

type WebSocketPushEnable struct {
	Type      string      `json:"@type"` // Must be "WebSocketPushEnable"
	DataTypes []EventType `json:"dataTypes,omitempty"`
	PushState string      `json:"pushState,omitempty"`
}

WebSocketPushEnable enables push notifications over a WebSocket connection (RFC 8887 Section 4.3).

type WebSocketRequest

type WebSocketRequest struct {
	Type string `json:"@type"` // Must be "Request"
	ID   string `json:"id,omitempty"`

	Using      []URI         `json:"using"`
	Calls      []*Invocation `json:"methodCalls"`
	CreatedIDs map[ID]ID     `json:"createdIds,omitempty"`
}

WebSocketRequest is the JSON structure sent over WebSocket for API requests (RFC 8887 Section 4.1).

type WebSocketResponse

type WebSocketResponse struct {
	Type string `json:"@type"` // "Response" or "RequestError"
	// RequestID correlates the response to the request.
	RequestID string `json:"requestId,omitempty"`

	// Response fields (when @type is "Response")
	Responses    []*Invocation `json:"methodResponses,omitempty"`
	CreatedIDs   map[ID]ID     `json:"createdIds,omitempty"`
	SessionState string        `json:"sessionState,omitempty"`

	// Error fields (when @type is "RequestError")
	ErrorType string  `json:"type,omitempty"`
	Status    int     `json:"status,omitempty"`
	Detail    string  `json:"detail,omitempty"`
	Limit     *string `json:"limit,omitempty"`
}

WebSocketResponse is the JSON structure received over WebSocket for API responses (RFC 8887 Section 4.2).

Directories

Path Synopsis
Package blob implements JMAP Blob Management (RFC 9404).
Package blob implements JMAP Blob Management (RFC 9404).
Package calendar implements the JMAP Calendars protocol (draft-ietf-jmap-calendars-26), providing Calendar, Event, and ParticipantIdentity data types and methods.
Package calendar implements the JMAP Calendars protocol (draft-ietf-jmap-calendars-26), providing Calendar, Event, and ParticipantIdentity data types and methods.
Package contacts implements the JMAP Contacts protocol (RFC 9610), providing AddressBook and ContactCard data types and methods, with the JSContact Card data model (RFC 9553).
Package contacts implements the JMAP Contacts protocol (RFC 9610), providing AddressBook and ContactCard data types and methods, with the JSContact Card data model (RFC 9553).
Package mail implements JMAP Mail (RFC 8621), JMAP MDN (RFC 9007), and JMAP S/MIME Verification (RFC 9219).
Package mail implements JMAP Mail (RFC 8621), JMAP MDN (RFC 9007), and JMAP S/MIME Verification (RFC 9219).
Package quota implements JMAP Quotas (RFC 9425).
Package quota implements JMAP Quotas (RFC 9425).
Package sharing implements the JMAP Sharing protocol (RFC 9670), providing Principal and ShareNotification data types and methods.
Package sharing implements the JMAP Sharing protocol (RFC 9670), providing Principal and ShareNotification data types and methods.
Package sieve implements JMAP Sieve Scripts (RFC 9661).
Package sieve implements JMAP Sieve Scripts (RFC 9661).
Package stalwart implements helpers for Stalwart's JMAP management schema.
Package stalwart implements helpers for Stalwart's JMAP management schema.

Jump to

Keyboard shortcuts

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