gomap

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 4, 2026 License: BSD-3-Clause Imports: 5 Imported by: 0

README

Go Reference Go Report Card License

gomap

Go module for interfacing with JMAP mail servers, such as Fastmail.

Usage

To add the module to your project:

go get -u github.com/cwinters8/gomap

First, create a new mail client. You will need a session URL and a bearer token from your JMAP mail server. For Fastmail, the session URL is https://api.fastmail.com/jmap/session, and you can create an API token in Settings > Privacy & Security > Integrations > API tokens. You will most likely need to give access to Email (for querying and reading email contents) and Email submission (for sending emails) when you create the token.

mail, err := gomap.NewClient(
  "https://api.fastmail.com/jmap/session",
  os.Getenv("BEARER_TOKEN"),
  gomap.DefaultDrafts,
  gomap.DefaultSent,
)
if err != nil {
  log.Fatal(err)
}

Then you can use the client for your chosen operations. Check out the examples for full details on how to send and find emails.

Sending with a custom visible From address

JMAP requires every EmailSubmission to be associated with an account Identity, but the message's visible From header is part of the Email object. Use SendEmailWithIdentity when those values need to differ, such as contact-form notifications where the visible sender should be the email address submitted in the form while the authenticated mailbox identity is used for submission:

submitter := gomap.NewAddress("Form Submitter", "[email protected]")
recipient := gomap.NewAddress("Contact Inbox", "[email protected]")

err := mail.SendEmailWithIdentity(
  gomap.NewAddresses(submitter),
  gomap.NewAddresses(recipient),
  "Contact form submission",
  "Message body",
  "[email protected]", // authenticated JMAP identity email
  false,
)

Servers may still reject this if the selected identity is not permitted to use the requested From header.

Documentation

Index

Examples

Constants

View Source
const (
	DefaultDrafts = "Drafts"
	DefaultSent   = "Sent"
)

Variables

This section is empty.

Functions

func NewAddress

func NewAddress(name, email string) *emails.Address

NewAddress is a convenience function for creating a new *emails.Address

Types

type Addresses

type Addresses []*emails.Address

func NewAddresses

func NewAddresses(addresses ...*emails.Address) Addresses

NewAddresses creates a new Addresses slice that can be used for sending emails

type Client

type Client struct {
	*client.Client
	Drafts *mailboxes.Mailbox
	Sent   *mailboxes.Mailbox
}

func NewClient

func NewClient(jmapSessionURL, bearerToken, draftsMailbox, sentMailbox string) (*Client, error)

NewClient creates a new JMAP mail client that can be used for interacting with the JMAP mail server specified with jmapSessionURL.

Commonly, draftsMailbox should be "Drafts" and sentMailbox should be "Sent". These arguments are available in case customization is necessary. You can use the DefaultDrafts and DefaultSent constants for convenience.

func (*Client) GetEmails

func (c *Client) GetEmails(filter *Filter, maxCount int, timeout time.Duration) ([]*emails.Email, error)

GetEmails retrieves emails based on the provided filter. It will continue to query until the first of maxCount or timeout has been reached.

maxCount is used as a metric for breaking out of the query loop, not a hard limit on the number of emails returned.

Example
package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/cwinters8/gomap"
	"github.com/google/uuid"
)

func main() {
	mail, err := gomap.NewClient(
		"https://api.fastmail.com/jmap/session",
		os.Getenv("BEARER_TOKEN"),
		gomap.DefaultDrafts,
		gomap.DefaultSent,
	)
	if err != nil {
		log.Fatal(err)
	}

	// send an email with a unique identifier
	from := gomap.NewAddress("Clark Winters", "[email protected]")
	to := gomap.NewAddress("Tester Gopher", "[email protected]")

	id := uuid.New()
	strID := id.String()

	if err := mail.SendEmail(
		gomap.NewAddresses(from),
		gomap.NewAddresses(to),
		"Hello from gomap!",
		fmt.Sprintf("ID: %s", strID),
		false,
	); err != nil {
		log.Fatal(err)
	}

	// retrieve the email
	emails, err := mail.GetEmails(&gomap.Filter{Text: strID}, 1, 30*time.Second)
	if err != nil {
		log.Fatal(err)
	}
	if len(emails) > 0 {
		email := emails[0]
		wantBody := fmt.Sprintf("ID: %s", strID)
		fmt.Println("found email:")
		fmt.Printf("\tfrom: %+v\n", *email.From[0])
		fmt.Printf("\tto: %+v\n", *email.To[0])
		fmt.Printf("\tsubject: %s\n", email.Subject)
		if email.Body.Value != wantBody {
			log.Fatalf("retrieved email body %q does not match expected body %q", email.Body.Value, wantBody)
		}
		fmt.Println("\tbody: ID: <generated>")
	}

}
Output:
found email:
	from: {Name:Clark Winters Email:[email protected]}
	to: {Name:Tester Gopher Email:[email protected]}
	subject: Hello from gomap!
	body: ID: <generated>

func (*Client) GetMailbox

func (c *Client) GetMailbox(name string) (*mailboxes.Mailbox, error)

GetMailbox retrieves a mailbox with the matching name.

func (*Client) SendEmail

func (c *Client) SendEmail(from, to Addresses, subject, body string, isHTML bool) error

SendEmail sends an email using the provided arguments.

Addresses in from must be owned by the account authenticated with the Client, otherwise the email will fail to send.

Setting isHTML to true will set the body type attribute to HTML instead of plaintext. This works best if body is a string that has been output from executing an html/template.

Example
package main

import (
	"log"
	"os"

	"github.com/cwinters8/gomap"
)

func main() {
	mail, err := gomap.NewClient(
		"https://api.fastmail.com/jmap/session",
		os.Getenv("BEARER_TOKEN"),
		gomap.DefaultDrafts,
		gomap.DefaultSent,
	)
	if err != nil {
		log.Fatal(err)
	}

	// send an email
	from := gomap.NewAddress("Clark Winters", "[email protected]")
	to := gomap.NewAddress("Tester Gopher", "[email protected]")

	if err := mail.SendEmail(
		gomap.NewAddresses(from),
		gomap.NewAddresses(to),
		"Hello from gomap!",
		"Hello Tester Gopher,\n\nNice to meet you.",
		false,
	); err != nil {
		log.Fatal(err)
	}
}

func (*Client) SendEmailWithIdentity added in v0.2.0

func (c *Client) SendEmailWithIdentity(from, to Addresses, subject, body, identityEmail string, isHTML bool) error

SendEmailWithIdentity sends an email with the provided visible From header, while using identityEmail to choose the JMAP Identity for the submission.

JMAP separates the RFC 5322 From header from the submission Identity. This method is useful for contact-form style messages where the visible From address should be supplied by the form submitter, but the authenticated JMAP account's identity must still be used for EmailSubmission/create. Servers may still reject the send if the selected Identity is not allowed to use the message's From header.

type Filter

type Filter emails.Filter

Directories

Path Synopsis
objects

Jump to

Keyboard shortcuts

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