net.imap #
A sequence set names the messages a command applies to (RFC 3501 section 9, sequence-set). It is a comma separated list of numbers and ranges, and * stands for the highest number in the mailbox.
Ranges matter: a mailbox with fifty thousand messages is addressed as 1:50000, where a list of every number would be a command line no server is obliged to accept. Modified UTF-7 is how IMAP carries mailbox names that are not plain US-ASCII (RFC 3501 section 5.1.3). It differs from UTF-7 on three points: & shifts into base64 rather than +, the base64 alphabet ends in , instead of / so that the popular hierarchy delimiter stays usable, and printable US-ASCII must never be encoded.
Names travel encoded and are handed to the caller decoded, so a program using this module works in ordinary UTF-8 throughout.
Constants #
const default_port = 143
The port a server listens on depends on whether TLS is negotiated up front.
const default_ssl_port = 993
fn new_client #
fn new_client(config Config) !&Client
new_client opens a session, greets the server, upgrades the connection if asked to, and logs in.
fn parse_seq_set #
fn parse_seq_set(s string) !SeqSet
parse_seq_set reads a set back from its wire form, such as 2,4:7,9:*.
fn seq_all #
fn seq_all() SeqSet
seq_all is the set every message in the mailbox belongs to, 1:*.
fn seq_range #
fn seq_range(start u32, stop u32) SeqSet
seq_range builds a set holding the single range start:stop.
fn seq_set #
fn seq_set(numbers []u32) SeqSet
seq_set builds a set from a list of numbers.
fn utf7_decode #
fn utf7_decode(s string) !string
utf7_decode reads a mailbox name back out of modified UTF-7.
Bytes above US-ASCII are passed through as they are: some servers send raw UTF-8 despite the convention, and refusing it would hide their mailboxes.
fn utf7_encode #
fn utf7_encode(s string) string
utf7_encode renders a mailbox name in modified UTF-7.
fn AuthMethod.from #
fn AuthMethod.from[W](input W) !AuthMethod
fn Status.from #
fn Status.from[W](input W) !Status
fn TokenKind.from #
fn TokenKind.from[W](input W) !TokenKind
enum AuthMethod #
enum AuthMethod {
login
plain
}
AuthMethod selects how new_client authenticates configured credentials.
enum Status #
enum Status {
ok
no
bad
bye
preauth
}
Status is the outcome a tagged completion reports.
struct Address #
struct Address {
pub:
name string
// mailbox is the part before the `@`, or the group name when `host` is
// empty and this address opens a group.
mailbox string
// host is the part after the `@`.
host string
}
Address is one sender or recipient, as an envelope carries it. name is the display name, empty when the message gave none.
fn (Address) addr #
fn (a &Address) addr() string
addr renders the address as someone@example.com, and is empty for the markers that open and close a group.
struct BodyStructure #
struct BodyStructure {
pub:
media_type string
media_subtype string
params map[string]string
id string
description string
encoding string
message_envelope ?Envelope
message_structure ?&BodyStructure
// size is the part's length in octets, and `lines` its line count for a
// text part.
size u32
lines u32
parts []BodyStructure
}
BodyStructure describes one MIME part. A multipart has parts filled in and a media type of multipart. A message/rfc822 part retains the attached message's envelope and MIME tree in message_envelope and message_structure.
fn (BodyStructure) mime_type #
fn (b &BodyStructure) mime_type() string
mime_type renders the pair as it appears in a Content-Type header.
struct Client #
struct Client {
Config
mut:
conn net.TcpConn
ssl_conn &ssl.SSLConn = unsafe { nil }
dec ?&Decoder
tag_seq int
// transport_open is separate from is_open: an unsolicited BYE makes the
// session unusable before the local socket has necessarily been closed.
transport_open bool
authenticated bool
logging_out bool
server_capabilities []string
pub mut:
is_open bool
encrypted bool
// selected names the mailbox the session is working in, and is empty when
// none has been selected.
selected string
// exists and recent track the counts the server reports, which it may do
// during any command as messages arrive or are removed by another client.
exists u32
recent u32
}
Client is a connection to an IMAP server.
fn (Client) connect #
fn (mut c Client) connect() !
connect opens the transport and reads the server greeting, without logging in. new_client calls it; call it directly only to drive a session by hand.
fn (Client) login #
fn (mut c Client) login() !
login authenticates with the LOGIN command, and does nothing when no username was configured.
fn (Client) login_plain #
fn (mut c Client) login_plain() !
login_plain authenticates with the SASL PLAIN mechanism instead, which some servers require and others prefer.
fn (Client) capability #
fn (mut c Client) capability() ![]string
capability returns the extensions the server advertises.
fn (Client) supports #
fn (mut c Client) supports(name string) !bool
supports reports whether the server advertises name, which is how an optional command should be guarded before it is sent.
fn (Client) noop #
fn (mut c Client) noop() !
noop asks the server for nothing. It keeps the connection alive, and gives the server the chance to report anything that changed in the mailbox.
fn (Client) list_mailboxes #
fn (mut c Client) list_mailboxes(reference string, pattern string) ![]MailboxInfo
list_mailboxes returns the mailboxes matching pattern below reference.
The usual call is list_mailboxes('', '*'), which lists everything the account can see. % matches within one level of the hierarchy where * crosses levels.
fn (Client) list_subscribed #
fn (mut c Client) list_subscribed(reference string, pattern string) ![]MailboxInfo
list_subscribed returns the subscribed mailboxes matching pattern, which is the set a mail client would show by default.
fn (Client) select_mailbox #
fn (mut c Client) select_mailbox(name string) !Mailbox
select_mailbox opens a mailbox for reading and writing, and returns its state. Later fetches, searches and stores act on it.
fn (Client) examine_mailbox #
fn (mut c Client) examine_mailbox(name string) !Mailbox
examine_mailbox opens a mailbox read-only. It behaves like select_mailbox, except that nothing the session does marks messages as seen or otherwise alters the mailbox.
fn (Client) status #
fn (mut c Client) status(name string, items []string) !MailboxStatus
status reports on a mailbox without selecting it, which is how a client polls for new mail while working in another mailbox.
items names what to ask for: MESSAGES, RECENT, UIDNEXT, UIDVALIDITY and UNSEEN.
fn (Client) create_mailbox #
fn (mut c Client) create_mailbox(name string) !
create_mailbox creates a mailbox.
fn (Client) delete_mailbox #
fn (mut c Client) delete_mailbox(name string) !
delete_mailbox deletes a mailbox and everything in it.
fn (Client) subscribe #
fn (mut c Client) subscribe(name string) !
subscribe adds a mailbox to the set a client shows by default.
fn (Client) unsubscribe #
fn (mut c Client) unsubscribe(name string) !
unsubscribe removes it from that set, without touching the mailbox itself.
fn (Client) rename_mailbox #
fn (mut c Client) rename_mailbox(from string, to string) !
rename_mailbox renames a mailbox, along with everything below it in the hierarchy.
fn (Client) append #
fn (mut c Client) append(mailbox string, flags []string, stamp time.Time, body []u8) !
append adds a message to a mailbox, which is how a sent message is filed into a Sent folder or a draft is saved.
flags are set on the new message, commonly \Seen for a message the user has already read. stamp becomes its internal date; pass the zero time to let the server use the moment of delivery.
fn (Client) search #
fn (mut c Client) search(criteria string) !SeqSet
search returns the sequence numbers of the messages in the selected mailbox matching criteria, which is an IMAP search key such as UNSEEN, FROM "someone@example.com" or SINCE 1-Jan-2026.
fn (Client) uid_search #
fn (mut c Client) uid_search(criteria string) !SeqSet
uid_search behaves like search but returns UIDs, which stay valid across sessions where sequence numbers do not.
fn (Client) fetch #
fn (mut c Client) fetch(set SeqSet, items string) ![]Message
fetch retrieves items for each message in set.
items is an IMAP fetch specification. BODY.PEEK[] takes the whole message without marking it read, BODY.PEEK[HEADER] takes just the headers, and (UID FLAGS ENVELOPE) takes metadata alone.
fn (Client) uid_fetch #
fn (mut c Client) uid_fetch(set SeqSet, items string) ![]Message
uid_fetch behaves like fetch but addresses messages by UID.
fn (Client) store #
fn (mut c Client) store(set SeqSet, action string, flags []string) ![]Message
store changes the flags of the messages in set, and returns what the server reports the new flags to be.
action is +FLAGS to add, -FLAGS to remove, or FLAGS to replace. Appending .SILENT tells the server not to echo the result back, in which case the returned list is empty.
fn (Client) uid_store #
fn (mut c Client) uid_store(set SeqSet, action string, flags []string) ![]Message
uid_store behaves like store but addresses messages by UID.
fn (Client) mark_seen #
fn (mut c Client) mark_seen(set SeqSet) !
mark_seen flags messages as read.
fn (Client) mark_deleted #
fn (mut c Client) mark_deleted(set SeqSet) !
mark_deleted flags messages for deletion. They go on being readable until expunge runs.
fn (Client) copy #
fn (mut c Client) copy(set SeqSet, dest string) !
copy copies messages into another mailbox, leaving the originals in place.
fn (Client) uid_copy #
fn (mut c Client) uid_copy(set SeqSet, dest string) !
uid_copy behaves like copy but addresses messages by UID.
fn (Client) move #
fn (mut c Client) move(set SeqSet, dest string) !
move moves messages into another mailbox in one step (RFC 6851), which a copy followed by a delete cannot do without a window where the message exists twice or not at all.
It needs the MOVE capability; check supports('MOVE') first when the server is not known.
fn (Client) uid_move #
fn (mut c Client) uid_move(set SeqSet, dest string) !
uid_move behaves like move but addresses messages by UID.
fn (Client) expunge #
fn (mut c Client) expunge() ![]u32
expunge permanently removes every message flagged \Deleted from the selected mailbox, and returns the sequence numbers the server reported as removed.
The numbers are reported one at a time, each already renumbered by the removals before it, which is why the same number can appear twice.
fn (Client) check #
fn (mut c Client) check() !
check asks the server to bring its own housekeeping up to date. It is not a NOOP: it may take real time, and it is the right thing to call before a long idle period.
fn (Client) close_mailbox #
fn (mut c Client) close_mailbox() !
close_mailbox leaves the selected mailbox, silently expunging any message flagged \Deleted on the way out.
fn (Client) unselect #
fn (mut c Client) unselect() !
unselect leaves the selected mailbox without expunging anything (RFC 3691), which is what a client wants when the user simply navigated away.
It needs the UNSELECT capability.
fn (Client) logout #
fn (mut c Client) logout() !
logout ends the session politely, giving the server the chance to close the connection itself.
fn (Client) close #
fn (mut c Client) close() !
close logs out and tears down the connection. It is safe to call on a session that is already closed.
fn (Client) command #
fn (mut c Client) command(cmd string) !string
command sends one command with a fresh tag and returns the completion text, so that a caller can reach an extension this module does not wrap. The tag is added here; pass the command without one.
struct Config #
struct Config {
pub:
server string
port int
username string
password string
ssl bool
starttls bool
timeout time.Duration
validate bool = true
verify string
cert string
cert_key string
in_memory_verification bool
allow_insecure_auth bool
auth_method AuthMethod
}
Config holds the settings used to open a session.
Leave port unset to take 993 when ssl is true and 143 otherwise. Set ssl for a connection encrypted from the first byte, or starttls to upgrade a plain connection once it is open. The two are mutually exclusive. TLS certificates are validated by default. A TLS connection with validation enabled requires verify to name a PEM CA bundle; set in_memory_verification when it contains the PEM data itself. cert and cert_key configure a client certificate when the server requires one. Credentials are refused on an unencrypted connection unless allow_insecure_auth is explicitly set.
struct Envelope #
struct Envelope {
pub:
date string
subject string
from []Address
sender []Address
reply_to []Address
to []Address
cc []Address
bcc []Address
in_reply_to string
message_id string
}
Envelope is the parsed header of a message, which a server can produce without the client fetching and parsing the header itself.
struct Mailbox #
struct Mailbox {
pub:
name string
// exists is the number of messages in the mailbox.
exists u32
// recent is how many of them arrived since the last session looked.
recent u32
// unseen is the sequence number of the first unread message, zero when the
// server did not report one.
unseen u32
// flags are the flags this mailbox can hold.
flags []string
// permanent_flags are the ones a STORE can make stick. A `\*` among them
// means the mailbox accepts new keywords.
permanent_flags []string
// uid_validity changes when the server can no longer promise that UIDs
// from an earlier session still name the same messages.
uid_validity u32
// uid_next is the UID the next arriving message is expected to take.
uid_next u32
// read_only is true for a mailbox opened with `examine`, and also for one
// opened with `select` that the server would only give out read-only.
read_only bool
}
Mailbox is the state of a mailbox at the moment it was selected.
struct MailboxInfo #
struct MailboxInfo {
pub:
name string
// delimiter separates the levels of a hierarchical name, and is empty when
// the server presents a flat namespace.
delimiter string
// attributes are the server's notes about the mailbox, such as `\Noselect`
// for a name that only exists to hold children.
attributes []string
}
MailboxInfo is one entry of a mailbox listing.
struct MailboxStatus #
struct MailboxStatus {
pub:
name string
messages u32
recent u32
uid_next u32
uid_validity u32
unseen u32
}
MailboxStatus is what STATUS reports about a mailbox without selecting it.
struct Message #
struct Message {
pub:
seq u32
uid u32
flags []string
// size is what RFC822.SIZE reported.
size u32
// internal_date is when the server took delivery, which is not the Date
// header and does not change when a message is copied.
internal_date time.Time
envelope ?Envelope
structure ?BodyStructure
// sections holds every body section the fetch asked for, keyed by the
// specification the server echoed back: `BODY[]` for the whole message,
// `BODY[HEADER]` for the header block, `BODY[1.2]` for one MIME part.
sections map[string]string
}
Message is one fetched message, holding whatever the fetch asked for.
seq is its sequence number in the selected mailbox and is always set. The rest is filled in only when the fetch requested it.
fn (Message) body #
fn (m &Message) body() string
body returns the whole message when it was fetched, and the lone section when exactly one was, which is what a fetch of a single section wants.
A fetch of several sections has no one answer, so it gives back nothing; read sections directly in that case.
struct SeqRange #
struct SeqRange {
pub:
start u32
stop u32
}
SeqRange is one number or one range of them. A single number has start equal to stop. A stop of zero means *, so {5, 0} reads 5:* and {0, 0} reads *.
fn (SeqRange) str #
fn (r SeqRange) str() string
str renders one range, collapsing n:n back to n.
struct SeqSet #
struct SeqSet {
pub mut:
ranges []SeqRange
}
SeqSet is a set of message numbers, held as ranges that are kept sorted and merged so that the rendered form stays short.
fn (SeqSet) add #
fn (mut s SeqSet) add(n u32)
add inserts one number.
fn (SeqSet) add_range #
fn (mut s SeqSet) add_range(start u32, stop u32)
add_range inserts a range, in either order.
fn (SeqSet) len #
fn (s &SeqSet) len() int
len is the number of ranges the set is stored as, not the number of messages it names.
fn (SeqSet) is_empty #
fn (s &SeqSet) is_empty() bool
is_empty reports whether the set names nothing, in which case no command should be sent at all.
fn (SeqSet) contains #
fn (s &SeqSet) contains(n u32) bool
contains reports whether n is named by the set. It answers for a concrete number; * is not resolvable without knowing the mailbox.
fn (SeqSet) numbers #
fn (s &SeqSet) numbers() ![]u32
numbers expands the set. It fails on a set holding *, whose end is only known to the server.
fn (SeqSet) str #
fn (s SeqSet) str() string
str renders the set as a server reads it.
- README
- Constants
- fn new_client
- fn parse_seq_set
- fn seq_all
- fn seq_range
- fn seq_set
- fn utf7_decode
- fn utf7_encode
- fn AuthMethod.from
- fn Status.from
- fn TokenKind.from
- enum AuthMethod
- enum Status
- struct Address
- struct BodyStructure
- struct Client
- fn connect
- fn login
- fn login_plain
- fn capability
- fn supports
- fn noop
- fn list_mailboxes
- fn list_subscribed
- fn select_mailbox
- fn examine_mailbox
- fn status
- fn create_mailbox
- fn delete_mailbox
- fn subscribe
- fn unsubscribe
- fn rename_mailbox
- fn append
- fn search
- fn uid_search
- fn fetch
- fn uid_fetch
- fn store
- fn uid_store
- fn mark_seen
- fn mark_deleted
- fn copy
- fn uid_copy
- fn move
- fn uid_move
- fn expunge
- fn check
- fn close_mailbox
- fn unselect
- fn logout
- fn close
- fn command
- struct Config
- struct Envelope
- struct Mailbox
- struct MailboxInfo
- struct MailboxStatus
- struct Message
- struct SeqRange
- struct SeqSet