### Start an IMAP Server with imapserver.New Source: https://context7.com/emersion/go-imap/llms.txt Initialize an IMAP server using `imapserver.New` with specified `Options`, including `NewSession` for handling new client sessions. The server can then be started using `Server.ListenAndServeTLS`. ```go import ( "crypto/tls" "github.com/emersion/go-imap/v2" "github.com/emersion/go-imap/v2/imapserver" ) tlsCert, _ := tls.LoadX509KeyPair("cert.pem", "key.pem") srv := imapserver.New(&imapserver.Options{ NewSession: func(conn *imapserver.Conn) (imapserver.Session, *imapserver.GreetingData, error) { return myBackend.NewSession(), &imapserver.GreetingData{}, nil }, Caps: imap.CapSet{ imap.CapIMAP4rev2: {}, }, TLSConfig: &tls.Config{Certificates: []tls.Certificate{tlsCert}}, InsecureAuth: false, }) log.Printf("IMAP server listening on :993") if err := srv.ListenAndServeTLS(":993"); err != nil { log.Fatalf("server error: %v", err) } ``` -------------------------------- ### imapserver.New / Server.ListenAndServeTLS Source: https://context7.com/emersion/go-imap/llms.txt Initializes and starts an IMAP server. `imapserver.New` creates a `*Server` instance with specified options, and `ListenAndServeTLS` begins accepting incoming TLS connections. ```APIDOC ## imapserver.New / Server.ListenAndServeTLS — Start an IMAP server Creates a `*Server` with the provided `Options` and starts accepting connections. The only required option field is `NewSession`. ### Example Usage: ```go import ( "crypto/tls" "github.com/emersion/go-imap/v2" "github.com/emersion/go-imap/v2/imapserver" ) tlsCert, _ := tls.LoadX509KeyPair("cert.pem", "key.pem") srv := imapserver.New(&imapserver.Options{ NewSession: func(conn *imapserver.Conn) (imapserver.Session, *imapserver.GreetingData, error) { return myBackend.NewSession(), &imapserver.GreetingData{}, nil }, Caps: imap.CapSet{ imap.CapIMAP4rev2: {}, }, TLSConfig: &tls.Config{Certificates: []tls.Certificate{tlsCert}}, InsecureAuth: false, }) log.Printf("IMAP server listening on :993") if err := srv.ListenAndServeTLS(":993"); err != nil { log.Fatalf("server error: %v", err) } ``` ``` -------------------------------- ### Enable IDLE Extension on Server Source: https://github.com/emersion/go-imap/wiki/Using-extensions Enable the IDLE extension for an IMAP server instance. This is typically done during server setup or configuration. ```go s.Enable(idle.NewExtension()) ``` -------------------------------- ### Get Mailbox Status with Client.Status Source: https://context7.com/emersion/go-imap/llms.txt Retrieves mailbox status without changing the selected mailbox. Use `StatusOptions` to specify which status items to fetch. ```go opts := &imap.StatusOptions{NumMessages: true, NumUnseen: true, Size: true} data, err := c.Status("INBOX", opts).Wait() if err != nil { log.Fatalf("STATUS failed: %v", err) } log.Printf("INBOX: %d messages (%d unseen), total size %d bytes", *data.NumMessages, *data.NumUnseen, *data.Size) ``` -------------------------------- ### Monitor Connection Lifecycle with Client.Closed Source: https://context7.com/emersion/go-imap/llms.txt The `Client.Closed` channel is closed when the IMAP connection is torn down. Goroutines can use this channel to react to disconnections, for example, by attempting to reconnect. ```go go func() { <-c.Closed() log.Println("IMAP connection closed; attempting reconnect…") }() ``` -------------------------------- ### Connect using STARTTLS Source: https://context7.com/emersion/go-imap/llms.txt Use `DialStartTLS` to connect on the plain-text port and then upgrade the connection to TLS. This method refuses PREAUTH on unencrypted connections. ```go c, err := imapclient.DialStartTLS("imap.example.org:143", nil) if err != nil { log.Fatalf("STARTTLS dial failed: %v", err) } defer c.Close() ``` -------------------------------- ### Graceful and Immediate Connection Shutdown Source: https://context7.com/emersion/go-imap/llms.txt Use `Client.Logout` to send the `LOGOUT` command for a graceful shutdown. For an immediate termination, use `Client.Close`. ```go if err := c.Logout().Wait(); err != nil { log.Printf("LOGOUT error: %v", err) } // or for immediate close: c.Close() ``` -------------------------------- ### Query server capabilities Source: https://context7.com/emersion/go-imap/llms.txt The `Caps` method returns the server's `imap.CapSet`. Capabilities are fetched automatically on the first call if not already advertised. Use `CapSet.Has` to check for specific capabilities. ```go caps := c.Caps() log.Printf("IMAP4rev2: %v", caps.Has(imap.CapIMAP4rev2)) log.Printf("MOVE: %v", caps.Has(imap.CapMove)) log.Printf("IDLE: %v", caps.Has(imap.CapIdle)) log.Printf("AUTH mechanisms: %v", caps.AuthMechanisms()) // Example output: // IMAP4rev2: true // MOVE: true // IDLE: true // AUTH mechanisms: [PLAIN XOAUTH2] ``` -------------------------------- ### Authenticate with username and password Source: https://context7.com/emersion/go-imap/llms.txt The `Login` method sends the `LOGIN` command. It returns a `*Command` object; call `.Wait()` on this object to block until the server responds. ```go if err := c.Login("alice", "s3cr3t").Wait(); err != nil { log.Fatalf("login failed: %v", err) } ``` -------------------------------- ### Wrap an existing net.Conn Source: https://context7.com/emersion/go-imap/llms.txt Use `imapclient.New` to create a client from an existing `net.Conn`. This is useful for testing with mock connections or custom transports. It does not perform any I/O itself. ```go import "net" conn, err := net.Dial("tcp", "imap.example.org:143") if err != nil { log.Fatal(err) } c := imapclient.New(conn, &imapclient.Options{ DebugWriter: os.Stderr, // log raw protocol bytes }) if err := c.WaitGreeting(); err != nil { log.Fatalf("greeting failed: %v", err) } ``` -------------------------------- ### Client.Login Source: https://context7.com/emersion/go-imap/llms.txt Sends the LOGIN command. Returns a *Command; call .Wait() to block until the server responds. ```APIDOC ## Client.Login ### Description Sends the `LOGIN` command. Returns a `*Command`; call `.Wait()` to block until the server responds. ### Method ```go if err := c.Login("alice", "s3cr3t").Wait(); err != nil { log.Fatalf("login failed: %v", err) } ``` ``` -------------------------------- ### Open Mailbox with Client.Select Source: https://context7.com/emersion/go-imap/llms.txt Opens a mailbox for read-write or read-only access. Use `SelectOptions.ReadOnly` for read-only access. The `.Wait()` method returns `*imap.SelectData`. ```go data, err := c.Select("INBOX", nil).Wait() if err != nil { log.Fatalf("SELECT failed: %v", err) } log.Printf("INBOX: %d messages, UIDNext=%d, UIDValidity=%d", data.NumMessages, data.UIDNext, data.UIDValidity) ``` ```go data, err = c.Select("INBOX", &imap.SelectOptions{ ReadOnly: true, CondStore: true, }).Wait() ``` -------------------------------- ### Client.Select Source: https://context7.com/emersion/go-imap/llms.txt Opens a mailbox for reading and writing, or read-only using SelectOptions.Wait() yields SelectData. ```APIDOC ## Client.Select — Open a mailbox Sends `SELECT` (read-write) or `EXAMINE` (read-only via `SelectOptions.ReadOnly`). Returns a `*SelectCommand` whose `.Wait()` yields `*imap.SelectData`. ### Method ```go c.Select(mailbox string, opts *SelectOptions) *SelectCommand ``` ### Parameters #### Mailbox - **mailbox** (string) - The name of the mailbox to select. #### Options - **opts** (*SelectOptions) - Optional settings for the SELECT/EXAMINE command. Can be nil. - **ReadOnly** (bool) - If true, opens the mailbox in read-only mode (EXAMINE). - **CondStore** (bool) - If true, enables the CONDSTORE extension. ### Request Example ```go data, err := c.Select("INBOX", nil).Wait() // Read-only with CONDSTORE data, err = c.Select("INBOX", &imap.SelectOptions{ ReadOnly: true, CondStore: true, }).Wait() ``` ### Response #### Success Response - **SelectData** (*imap.SelectData) - Contains information about the selected mailbox. - **NumMessages** (int64) - The number of messages in the mailbox. - **UIDNext** (uint32) - The next available UID for new messages. - **UIDValidity** (uint32) - The validity value for UIDs in this mailbox. ``` -------------------------------- ### Handle Push Notifications with Client.Idle Source: https://context7.com/emersion/go-imap/llms.txt Implement `Client.Idle` to receive push notifications from the server. Configure `UnilateralDataHandler` to process events like expunges and mailbox updates. The IDLE command is automatically restarted every 28 minutes. ```go options := &imapclient.Options{ UnilateralDataHandler: &imapclient.UnilateralDataHandler{ Expunge: func(seqNum uint32) { log.Printf("message %d expunged", sequm) }, Mailbox: func(data *imapclient.UnilateralDataMailbox) { if data.NumMessages != nil { log.Printf("mailbox now has %d messages", *data.NumMessages) } }, }, } c, _ := imapclient.DialTLS("imap.example.org:993", options) c.Login("alice", "s3cr3t").Wait() c.Select("INBOX", nil).Wait() idleCmd, err := c.Idle() if err != nil { log.Fatalf("IDLE failed: %v", err) } // Stop after 5 minutes time.AfterFunc(5*time.Minute, func() { idleCmd.Close() }) if err := idleCmd.Wait(); err != nil { log.Fatalf("IDLE ended with error: %v", err) } ``` -------------------------------- ### Implement Custom IMAP Session Backend Source: https://context7.com/emersion/go-imap/llms.txt Implement the `Session` interface to provide custom backend storage logic for an IMAP server. Optional extension interfaces can be implemented to enable additional capabilities. ```go type MySession struct { user *MyUser } func (s *MySession) Close() error { return nil } func (s *MySession) Login(username, password string) error { u, ok := db.LookupUser(username, password) if !ok { return imapserver.ErrAuthFailed } s.user = u return nil } func (s *MySession) Select(mailbox string, opts *imap.SelectOptions) (*imap.SelectData, error) { mbox, err := s.user.Mailbox(mailbox) if err != nil { return nil, err } return &imap.SelectData{ NumMessages: mbox.Count(), UIDValidity: mbox.UIDValidity(), UIDNext: mbox.UIDNext(), }, nil } func (s *MySession) Fetch(w *imapserver.FetchWriter, numSet imap.NumSet, opts *imap.FetchOptions) error { return s.user.FetchMessages(w, numSet, opts) } // … implement remaining Session methods: Create, Delete, Rename, Subscribe, // Unsubscribe, List, Status, Append, Poll, Idle, Unselect, Expunge, Search, // Store, Copy ``` -------------------------------- ### In-Memory IMAP Server for Testing Source: https://context7.com/emersion/go-imap/llms.txt Use `imapmemserver` to create a complete in-memory `Session` implementation for unit tests or demos. This allows testing client interactions without a live IMAP server. ```go import ( "github.com/emersion/go-imap/v2" "github.com/emersion/go-imap/v2/imapserver" "github.com/emersion/go-imap/v2/imapserver/imapmemserver" "github.com/emersion/go-imap/v2/imapclient" ) // Build in-memory server memSrv := imapmemserver.New() u := imapmemserver.NewUser("alice", "password") u.CreateMailbox("INBOX") memSrv.AddUser(u) srv := imapserver.New(&imapserver.Options{ NewSession: func(c *imapserver.Conn) (imapserver.Session, *imapserver.GreetingData, error) { return memSrv.NewSession(), &imapserver.GreetingData{}, nil }, Caps: imap.CapSet{imap.CapIMAP4rev2: {}}, InsecureAuth: true, }) ln, _ := net.Listen("tcp", "127.0.0.1:0") go srv.Serve(ln) // Connect client to the test server c, _ := imapclient.DialInsecure(ln.Addr().String(), nil) c.Login("alice", "password").Wait() data, _ := c.Select("INBOX", nil).Wait() log.Printf("INBOX has %d messages", data.NumMessages) srv.Close() ``` -------------------------------- ### Client.Caps Source: https://context7.com/emersion/go-imap/llms.txt Returns the server's imap.CapSet. Fetches capabilities automatically on first call if not yet advertised by the server. Use CapSet.Has to check individual capabilities (IMAP4rev2 implied-cap logic is applied automatically). ```APIDOC ## Client.Caps ### Description Returns the server's `imap.CapSet`. Fetches capabilities automatically on first call if not yet advertised by the server. Use `CapSet.Has` to check individual capabilities (IMAP4rev2 implied-cap logic is applied automatically). ### Method ```go caps := c.Caps() log.Printf("IMAP4rev2: %v", caps.Has(imap.CapIMAP4rev2)) log.Printf("MOVE: %v", caps.Has(imap.CapMove)) log.Printf("IDLE: %v", caps.Has(imap.CapIdle)) log.Printf("AUTH mechanisms: %v", caps.AuthMechanisms()) // Example output: // IMAP4rev2: true // MOVE: true // IDLE: true // AUTH mechanisms: [PLAIN XOAUTH2] ``` ``` -------------------------------- ### imapclient.New Source: https://context7.com/emersion/go-imap/llms.txt Creates a client from any net.Conn (useful for test doubles or custom transports). Does not perform I/O. ```APIDOC ## imapclient.New ### Description Creates a client from any `net.Conn` (useful for test doubles or custom transports). Does not perform I/O. ### Method ```go import "net" conn, err := net.Dial("tcp", "imap.example.org:143") if err != nil { log.Fatal(err) } c := imapclient.New(conn, &imapclient.Options{ DebugWriter: os.Stderr, // log raw protocol bytes }) if err := c.WaitGreeting(); err != nil { log.Fatalf("greeting failed: %v", err) } ``` ``` -------------------------------- ### imapclient.DialStartTLS Source: https://context7.com/emersion/go-imap/llms.txt Connects on the plain-text port, upgrades to TLS via STARTTLS, and refuses PREAUTH on unencrypted connections. ```APIDOC ## imapclient.DialStartTLS ### Description Connects on the plain-text port, upgrades to TLS via STARTTLS, and refuses PREAUTH on unencrypted connections. ### Method ```go c, err := imapclient.DialStartTLS("imap.example.org:143", nil) if err != nil { log.Fatalf("STARTTLS dial failed: %v", err) } defer c.Close() ``` ``` -------------------------------- ### Upload Message with Client.Append Source: https://context7.com/emersion/go-imap/llms.txt Uploads a message to a mailbox using the `APPEND` command. Write message bytes to the returned `*AppendCommand` and then call `Close()`. The `AppendOptions` can specify flags and the message date. ```go raw := []byte("From: alice@example.org\r\nTo: bob@example.org\r\nSubject: Test\r\n\r\nHello!\r\n") appendCmd := c.Append("Sent", int64(len(raw)), &imap.AppendOptions{ Flags: []imap.Flag{imap.FlagSeen}, Time: time.Now(), }) if _, err := appendCmd.Write(raw); err != nil { log.Fatalf("write failed: %v", err) } if err := appendCmd.Close(); err != nil { log.Fatalf("close failed: %v", err) } data, err := appendCmd.Wait() if err != nil { log.Fatalf("APPEND failed: %v", err) } log.Printf("appended UID=%d (validity=%d)", data.UID, data.UIDValidity) ``` -------------------------------- ### Command Pipelining with go-imap Client Source: https://context7.com/emersion/go-imap/llms.txt Utilize command pipelining by dispatching multiple commands without waiting for individual responses. Chain `.Wait()` calls to collect results, improving efficiency by exploiting RFC 9051 §5.5. ```go // Send LOGIN, SELECT, and FETCH without waiting between sends loginCmd := c.Login("alice", "s3cr3t") selectCmd := c.Select("INBOX", nil) fetchCmd := c.Fetch(imap.UIDSetNum(42), &imap.FetchOptions{Envelope: true}) if err := loginCmd.Wait(); err != nil { log.Fatalf("login: %v", err) } if _, err := selectCmd.Wait(); err != nil { log.Fatalf("select: %v", err) } msgs, err := fetchCmd.Collect() if err != nil { log.Fatalf("fetch: %v", err) } log.Printf("Subject: %v", msgs[0].Envelope.Subject) ``` -------------------------------- ### Client.Authenticate Source: https://context7.com/emersion/go-imap/llms.txt Sends AUTHENTICATE and runs the full SASL exchange synchronously. Supports any sasl.Client (PLAIN, XOAUTH2, OAUTHBEARER, etc.) via go-sasl. ```APIDOC ## Client.Authenticate ### Description Sends `AUTHENTICATE` and runs the full SASL exchange synchronously. Supports any `sasl.Client` (PLAIN, XOAUTH2, OAUTHBEARER, etc.) via [go-sasl](https://github.com/emersion/go-sasl). ### Method ```go import "github.com/emersion/go-sasl" import "github.com/emersion/go-imap/v2" // Check capability before authenticating if !c.Caps().Has(imap.AuthCap(sasl.OAuthBearer)) { log.Fatal("OAUTHBEARER not supported") } saslClient := sasl.NewOAuthBearerClient(&sasl.OAuthBearerOptions{ Username: "alice@example.org", Token: "ya29.access-token", }) if err := c.Authenticate(saslClient); err != nil { log.Fatalf("authentication failed: %v", err) } ``` ``` -------------------------------- ### Create Custom Client with IDLE Extension Source: https://github.com/emersion/go-imap/wiki/Using-extensions Define a custom IMAP client struct that embeds the base client and the IDLE extension client. This allows for a unified interface to access both standard and extension functionalities. ```go type IMAPClient struct { *client.Client *idle.IdleClient } func NewIMAPClient(c *imap.Client) *IMAPClient { return &IMAPClient{ c, idle.NewClient(c), } } ``` -------------------------------- ### Client.Idle Source: https://context7.com/emersion/go-imap/llms.txt Enables push notifications from the server. It sends the `IDLE` command and automatically restarts it every 28 minutes. Server-sent data like new messages or expunges are handled via the `UnilateralDataHandler`. ```APIDOC ## Client.Idle — Push notifications Sends `IDLE`, restarting it automatically every 28 minutes. Unilateral server data (new messages, expunges) is delivered via the `UnilateralDataHandler` set in `Options`. ### Example Usage: ```go options := &imapclient.Options{ UnilateralDataHandler: &imapclient.UnilateralDataHandler{ Expunge: func(seqNum uint32) { log.Printf("message %d expunged", seqNum) }, Mailbox: func(data *imapclient.UnilateralDataMailbox) { if data.NumMessages != nil { log.Printf("mailbox now has %d messages", *data.NumMessages) } }, }, } c, _ := imapclient.DialTLS("imap.example.org:993", options) c.Login("alice", "s3cr3t").Wait() c.Select("INBOX", nil).Wait() idleCmd, err := c.Idle() if err != nil { log.Fatalf("IDLE failed: %v", err) } // Stop after 5 minutes time.AfterFunc(5*time.Minute, func() { idleCmd.Close() }) if err := idleCmd.Wait(); err != nil { log.Fatalf("IDLE ended with error: %v", err) } ``` ``` -------------------------------- ### List mailboxes Source: https://context7.com/emersion/go-imap/llms.txt The `List` method sends a `LIST` command. It returns a `*ListCommand` that can be iterated using `Next()` or collected into a slice with `Collect()`. Extended options like `RETURN STATUS` require IMAP4rev2 or LIST-EXTENDED. ```go // Simple listing mailboxes, err := c.List("", "%", nil).Collect() if err != nil { log.Fatalf("LIST failed: %v", err) } for _, mbox := range mailboxes { log.Printf(" %v (attrs: %v)", mbox.Mailbox, mbox.Attrs) } // Streaming with per-mailbox STATUS (requires LIST-STATUS or IMAP4rev2) listCmd := c.List("", "%", &imap.ListOptions{ ReturnStatus: &imap.StatusOptions{NumMessages: true, NumUnseen: true}, }) defer listCmd.Close() for { mbox := listCmd.Next() if mbox == nil { break } log.Printf("%q: %d messages, %d unseen", mbox.Mailbox, *mbox.Status.NumMessages, *mbox.Status.NumUnseen) } if err := listCmd.Close(); err != nil { log.Fatalf("LIST error: %v", err) } ``` -------------------------------- ### Copy or Move Messages with go-imap Client Source: https://context7.com/emersion/go-imap/llms.txt Use `Client.Copy` to copy messages and `Client.Move` to move them. `Move` automatically falls back to `COPY + STORE + EXPUNGE` if the `MOVE` command is not supported. ```go // Copy UIDs 10–20 to "Archive" copyData, err := c.Copy(imap.UIDSetRange(10, 20), "Archive").Wait() if err != nil { log.Fatalf("COPY failed: %v", err) } log.Printf("copied to UIDs %v (validity %d)", copyData.DestUIDs, copyData.UIDValidity) // Move message 5 to "Trash" (auto-fallback if MOVE not supported) if _, err := c.Move(imap.SeqSetNum(5), "Trash").Wait(); err != nil { log.Fatalf("MOVE failed: %v", err) } ``` -------------------------------- ### Fetch Message Data with Client.Fetch Source: https://context7.com/emersion/go-imap/llms.txt Retrieves message data using `FETCH` or `UID FETCH`. Returns a streaming `*FetchCommand`. Use `.Collect()` for in-memory results or `.Next()` for streaming large messages. Supports fetching envelopes, flags, and message bodies. ```go import "github.com/emersion/go-imap/v2" // Collect envelope + flags for messages 1–5 seqSet := imap.SeqSetRange(1, 5) messages, err := c.Fetch(seqSet, &imap.FetchOptions{ Envelope: true, Flags: true, }).Collect() if err != nil { log.Fatalf("FETCH failed: %v", err) } for _, msg := range messages { log.Printf("[%d] %q flags=%v", msg.SeqNum, msg.Envelope.Subject, msg.Flags) } ``` ```go // Stream the full body of message 1 (avoids buffering large literals) bodySection := &imap.FetchItemBodySection{} fetchCmd := c.Fetch(imap.SeqSetNum(1), &imap.FetchOptions{ UID: true, BodySection: []*imap.FetchItemBodySection{bodySection}, }) defer fetchCmd.Close() for { msg := fetchCmd.Next() if msg == nil { break } for { item := msg.Next() if item == nil { break } switch item := item.(type) { case imapclient.FetchItemDataUID: log.Printf("UID: %d", item.UID) case imapclient.FetchItemDataBodySection: // Parse with go-message mr, _ := mail.CreateReader(item.Literal) subject, _ := mr.Header.Text("Subject") log.Printf("Subject: %v", subject) } } } if err := fetchCmd.Close(); err != nil { log.Fatalf("FETCH stream error: %v", err) } ``` -------------------------------- ### Command Pipelining Source: https://context7.com/emersion/go-imap/llms.txt Allows sending multiple commands in a single network round-trip. Callers can chain `.Wait()` calls to collect results sequentially, improving efficiency by leveraging IMAP pipelining. ```APIDOC ## Command pipelining — Multiple commands in one round-trip Commands are dispatched without waiting for a response; callers chain `.Wait()` calls to collect results. This exploits IMAP pipelining per RFC 9051 §5.5. ### Example Usage: ```go // Send LOGIN, SELECT, and FETCH without waiting between sends loginCmd := c.Login("alice", "s3cr3t") selectCmd := c.Select("INBOX", nil) fetchCmd := c.Fetch(imap.UIDSetNum(42), &imap.FetchOptions{Envelope: true}) if err := loginCmd.Wait(); err != nil { log.Fatalf("login: %v", err) } if _, err := selectCmd.Wait(); err != nil { log.Fatalf("select: %v", err) } msgs, err := fetchCmd.Collect() if err != nil { log.Fatalf("fetch: %v", err) } log.Printf("Subject: %v", msgs[0].Envelope.Subject) ``` ``` -------------------------------- ### Client.List Source: https://context7.com/emersion/go-imap/llms.txt Sends a LIST command. Returns a *ListCommand which can be iterated with Next() or collected with Collect(). Extended options (RETURN STATUS, SELECT SUBSCRIBED, etc.) require IMAP4rev2 or LIST-EXTENDED. ```APIDOC ## Client.List ### Description Sends a `LIST` command. Returns a `*ListCommand` which can be iterated with `Next()` or collected with `Collect()`. Extended options (RETURN STATUS, SELECT SUBSCRIBED, etc.) require IMAP4rev2 or LIST-EXTENDED. ### Method ```go // Simple listing mailboxes, err := c.List("", "%", nil).Collect() if err != nil { log.Fatalf("LIST failed: %v", err) } for _, mbox := range mailboxes { log.Printf(" %v (attrs: %v)", mbox.Mailbox, mbox.Attrs) } // Streaming with per-mailbox STATUS (requires LIST-STATUS or IMAP4rev2) listCmd := c.List("", "%", &imap.ListOptions{ ReturnStatus: &imap.StatusOptions{NumMessages: true, NumUnseen: true}, }) defer listCmd.Close() for { mbox := listCmd.Next() if mbox == nil { break } log.Printf("%q: %d messages, %d unseen", mbox.Mailbox, *mbox.Status.NumMessages, *mbox.Status.NumUnseen) } if err := listCmd.Close(); err != nil { log.Fatalf("LIST error: %v", err) } ``` ``` -------------------------------- ### Client.Fetch Source: https://context7.com/emersion/go-imap/llms.txt Retrieves message data using FETCH or UID FETCH. Returns a streaming FetchCommand. ```APIDOC ## Client.Fetch — Retrieve message data Sends `FETCH` (or `UID FETCH` when a `imap.UIDSet` is passed). Returns a streaming `*FetchCommand`. Use `.Collect()` for in-memory results or `.Next()` for streaming large messages. ### Method ```go c.Fetch(set imap.SeqSet, opts *FetchOptions) *FetchCommand ``` ### Parameters #### Set - **set** (imap.SeqSet) - The sequence set of messages to fetch. #### Options - **opts** (*FetchOptions) - Specifies which data items to fetch. - **Envelope** (bool) - If true, fetches the message envelope. - **Flags** (bool) - If true, fetches the message flags. - **UID** (bool) - If true, fetches the message UID. - **BodySection** ([]*FetchItemBodySection) - Specifies body sections to fetch. ### Request Example ```go // Collect envelope + flags for messages 1–5 seqSet := imap.SeqSetRange(1, 5) messages, err := c.Fetch(seqSet, &imap.FetchOptions{ Envelope: true, Flags: true, }).Collect() // Stream the full body of message 1 bodySection := &imap.FetchItemBodySection{} fetchCmd := c.Fetch(imap.SeqSetNum(1), &imap.FetchOptions{ UID: true, BodySection: []*imap.FetchItemBodySection{bodySection}, }) ``` ### Response #### Success Response - **FetchCommand** (*FetchCommand) - A streaming command object. - **Collect()** ([]*Message) - Collects all fetched messages into memory. - **Next()** (*Message) - Retrieves the next fetched message. - **Close()** error - Closes the fetch command and releases resources. ``` -------------------------------- ### imapclient.DialTLS Source: https://context7.com/emersion/go-imap/llms.txt Opens a TLS connection to the given address (default port 993) and returns a ready-to-use *Client. Use DialStartTLS for STARTTLS or DialInsecure for unencrypted connections. ```APIDOC ## imapclient.DialTLS ### Description Opens a TLS connection to the given address (default port 993) and returns a ready-to-use `*Client`. Use `DialStartTLS` for STARTTLS or `DialInsecure` for unencrypted connections. ### Method ```go c, err := imapclient.DialTLS("imap.example.org:993", nil) if err != nil { log.Fatalf("dial failed: %v", err) } defer c.Close() ``` ``` -------------------------------- ### Fetch Whole Message Body - Go Source: https://github.com/emersion/go-imap/wiki/Fetching-messages Fetches the entire message body and parses its header and parts. Requires selecting a mailbox and specifying the message sequence set. Uses the go-message library for parsing. ```go package main import ( io "io/ioutil" "log" "github.com/emersion/go-imap" "github.com/emersion/go-imap/client" "github.com/emersion/go-message/mail" ) func main() { // Let's assume c is a client var c *client.Client // Select INBOX mbox, err := c.Select("INBOX", false) if err != nil { log.Fatal(err) } // Get the last message if mbox.Messages == 0 { log.Fatal("No message in mailbox") } seqSet := new(imap.SeqSet) seqSet.AddNum(mbox.Messages) // Get the whole message body var section imap.BodySectionName items := []imap.FetchItem{section.FetchItem()} messages := make(chan *imap.Message, 1) go func() { if err := c.Fetch(seqSet, items, messages); err != nil { log.Fatal(err) } }() msg := <-messages if msg == nil { log.Fatal("Server didn't returned message") } r := msg.GetBody(§ion) if r == nil { log.Fatal("Server didn't returned message body") } // Create a new mail reader mr, err := mail.CreateReader(r) if err != nil { log.Fatal(err) } // Print some info about the message header := mr.Header if date, err := header.Date(); err == nil { log.Println("Date:", date) } if from, err := header.AddressList("From"); err == nil { log.Println("From:", from) } if to, err := header.AddressList("To"); err == nil { log.Println("To:", to) } if subject, err := header.Subject(); err == nil { log.Println("Subject:", subject) } // Process each message's part for { p, err := mr.NextPart() if err == io.EOF { break } else if err != nil { log.Fatal(err) } switch h := p.Header.(type) { case *mail.InlineHeader: // This is the message's text (can be plain-text or HTML) b, _ := ioutil.ReadAll(p.Body) log.Println("Got text: %v", string(b)) case *mail.AttachmentHeader: // This is an attachment filename, _ := h.Filename() log.Println("Got attachment: %v", filename) } } } ``` -------------------------------- ### Specify Message Part Path - Go Source: https://github.com/emersion/go-imap/wiki/Fetching-messages Specifies a particular part of the message body to fetch using an array of integers for the path. ```go var section imap.BodySectionName section.Path = []int{1, 2, 3} ``` -------------------------------- ### Client.Store Source: https://context7.com/emersion/go-imap/llms.txt Modifies message flags using STORE or UID STORE. Returns a FetchCommand for updated flags unless Silent is set. ```APIDOC ## Client.Store — Modify message flags Sends `STORE` (or `UID STORE`). Returns a `*FetchCommand` that delivers updated flag values (unless `Silent` is set). ### Method ```go c.Store(set imap.SeqSet, flags *StoreFlags, opts *StoreOptions) *FetchCommand ``` ### Parameters #### Set - **set** (imap.SeqSet) - The sequence set of messages to modify. #### Flags - **flags** (*StoreFlags) - Specifies the flags to add, remove, or replace. - **Op** (imap.StoreFlagsOp) - The operation type (Add, Remove, Replace). - **Flags** ([]imap.Flag) - The flags to operate on. - **Silent** (bool) - If true, suppresses the response with updated flags. #### Options - **opts** (*StoreOptions) - Optional settings for the STORE command. - **UnchangedSince** (uint32) - Conditional store using a modification sequence number. ### Request Example ```go // Mark messages 1–3 as \Seen, silently storeFlags := &imap.StoreFlags{ Op: imap.StoreFlagsAdd, Flags: []imap.Flag{imap.FlagSeen}, Silent: true, } c.Store(imap.SeqSetRange(1, 3), storeFlags, nil).Close() // Remove \Flagged from UID 100, with CONDSTORE unchanged-since guard c.Store(imap.UIDSetNum(100), &imap.StoreFlags{ Op: imap.StoreFlagsDel, Flags: []imap.Flag{imap.FlagFlagged}, }, &imap.StoreOptions{UnchangedSince: 12345}).Close() ``` ``` -------------------------------- ### SASL authentication Source: https://context7.com/emersion/go-imap/llms.txt The `Authenticate` method performs a full SASL exchange synchronously. It supports various SASL mechanisms via `go-sasl`, such as PLAIN, XOAUTH2, and OAUTHBEARER. Ensure the server supports the desired mechanism before attempting authentication. ```go import "github.com/emersion/go-sasl" import "github.com/emersion/go-imap/v2" // Check capability before authenticating if !c.Caps().Has(imap.AuthCap(sasl.OAuthBearer)) { log.Fatal("OAUTHBEARER not supported") } saslClient := sasl.NewOAuthBearerClient(&sasl.OAuthBearerOptions{ Username: "alice@example.org", Token: "ya29.access-token", }) if err := c.Authenticate(saslClient); err != nil { log.Fatalf("authentication failed: %v", err) } ``` -------------------------------- ### Connect to IMAP server over TLS Source: https://context7.com/emersion/go-imap/llms.txt Use `DialTLS` to establish a secure TLS connection to the IMAP server. The default port is 993. Ensure the server address is correctly specified. ```go import ( "log" "github.com/emersion/go-imap/v2/imapclient" ) c, err := imapclient.DialTLS("imap.example.org:993", nil) if err != nil { log.Fatalf("dial failed: %v", err) } defer c.Close() // Output: connected, server greeting processed ``` -------------------------------- ### Search Messages with Client.Search / Client.UIDSearch Source: https://context7.com/emersion/go-imap/llms.txt Sends `SEARCH` or `UID SEARCH` commands to find messages based on specified criteria. The `.Wait()` method returns `*imap.SearchData` containing matching UIDs. ```go // Find UIDs of unseen messages with "invoice" in the subject, received this year criteria := &imap.SearchCriteria{ NotFlag: []imap.Flag{imap.FlagSeen}, Header: []imap.SearchCriteriaHeaderField{{Key: "Subject", Value: "invoice"}}, Since: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), } data, err := c.UIDSearch(criteria, nil).Wait() if err != nil { log.Fatalf("UID SEARCH failed: %v", err) } log.Printf("matching UIDs: %v", data.AllUIDs()) ``` -------------------------------- ### Client.Copy / Client.Move Source: https://context7.com/emersion/go-imap/llms.txt Copy or move messages between mailboxes. `Move` attempts to use the `MOVE` command and falls back to `COPY + STORE + EXPUNGE` if not supported. ```APIDOC ## Client.Copy / Client.Move — Copy or move messages `Copy` sends a `COPY` command; `Move` uses `MOVE` when available, falling back to `COPY + STORE + EXPUNGE` automatically. ### Example Usage: ```go // Copy UIDs 10–20 to "Archive" copyData, err := c.Copy(imap.UIDSetRange(10, 20), "Archive").Wait() if err != nil { log.Fatalf("COPY failed: %v", err) } log.Printf("copied to UIDs %v (validity %d)", copyData.DestUIDs, copyData.UIDValidity) // Move message 5 to "Trash" (auto-fallback if MOVE not supported) if _, err := c.Move(imap.SeqSetNum(5), "Trash").Wait(); err != nil { log.Fatalf("MOVE failed: %v", err) } ``` ``` -------------------------------- ### Server: Enable LOGIN Authentication Mechanism Source: https://github.com/emersion/go-imap/wiki/Using-authentication-mechanisms Enable the obsolete LOGIN authentication mechanism for your IMAP server, which is sometimes required by clients like Outlook. This function is called on the server instance to register the mechanism. ```go import ( "github.com/emersion/go-imap" "github.com/emersion/go-imap/server" "github.com/emersion/go-sasl" ) s.EnableAuth(sasl.Login, func(conn server.Conn) sasl.Server { return sasl.NewLoginServer(func(username, password string) error { user, err := conn.Server().Backend.Login(username, password) if err != nil { return err } ctx := conn.Context() ctx.State = imap.AuthenticatedState ctx.User = user return nil }) }) ``` -------------------------------- ### Client: Authenticate with OAUTHBEARER (XOAUTH2) Source: https://github.com/emersion/go-imap/wiki/Using-authentication-mechanisms Use this snippet to authenticate a client connection using the OAUTHBEARER mechanism, which is required by Gmail. Ensure the server supports OAUTHBEARER before attempting to authenticate. This involves obtaining an OAuth2 token. ```go import ( "github.com/emersion/go-imap" "github.com/emersion/go-imap/client" "github.com/emersion/go-oauthdialog" "github.com/emersion/go-sasl" "golang.org/x/oauth2" ) func authenticate(c *client.Client, cfg *oauth2.Config, username string) error { if !c.SupportAuth(sasl.OAuthBearer) { return errors.New("OAUTHBEARER not supported by the server") } // Ask for the user to login with his Google account code, err := oauthdialog.Open(cfg) if err != nil { return err } // Get a token from the returned code // This token can be saved in a secure store to be reused later token, err := cfg.Exchange(oauth2.NoContext, code) if err != nil { return err } // Login to the IMAP server with XOAUTH2 saslClient := sasl.NewOAuthBearerClient(&sasl.OAuthBearerOptions{ Username: username, Token: token, }) return c.Authenticate(saslClient) } ``` -------------------------------- ### Client.Append Source: https://context7.com/emersion/go-imap/llms.txt Uploads a message to a mailbox. Write message bytes to the returned AppendCommand, then call Close(). Wait() yields AppendData. ```APIDOC ## Client.Append — Upload a message to a mailbox Sends the `APPEND` command. The caller writes message bytes to the returned `*AppendCommand` then calls `Close()`. ### Method ```go c.Append(mailbox string, size int64, opts *AppendOptions) *AppendCommand ``` ### Parameters #### Mailbox - **mailbox** (string) - The name of the mailbox to append the message to. #### Size - **size** (int64) - The size of the message in octets. #### Options - **opts** (*AppendOptions) - Optional settings for the APPEND command. - **Flags** ([]imap.Flag) - Flags to set on the appended message. - **Time** (time.Time) - The internal date to set for the message. ### Request Example ```go raw := []byte("From: alice@example.org\r\nTo: bob@example.org\r\nSubject: Test\r\n\r\nHello!\r\n") appendCmd := c.Append("Sent", int64(len(raw)), &imap.AppendOptions{ Flags: []imap.Flag{imap.FlagSeen}, Time: time.Now(), }) appendCmd.Write(raw) appendCmd.Close() data, err := appendCmd.Wait() ``` ### Response #### Success Response - **AppendData** (*AppendData) - Contains information about the appended message. - **UID** (uint32) - The UID of the appended message. - **UIDValidity** (uint32) - The UIDValidity of the mailbox. ``` -------------------------------- ### Client.Search / Client.UIDSearch Source: https://context7.com/emersion/go-imap/llms.txt Searches messages based on criteria. Wait() yields SearchData. ```APIDOC ## Client.Search / Client.UIDSearch — Search messages Sends `SEARCH` or `UID SEARCH`. Returns a `*SearchCommand` whose `.Wait()` yields `*imap.SearchData`. ### Method ```go c.Search(criteria *SearchCriteria, opts *SearchOptions) *SearchCommand c.UIDSearch(criteria *SearchCriteria, opts *SearchOptions) *SearchCommand ``` ### Parameters #### Criteria - **criteria** (*SearchCriteria) - The search criteria. - **NotFlag** ([]imap.Flag) - Messages that do not have these flags. - **Header** ([]SearchCriteriaHeaderField) - Search based on header fields. - **Key** (string) - The header field name (e.g., "Subject"). - **Value** (string) - The value to search for. - **Since** (time.Time) - Messages received on or after this date. #### Options - **opts** (*SearchOptions) - Optional settings for the search command (e.g., SORT, CHARSET). ### Request Example ```go criteria := &imap.SearchCriteria{ NotFlag: []imap.Flag{imap.FlagSeen}, Header: []imap.SearchCriteriaHeaderField{{Key: "Subject", Value: "invoice"}}, Since: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), } data, err := c.UIDSearch(criteria, nil).Wait() ``` ### Response #### Success Response - **SearchData** (*imap.SearchData) - Contains the UIDs of matching messages. - **AllUIDs()** ([]uint32) - Returns all matching UIDs. ``` -------------------------------- ### Fetch Only Message Header - Go Source: https://github.com/emersion/go-imap/wiki/Fetching-messages Configures the fetch item to retrieve only the header of the message. ```go var section imap.BodySectionName section.Specifier = imap.HeaderSpecifier ``` -------------------------------- ### Client.Logout / Client.Close Source: https://context7.com/emersion/go-imap/llms.txt Provides methods for gracefully shutting down the IMAP connection. `Logout` sends the `LOGOUT` command, while `Close` terminates the connection immediately. ```APIDOC ## Client.Logout / Client.Close — Graceful and immediate shutdown `Logout` sends the `LOGOUT` command; `Close` tears down the connection immediately. ### Example Usage: ```go if err := c.Logout().Wait(); err != nil { log.Printf("LOGOUT error: %v", err) } // or for immediate close: c.Close() ``` ``` -------------------------------- ### Modify Message Flags with Client.Store Source: https://context7.com/emersion/go-imap/llms.txt Modifies message flags using `STORE` or `UID STORE`. Returns a `*FetchCommand` with updated flag values unless `Silent` is set. Supports adding, deleting, or replacing flags. ```go // Mark messages 1–3 as \Seen, silently storeFlags := &imap.StoreFlags{ Op: imap.StoreFlagsAdd, Flags: []imap.Flag{imap.FlagSeen}, Silent: true, } if err := c.Store(imap.SeqSetRange(1, 3), storeFlags, nil).Close(); err != nil { log.Fatalf("STORE failed: %v", err) } ``` ```go // Remove \Flagged from UID 100, with CONDSTORE unchanged-since guard if err := c.Store(imap.UIDSetNum(100), &imap.StoreFlags{ Op: imap.StoreFlagsDel, Flags: []imap.Flag{imap.FlagFlagged}, }, &imap.StoreOptions{UnchangedSince: 12345}).Close(); err != nil { log.Fatalf("STORE failed: %v", err) } ```