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 ¶
- type Config
- type Mailbox
- func (m *Mailbox) Append(ctx context.Context, folder string, raw []byte, flags []string, date time.Time) (mail.MsgRef, error)
- func (m *Mailbox) Capabilities() mail.Caps
- func (m *Mailbox) Close() error
- func (m *Mailbox) Delete(ctx context.Context, ref mail.MsgRef) error
- func (m *Mailbox) EnsureFolder(ctx context.Context, name string) error
- func (m *Mailbox) Fetch(ctx context.Context, ref mail.MsgRef, maxBody int) (*message.Raw, error)
- func (m *Mailbox) FetchMany(ctx context.Context, refs []mail.MsgRef, maxBody int) ([]*message.Raw, error)
- func (m *Mailbox) FetchSince(ctx context.Context, folder string, since time.Time, limit int) (refs []mail.MsgRef, matched int, err error)
- func (m *Mailbox) FindByMessageID(ctx context.Context, folder, messageID string) (mail.MsgRef, error)
- func (m *Mailbox) Flags(ctx context.Context, ref mail.MsgRef) ([]string, error)
- func (m *Mailbox) Folders(ctx context.Context) ([]mail.Folder, error)
- func (m *Mailbox) Move(ctx context.Context, ref mail.MsgRef, dest string) (mail.MsgRef, error)
- func (m *Mailbox) MoveMany(ctx context.Context, refs []mail.MsgRef, dest string) ([]mail.MsgRef, error)
- func (m *Mailbox) Present(ctx context.Context, folder string, uidValidity uint32, uids []uint32) ([]uint32, error)
- func (m *Mailbox) SentRecipients(ctx context.Context, folder string, limit int) ([]mail.Recipient, error)
- func (m *Mailbox) SetFlags(ctx context.Context, ref mail.MsgRef, add, remove []string) error
- func (m *Mailbox) Status(ctx context.Context, folder string) (mail.FolderStatus, error)
- func (m *Mailbox) Watch(ctx context.Context, folder string, lastUID uint32, out chan<- mail.NewMail) error
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 (*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 ¶
Capabilities reports what the server advertised after login.
func (*Mailbox) Close ¶
Close drops the worker connection. A running Watch stops through its context.
func (*Mailbox) Delete ¶ added in v0.3.0
Delete marks the one message deleted and expunges that UID alone (UID EXPUNGE, UIDPLUS).
func (*Mailbox) EnsureFolder ¶
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) 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) Folders ¶
Folders runs LIST "" "*", asking for special-use attributes where the server can return them.
func (*Mailbox) Move ¶
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) 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).