imap

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: AGPL-3.0 Imports: 22 Imported by: 0

Documentation

Overview

Package imap implements mail.Mailbox over IMAP with go-imap v2.

Each Mailbox uses two connections: Watch dials its own long-lived one that only selects, searches and IDLEs, and every other method shares one worker connection, dialed on first use and redialed when the server has dropped it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	AccountID int64
	Host      string
	Port      int
	TLSMode   string // presets.TLSImplicit or presets.TLSStartTLS; there is no plaintext mode
	Username  string
	Password  string
	Preset    presets.Preset // folder-name fallbacks; zero means generic
	TLSConfig *tls.Config    // nil uses the system roots; tests pass their own CA
	Logger    *slog.Logger   // nil uses slog.Default()

	// CertFingerprint is the server certificate the person accepted (mail.Cert.Fingerprint).
	// When set, the server must present exactly that certificate, and the system's roots
	// and the host name are not checked: the pin replaces both. Empty trusts the system.
	CertFingerprint string

	// Token, when set, is how the account signs in: with OAuth (SASL XOAUTH2) as Username,
	// with the access token it returns, asked for again just before every login, so a
	// connection the server closed when its token expired comes back with a fresh one.
	// Password is not used. An error that wraps mail.ErrReconnect stops the account; any
	// other is a failed connection, retried. The server refusing the token is
	// mail.ErrReconnect too: the only fix is signing in to the provider again.
	Token func(ctx context.Context) (string, error)

	// Dial makes the TCP connection to Host:Port, before TLS; nil is a plain net.Dialer.
	// The hosted build passes one that connects only to public addresses (publicnet).
	Dial func(ctx context.Context, network, address string) (net.Conn, error)

	// Timers. Zero means the default; tests shrink them to milliseconds.
	IdleRestart     time.Duration // leave IDLE and check the connection (25 min)
	PollInterval    time.Duration // search for new mail when the server lacks IDLE (60 s)
	BackoffMin      time.Duration // first reconnect delay (1 s), doubling up to BackoffMax
	BackoffMax      time.Duration // longest reconnect delay (5 min)
	ThrottleBackoff time.Duration // delay after [UNAVAILABLE] or throttling (5 min)
	// contains filtered or unexported fields
}

Config is everything needed to reach one account.

type Mailbox

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

Mailbox is a mail.Mailbox over IMAP.

func Open

func Open(ctx context.Context, cfg Config) (*Mailbox, error)

Open logs in once, which checks the credentials and reads the server's capabilities.

func (*Mailbox) Append added in v0.3.0

func (m *Mailbox) Append(ctx context.Context, folder string, raw []byte, flags []string, date time.Time) (mail.MsgRef, error)

Append sends APPEND with the flags and internal date. The UID comes from APPENDUID; a server without UIDPLUS is searched for the message's Message-ID instead.

func (*Mailbox) Capabilities

func (m *Mailbox) Capabilities() mail.Caps

Capabilities reports what the server advertised after login.

func (*Mailbox) Close

func (m *Mailbox) Close() error

Close drops the worker connection. A running Watch stops through its context.

func (*Mailbox) Delete added in v0.3.0

func (m *Mailbox) Delete(ctx context.Context, ref mail.MsgRef) error

Delete marks the one message deleted and expunges that UID alone (UID EXPUNGE, UIDPLUS).

func (*Mailbox) EnsureFolder

func (m *Mailbox) EnsureFolder(ctx context.Context, name string) error

EnsureFolder creates name and any missing parents, split on the server's hierarchy delimiter, and subscribes what it creates. name is a server-side name, as Folders returns.

func (*Mailbox) Fetch

func (m *Mailbox) Fetch(ctx context.Context, ref mail.MsgRef, maxBody int) (*message.Raw, error)

Fetch reads one message with BODY.PEEK only, so it stays unread.

func (*Mailbox) FetchMany

func (m *Mailbox) FetchMany(ctx context.Context, refs []mail.MsgRef, maxBody int) ([]*message.Raw, error)

FetchMany reads the messages with one UID FETCH, BODY.PEEK only, so they stay unread. A UID the server does not return, or a folder whose UIDVALIDITY has changed, means gone.

func (*Mailbox) FetchSince

func (m *Mailbox) FetchSince(ctx context.Context, folder string, since time.Time, limit int) (refs []mail.MsgRef, matched int, err error)

FetchSince searches by internal date, which IMAP compares by day.

func (*Mailbox) FindByMessageID

func (m *Mailbox) FindByMessageID(ctx context.Context, folder, messageID string) (mail.MsgRef, error)

FindByMessageID searches the Message-ID header; angle brackets are optional.

func (*Mailbox) Flags

func (m *Mailbox) Flags(ctx context.Context, ref mail.MsgRef) ([]string, error)

Flags returns the message's current flags, sorted.

func (*Mailbox) Folders

func (m *Mailbox) Folders(ctx context.Context) ([]mail.Folder, error)

Folders runs LIST "" "*", asking for special-use attributes where the server can return them.

func (*Mailbox) Move

func (m *Mailbox) Move(ctx context.Context, ref mail.MsgRef, dest string) (mail.MsgRef, error)

Move uses UID MOVE, or UID COPY, UID STORE +FLAGS (\Deleted) and UID EXPUNGE of that one UID. It never sends a bare EXPUNGE, which would also remove mail other clients had marked deleted; a server with neither MOVE nor UIDPLUS gets ErrUnsupported instead.

func (*Mailbox) MoveMany added in v0.3.0

func (m *Mailbox) MoveMany(ctx context.Context, refs []mail.MsgRef, dest string) ([]mail.MsgRef, error)

MoveMany is Move for many messages of one folder: one UID FETCH to learn which are still there, then one UID MOVE (or UID COPY, UID STORE and UID EXPUNGE of exactly the UIDs copied) for all of them. Without UIDPLUS no COPYUID says where they went, so each is found again in dest by its Message-ID, and one that has none is left where it is.

func (*Mailbox) Present added in v0.3.0

func (m *Mailbox) Present(ctx context.Context, folder string, uidValidity uint32, uids []uint32) ([]uint32, error)

Present sends one UID SEARCH UID <uids> NOT DELETED, after syncFolder, so a message another client moved or expunged since the session last looked is already gone.

func (*Mailbox) SentRecipients

func (m *Mailbox) SentRecipients(ctx context.Context, folder string, limit int) ([]mail.Recipient, error)

SentRecipients peeks at the To and Cc headers of the newest limit messages. The folder is opened read-only (EXAMINE), so nothing in it can change.

func (*Mailbox) SetFlags

func (m *Mailbox) SetFlags(ctx context.Context, ref mail.MsgRef, add, remove []string) error

SetFlags adds and removes flags without reading the message.

func (*Mailbox) Status

func (m *Mailbox) Status(ctx context.Context, folder string) (mail.FolderStatus, error)

Status asks for UIDVALIDITY and UIDNEXT without selecting the folder.

func (*Mailbox) Watch

func (m *Mailbox) Watch(ctx context.Context, folder string, lastUID uint32, out chan<- mail.NewMail) error

Watch reports every message in folder with a UID above lastUID, in UID order: first the backlog, then arrivals as IDLE (or polling, without IDLE) announces them. It keeps its own connection and its own high-water mark, so after a dropped connection it resumes exactly where it stopped: nothing is skipped and nothing is sent twice.

It returns when ctx is done, or early for errors that reconnecting cannot fix: wrong credentials (mail.ErrAuth), a one-click sign-in to renew (mail.ErrReconnect), a TLS failure (mail.ErrTLS), a missing folder (mail.ErrNoFolder) or a server the hosted build does not connect to (mail.ErrNotPublic). A server that closes the connection, as Gmail and Outlook do when an access token expires, is reconnected to like any lost connection, with a fresh token (Config.Token).

Directories

Path Synopsis
Package imaptest runs go-imap's in-memory IMAP server over TLS for integration tests.
Package imaptest runs go-imap's in-memory IMAP server over TLS for integration tests.

Jump to

Keyboard shortcuts

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