JMAP library for Go
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
agent 64790e655f
All checks were successful
Roll release / plan (push) Successful in 5s
Roll release / changelog (push) Has been skipped
Roll release / test (push) Successful in 1m12s
Roll release / ci (push) Successful in 0s
Roll release / release (push) Successful in 6s
Cut release / changelog (push) Has been skipped
Cut release / test (push) Successful in 52s
Cut release / ci (push) Successful in 0s
Cut release / cut (push) Successful in 6s
Release 0.27.0
2026-10-23 18:11:20 +02:00
.forgejo/workflows CHANGELOG.md drives releases: cut a tag, publish the release 2026-10-23 18:07:53 +02:00
.github/workflows fix: dismiss stale reviews after new review, not before 2026-02-18 08:15:44 +01:00
core Module path is sarak.sh/mikluko/jmap 2026-10-23 17:30:50 +02:00
mail Module path is sarak.sh/mikluko/jmap 2026-10-23 17:30:50 +02:00
sieve Module path is sarak.sh/mikluko/jmap 2026-10-23 17:30:50 +02:00
.gitignore chore: update .gitignore configuration to ensure the file itself is tracked 2026-02-18 07:24:50 +01:00
account.go jmap: reword comments 2023-11-02 19:32:16 -05:00
AGENTS.md CHANGELOG.md drives releases: cut a tag, publish the release 2026-10-23 18:07:53 +02:00
capability.go uri: use a type for URIs for better readability 2023-02-01 11:18:33 -06:00
CHANGELOG.md Release 0.27.0 2026-10-23 18:11:20 +02:00
client.go client: check RawCapabilities field for capabilities 2025-02-01 07:08:03 -06:00
errors.go feat: implement RFC 9661 JMAP for Sieve Scripts 2026-02-18 07:52:40 +01:00
example_test.go Module path is sarak.sh/mikluko/jmap 2026-10-23 17:30:50 +02:00
go.mod Module path is sarak.sh/mikluko/jmap 2026-10-23 17:30:50 +02:00
go.sum build(deps): bump golang.org/x/oauth2 from 0.4.0 to 0.27.0 2026-02-18 07:09:31 +00:00
invocation.go email: Fix reported name of some methods 2023-01-29 17:19:54 -06:00
invocation_test.go methodresponse: define MethodResponse interface 2023-01-31 11:56:12 -06:00
jmap.go jmap: expose ID::Valid() function 2024-05-21 06:18:04 -05:00
jmap_test.go jmap: expose ID::Valid() function 2024-05-21 06:18:04 -05:00
LICENSE chore: update copyright 2022-08-06 08:05:57 -05:00
method.go uri: use a type for URIs for better readability 2023-02-01 11:18:33 -06:00
README.md Module path is sarak.sh/mikluko/jmap 2026-10-23 17:30:50 +02:00
request.go client: add Context to requests 2023-02-11 07:52:43 -06:00
request_test.go chore: fix request_test 2023-02-09 14:55:43 -06:00
response.go jmap: reword comments 2023-11-02 19:32:16 -05:00
response_test.go api: update registration API for methods and capabilities 2023-01-29 15:35:17 -06:00
session.go jmap: reword comments 2023-11-02 19:32:16 -05:00
session_test.go uri: use a type for URIs for better readability 2023-02-01 11:18:33 -06:00
statechange.go jmap: reword comments 2023-11-02 19:32:16 -05:00

jmap

A JMAP client library. Includes support for all core functionality (including PushSubscription and EventSource event streams), mail, smime-verify, and MDN specifications

Note: this library started as a fork of github.com/foxcpp/go-jmap It has since undergone massive refactoring and probably doesn't look very similar anymore, but many thanks to foxcpp for the initial work.

Usage

package main

import (
	"fmt"

	"sarak.sh/mikluko/jmap"
	"sarak.sh/mikluko/jmap/mail"
	"sarak.sh/mikluko/jmap/mail/email"
	"sarak.sh/mikluko/jmap/mail/mailbox"
)

func main() {
	// Create a new client. The SessionEndpoint must be specified for
	// initial connections.
	client := &jmap.Client{
		SessionEndpoint: "https://api.fastmail.com/jmap/session",
	}
	// Set the authentication mechanism. This also sets the HttpClient of
	// the jmap client
	client.WithAccessToken("my-access-token")

	// Authenticate the client. This gets a Session object. Session objects
	// are cacheable, and have their own state string clients can use to
	// decide when to refresh. The client can be initialized with a cached
	// Session object. If one isn't available, the first request will also
	// authenticate the client
	if err := client.Authenticate(); err != nil {
		// Handle the error
	}

	// Get the account ID of the primary mail account
	id := client.Session.PrimaryAccounts[mail.URI]

	// Create a new request
	req := &jmap.Request{}

	// Invoke a method. The CallID of this method will be returned to be
	// used when chaining calls
	req.Invoke(&mailbox.Get{
		Account: id,
	})

	// Invoke a changes call, let's save the callID and pass it to a Get
	// method
	callID := req.Invoke(&email.Changes{
		Account: id,
		SinceState: "some-known-state",
	})

	// Invoke a result reference call
	req.Invoke(&email.Get{
		Account: id,
		ReferenceIDs: &jmap.ResultReference{
			ResultOf: callID, // The CallID of the referenced method
			Name: "Email/changes", // The name of the referenced method
			Path: "/created", // JSON pointer to the location of the reference
		},
	})

	// Make the request
	resp, err := client.Do(req)
	if err != nil {
		// Handle the error
	}

	// Loop through the responses to invidividual invocations
	for _, inv := range resp.Responses {
		// Our result to individual calls is in the Args field of the
		// invocation
		switch r := inv.Args.(type) {
		case *mailbox.GetResponse:
			// A GetResponse contains a List of the objects
			// retrieved
			for _, mbox := range r.List {
				fmt.Printf("Mailbox name: %s", mbox.Name)
				fmt.Printf("Total email: %d", mbox.TotalEmails)
				fmt.Printf("Unread email: %d", mbox.UnreadEmails)
			}
		case *email.GetResponse:
			for _, eml := range r.List {
				fmt.Printf("Email subject: %s", eml.Subject)
			}
		}
		// There is a response in here to the Email/changes call, but we
		// don't care about the results since we passed them to the
		// Email/get call
	}
}

Status

Core (RFC 8620)

Complete

Mail (RFC 8621)

Complete

MDN (RFC 9007)

Complete

WebSocket (RFC 8887)

Not started

S/MIME (RFC 9219)

Complete