package client
import "github.com/ncastellani/imapServer/client"
Package client provides an IMAP client.
It is not safe to use the same Client from multiple goroutines. In general, the IMAP protocol doesn't make it possible to send multiple independent IMAP commands on the same connection.
Index ¶
- Variables
- type Client
- func Dial(addr string) (*Client, error)
- func DialTLS(addr string, tlsConfig *tls.Config) (*Client, error)
- func DialWithDialer(dialer Dialer, addr string) (*Client, error)
- func DialWithDialerTLS(dialer Dialer, addr string, tlsConfig *tls.Config) (*Client, error)
- func New(conn net.Conn) (*Client, error)
- func (c *Client) Append(mbox string, flags []string, date time.Time, msg imap.Literal) error
- func (c *Client) Authenticate(auth sasl.Client) error
- func (c *Client) Capability() (map[string]bool, error)
- func (c *Client) Check() error
- func (c *Client) Close() error
- func (c *Client) Copy(seqset *imap.SeqSet, dest string) error
- func (c *Client) Create(name string) error
- func (c *Client) Delete(name string) error
- func (c *Client) Enable(caps []string) ([]string, error)
- func (c *Client) Execute(cmdr imap.Commander, h responses.Handler) (*imap.StatusResp, error)
- func (c *Client) Expunge(ch chan uint32) error
- func (c *Client) Fetch(seqset *imap.SeqSet, items []imap.FetchItem, ch chan *imap.Message) error
- func (c *Client) Idle(stop <-chan struct{}, opts *IdleOptions) error
- func (c *Client) IsTLS() bool
- func (c *Client) List(ref, name string, ch chan *imap.MailboxInfo) error
- func (c *Client) LoggedOut() <-chan struct{}
- func (c *Client) Login(username, password string) error
- func (c *Client) Logout() error
- func (c *Client) Lsub(ref, name string, ch chan *imap.MailboxInfo) error
- func (c *Client) Mailbox() *imap.MailboxStatus
- func (c *Client) Move(seqset *imap.SeqSet, dest string) error
- func (c *Client) Noop() error
- func (c *Client) Rename(existingName, newName string) error
- func (c *Client) Search(criteria *imap.SearchCriteria) (seqNums []uint32, err error)
- func (c *Client) Select(name string, readOnly bool) (*imap.MailboxStatus, error)
- func (c *Client) SetDebug(w io.Writer)
- func (c *Client) SetState(state imap.ConnState, mailbox *imap.MailboxStatus)
- func (c *Client) StartTLS(tlsConfig *tls.Config) error
- func (c *Client) State() imap.ConnState
- func (c *Client) Status(name string, items []imap.StatusItem) (*imap.MailboxStatus, error)
- func (c *Client) Store(seqset *imap.SeqSet, item imap.StoreItem, value interface{}, ch chan *imap.Message) error
- func (c *Client) Subscribe(name string) error
- func (c *Client) Support(cap string) (bool, error)
- func (c *Client) SupportAuth(mech string) (bool, error)
- func (c *Client) SupportStartTLS() (bool, error)
- func (c *Client) Terminate() error
- func (c *Client) UidCopy(seqset *imap.SeqSet, dest string) error
- func (c *Client) UidFetch(seqset *imap.SeqSet, items []imap.FetchItem, ch chan *imap.Message) error
- func (c *Client) UidMove(seqset *imap.SeqSet, dest string) error
- func (c *Client) UidSearch(criteria *imap.SearchCriteria) (uids []uint32, err error)
- func (c *Client) UidStore(seqset *imap.SeqSet, item imap.StoreItem, value interface{}, ch chan *imap.Message) error
- func (c *Client) Unselect() error
- func (c *Client) Unsubscribe(name string) error
- func (c *Client) Upgrade(upgrader imap.ConnUpgrader) error
- func (c *Client) Writer() *imap.Writer
- type Dialer
- type ExpungeUpdate
- type IdleOptions
- type MailboxUpdate
- type MessageUpdate
- type StatusUpdate
- type Update
Examples ¶
- Client
- Client.Append
- Client.Expunge
- Client.Fetch
- Client.Idle
- Client.Search
- Client.StartTLS
- Client.Store
Variables ¶
var ( // ErrAlreadyLoggedIn is returned if Login or Authenticate is called when the // client is already logged in. ErrAlreadyLoggedIn = errors.New("Already logged in") // ErrTLSAlreadyEnabled is returned if StartTLS is called when TLS is already // enabled. ErrTLSAlreadyEnabled = errors.New("TLS is already enabled") // ErrLoginDisabled is returned if Login or Authenticate is called when the // server has disabled authentication. Most of the time, calling enabling TLS // solves the problem. ErrLoginDisabled = errors.New("Login is disabled in current state") )
var ( // ErrNoMailboxSelected is returned if a command that requires a mailbox to be // selected is called when there isn't. ErrNoMailboxSelected = errors.New("No mailbox selected") // ErrExtensionUnsupported is returned if a command uses a extension that // is not supported by the server. ErrExtensionUnsupported = errors.New("The required extension is not supported by the server") )
ErrAlreadyLoggedOut is returned if Logout is called when the client is already logged out.
ErrNotLoggedIn is returned if a function that requires the client to be logged in is called then the client isn't.
Types ¶
type Client ¶
type Client struct { // A channel to which unilateral updates from the server will be sent. An // update can be one of: *StatusUpdate, *MailboxUpdate, *MessageUpdate, // *ExpungeUpdate. Note that blocking this channel blocks the whole client, // so it's recommended to use a separate goroutine and a buffered channel to // prevent deadlocks. Updates chan<- Update // ErrorLog specifies an optional logger for errors accepting connections and // unexpected behavior from handlers. By default, logging goes to os.Stderr // via the log package's standard logger. The logger must be safe to use // simultaneously from multiple goroutines. ErrorLog imap.Logger // Timeout specifies a maximum amount of time to wait on a command. // // A Timeout of zero means no timeout. This is the default. Timeout time.Duration // contains filtered or unexported fields }
Client is an IMAP client.
Code:play
Example¶
package main
import (
"log"
imap "github.com/ncastellani/imapServer"
"github.com/ncastellani/imapServer/client"
)
func main() {
log.Println("Connecting to server...")
// Connect to server
c, err := client.DialTLS("mail.example.org:993", nil)
if err != nil {
log.Fatal(err)
}
log.Println("Connected")
// Don't forget to logout
defer c.Logout()
// Login
if err := c.Login("username", "password"); err != nil {
log.Fatal(err)
}
log.Println("Logged in")
// List mailboxes
mailboxes := make(chan *imap.MailboxInfo, 10)
done := make(chan error, 1)
go func() {
done <- c.List("", "*", mailboxes)
}()
log.Println("Mailboxes:")
for m := range mailboxes {
log.Println("* " + m.Name)
}
if err := <-done; err != nil {
log.Fatal(err)
}
// Select INBOX
mbox, err := c.Select("INBOX", false)
if err != nil {
log.Fatal(err)
}
log.Println("Flags for INBOX:", mbox.Flags)
// Get the last 4 messages
from := uint32(1)
to := mbox.Messages
if mbox.Messages > 3 {
// We're using unsigned integers here, only substract if the result is > 0
from = mbox.Messages - 3
}
seqset := new(imap.SeqSet)
seqset.AddRange(from, to)
items := []imap.FetchItem{imap.FetchEnvelope}
messages := make(chan *imap.Message, 10)
done = make(chan error, 1)
go func() {
done <- c.Fetch(seqset, items, messages)
}()
log.Println("Last 4 messages:")
for msg := range messages {
log.Println("* " + msg.Envelope.Subject)
}
if err := <-done; err != nil {
log.Fatal(err)
}
log.Println("Done!")
}
func Dial ¶
Dial connects to an IMAP server using an unencrypted connection.
func DialTLS ¶
DialTLS connects to an IMAP server using an encrypted connection.
func DialWithDialer ¶
DialWithDialer connects to an IMAP server using an unencrypted connection using dialer.Dial.
Among other uses, this allows to apply a dial timeout.
func DialWithDialerTLS ¶
DialWithDialerTLS connects to an IMAP server using an encrypted connection using dialer.Dial.
Among other uses, this allows to apply a dial timeout.
func New ¶
New creates a new client from an existing connection.
func (*Client) Append ¶
Append appends the literal argument as a new message to the end of the
specified destination mailbox. This argument SHOULD be in the format of an
RFC 2822 message. flags and date are optional arguments and can be set to
nil and the empty struct.
Code:play
Example¶
package main
import (
"bytes"
"log"
"time"
imap "github.com/ncastellani/imapServer"
"github.com/ncastellani/imapServer/client"
)
func main() {
// Let's assume c is a client
var c *client.Client
// Write the message to a buffer
var b bytes.Buffer
b.WriteString("From: <root@nsa.gov>\r\n")
b.WriteString("To: <root@gchq.gov.uk>\r\n")
b.WriteString("Subject: Hey there\r\n")
b.WriteString("\r\n")
b.WriteString("Hey <3")
// Append it to INBOX, with two flags
flags := []string{imap.FlaggedFlag, "foobar"}
if err := c.Append("INBOX", flags, time.Now(), &b); err != nil {
log.Fatal(err)
}
}
func (*Client) Authenticate ¶
Authenticate indicates a SASL authentication mechanism to the server. If the server supports the requested authentication mechanism, it performs an authentication protocol exchange to authenticate and identify the client.
func (*Client) Capability ¶
Capability requests a listing of capabilities that the server supports. Capabilities are often returned by the server with the greeting or with the STARTTLS and LOGIN responses, so usually explicitly requesting capabilities isn't needed.
Most of the time, Support should be used instead.
func (*Client) Check ¶
Check requests a checkpoint of the currently selected mailbox. A checkpoint refers to any implementation-dependent housekeeping associated with the mailbox that is not normally executed as part of each command.
func (*Client) Close ¶
Close permanently removes all messages that have the \Deleted flag set from the currently selected mailbox, and returns to the authenticated state from the selected state.
func (*Client) Copy ¶
Copy copies the specified message(s) to the end of the specified destination mailbox.
func (*Client) Create ¶
Create creates a mailbox with the given name.
func (*Client) Delete ¶
Delete permanently removes the mailbox with the given name.
func (*Client) Enable ¶
Enable requests the server to enable the named extensions. The extensions which were successfully enabled are returned.
See RFC 5161 section 3.1.
func (*Client) Execute ¶
Execute executes a generic command. cmdr is a value that can be converted to a raw command and h is a response handler. The function returns when the command has completed or failed, in this case err is nil. A non-nil err value indicates a network error.
This function should not be called directly, it must only be used by libraries implementing extensions of the IMAP protocol.
func (*Client) Expunge ¶
Expunge permanently removes all messages that have the \Deleted flag set from
the currently selected mailbox. If ch is not nil, sends sequence IDs of each
deleted message to this channel.
Code:play
Example¶
package main
import (
"log"
imap "github.com/ncastellani/imapServer"
"github.com/ncastellani/imapServer/client"
)
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)
}
// We will delete the last message
if mbox.Messages == 0 {
log.Fatal("No message in mailbox")
}
seqset := new(imap.SeqSet)
seqset.AddNum(mbox.Messages)
// First mark the message as deleted
item := imap.FormatFlagsOp(imap.AddFlags, true)
flags := []interface{}{imap.DeletedFlag}
if err := c.Store(seqset, item, flags, nil); err != nil {
log.Fatal(err)
}
// Then delete it
if err := c.Expunge(nil); err != nil {
log.Fatal(err)
}
log.Println("Last message has been deleted")
}
func (*Client) Fetch ¶
Fetch retrieves data associated with a message in the mailbox. See RFC 3501
section 6.4.5 for a list of items that can be requested.
Code:play
Example¶
package main
import (
"io/ioutil"
"log"
"net/mail"
imap "github.com/ncastellani/imapServer"
"github.com/ncastellani/imapServer/client"
)
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.AddRange(mbox.Messages, mbox.Messages)
// Get the whole message body
section := &imap.BodySectionName{}
items := []imap.FetchItem{section.FetchItem()}
messages := make(chan *imap.Message, 1)
done := make(chan error, 1)
go func() {
done <- c.Fetch(seqset, items, messages)
}()
log.Println("Last message:")
msg := <-messages
r := msg.GetBody(section)
if r == nil {
log.Fatal("Server didn't returned message body")
}
if err := <-done; err != nil {
log.Fatal(err)
}
m, err := mail.ReadMessage(r)
if err != nil {
log.Fatal(err)
}
header := m.Header
log.Println("Date:", header.Get("Date"))
log.Println("From:", header.Get("From"))
log.Println("To:", header.Get("To"))
log.Println("Subject:", header.Get("Subject"))
body, err := ioutil.ReadAll(m.Body)
if err != nil {
log.Fatal(err)
}
log.Println(body)
}
func (*Client) Idle ¶
func (c *Client) Idle(stop <-chan struct{}, opts *IdleOptions) error
Idle indicates to the server that the client is ready to receive unsolicited mailbox update messages. When the client wants to send commands again, it must first close stop.
If the server doesn't support IDLE, go-imap falls back to polling.
Code:play
Example¶
package main
import (
"log"
"github.com/ncastellani/imapServer/client"
)
func main() {
// Let's assume c is a client
var c *client.Client
// Select a mailbox
if _, err := c.Select("INBOX", false); err != nil {
log.Fatal(err)
}
// Create a channel to receive mailbox updates
updates := make(chan client.Update)
c.Updates = updates
// Start idling
stopped := false
stop := make(chan struct{})
done := make(chan error, 1)
go func() {
done <- c.Idle(stop, nil)
}()
// Listen for updates
for {
select {
case update := <-updates:
log.Println("New update:", update)
if !stopped {
close(stop)
stopped = true
}
case err := <-done:
if err != nil {
log.Fatal(err)
}
log.Println("Not idling anymore")
return
}
}
}
func (*Client) IsTLS ¶
IsTLS checks if this client's connection has TLS enabled.
func (*Client) List ¶
func (c *Client) List(ref, name string, ch chan *imap.MailboxInfo) error
List returns a subset of names from the complete set of all names available to the client.
An empty name argument is a special request to return the hierarchy delimiter and the root name of the name given in the reference. The character "*" is a wildcard, and matches zero or more characters at this position. The character "%" is similar to "*", but it does not match a hierarchy delimiter.
func (*Client) LoggedOut ¶
func (c *Client) LoggedOut() <-chan struct{}
LoggedOut returns a channel which is closed when the connection to the server is closed.
func (*Client) Login ¶
Login identifies the client to the server and carries the plaintext password authenticating this user.
func (*Client) Logout ¶
Logout gracefully closes the connection.
func (*Client) Lsub ¶
func (c *Client) Lsub(ref, name string, ch chan *imap.MailboxInfo) error
Lsub returns a subset of names from the set of names that the user has declared as being "active" or "subscribed".
func (*Client) Mailbox ¶
func (c *Client) Mailbox() *imap.MailboxStatus
Mailbox returns the selected mailbox. It returns nil if there isn't one.
func (*Client) Move ¶
Move moves the specified message(s) to the end of the specified destination mailbox.
If the server doesn't support the MOVE extension defined in RFC 6851, go-imap will fallback to copy, store and expunge.
func (*Client) Noop ¶
Noop always succeeds and does nothing.
It can be used as a periodic poll for new messages or message status updates during a period of inactivity. It can also be used to reset any inactivity autologout timer on the server.
func (*Client) Rename ¶
Rename changes the name of a mailbox.
func (*Client) Search ¶
func (c *Client) Search(criteria *imap.SearchCriteria) (seqNums []uint32, err error)
Search searches the mailbox for messages that match the given searching
criteria. Searching criteria consist of one or more search keys. The response
contains a list of message sequence IDs corresponding to those messages that
match the searching criteria. When multiple keys are specified, the result is
the intersection (AND function) of all the messages that match those keys.
Criteria must be UTF-8 encoded. See RFC 3501 section 6.4.4 for a list of
searching criteria. When no criteria has been set, all messages in the mailbox
will be searched using ALL criteria.
Code:play
Example¶
package main
import (
"log"
imap "github.com/ncastellani/imapServer"
"github.com/ncastellani/imapServer/client"
)
func main() {
// Let's assume c is a client
var c *client.Client
// Select INBOX
_, err := c.Select("INBOX", false)
if err != nil {
log.Fatal(err)
}
// Set search criteria
criteria := imap.NewSearchCriteria()
criteria.WithoutFlags = []string{imap.SeenFlag}
ids, err := c.Search(criteria)
if err != nil {
log.Fatal(err)
}
log.Println("IDs found:", ids)
if len(ids) > 0 {
seqset := new(imap.SeqSet)
seqset.AddNum(ids...)
messages := make(chan *imap.Message, 10)
done := make(chan error, 1)
go func() {
done <- c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope}, messages)
}()
log.Println("Unseen messages:")
for msg := range messages {
log.Println("* " + msg.Envelope.Subject)
}
if err := <-done; err != nil {
log.Fatal(err)
}
}
log.Println("Done!")
}
func (*Client) Select ¶
Select selects a mailbox so that messages in the mailbox can be accessed. Any currently selected mailbox is deselected before attempting the new selection. Even if the readOnly parameter is set to false, the server can decide to open the mailbox in read-only mode.
func (*Client) SetDebug ¶
SetDebug defines an io.Writer to which all network activity will be logged. If nil is provided, network activity will not be logged.
func (*Client) SetState ¶
func (c *Client) SetState(state imap.ConnState, mailbox *imap.MailboxStatus)
SetState sets this connection's internal state.
This function should not be called directly, it must only be used by libraries implementing extensions of the IMAP protocol.
func (*Client) StartTLS ¶
StartTLS starts TLS negotiation.
Code:play
Example¶
package main
import (
"crypto/tls"
"log"
"github.com/ncastellani/imapServer/client"
)
func main() {
log.Println("Connecting to server...")
// Connect to server
c, err := client.Dial("mail.example.org:143")
if err != nil {
log.Fatal(err)
}
log.Println("Connected")
// Don't forget to logout
defer c.Logout()
// Start a TLS session
tlsConfig := &tls.Config{ServerName: "mail.example.org"}
if err := c.StartTLS(tlsConfig); err != nil {
log.Fatal(err)
}
log.Println("TLS started")
// Now we can login
if err := c.Login("username", "password"); err != nil {
log.Fatal(err)
}
log.Println("Logged in")
}
func (*Client) State ¶
State returns the current connection state.
func (*Client) Status ¶
func (c *Client) Status(name string, items []imap.StatusItem) (*imap.MailboxStatus, error)
Status requests the status of the indicated mailbox. It does not change the currently selected mailbox, nor does it affect the state of any messages in the queried mailbox.
See RFC 3501 section 6.3.10 for a list of items that can be requested.
func (*Client) Store ¶
func (c *Client) Store(seqset *imap.SeqSet, item imap.StoreItem, value interface{}, ch chan *imap.Message) error
Store alters data associated with a message in the mailbox. If ch is not nil,
the updated value of the data will be sent to this channel. See RFC 3501
section 6.4.6 for a list of items that can be updated.
Code:play
Example¶
package main
import (
"log"
imap "github.com/ncastellani/imapServer"
"github.com/ncastellani/imapServer/client"
)
func main() {
// Let's assume c is a client
var c *client.Client
// Select INBOX
_, err := c.Select("INBOX", false)
if err != nil {
log.Fatal(err)
}
// Mark message 42 as seen
seqSet := new(imap.SeqSet)
seqSet.AddNum(42)
item := imap.FormatFlagsOp(imap.AddFlags, true)
flags := []interface{}{imap.SeenFlag}
err = c.Store(seqSet, item, flags, nil)
if err != nil {
log.Fatal(err)
}
log.Println("Message has been marked as seen")
}
func (*Client) Subscribe ¶
Subscribe adds the specified mailbox name to the server's set of "active" or "subscribed" mailboxes.
func (*Client) Support ¶
Support checks if cap is a capability supported by the server. If the server hasn't sent its capabilities yet, Support requests them.
func (*Client) SupportAuth ¶
SupportAuth checks if the server supports a given authentication mechanism.
func (*Client) SupportStartTLS ¶
SupportStartTLS checks if the server supports STARTTLS.
func (*Client) Terminate ¶
Terminate closes the tcp connection
func (*Client) UidCopy ¶
UidCopy is identical to Copy, but seqset is interpreted as containing unique identifiers instead of message sequence numbers.
func (*Client) UidFetch ¶
UidFetch is identical to Fetch, but seqset is interpreted as containing unique identifiers instead of message sequence numbers.
func (*Client) UidMove ¶
UidMove is identical to Move, but seqset is interpreted as containing unique identifiers instead of message sequence numbers.
func (*Client) UidSearch ¶
func (c *Client) UidSearch(criteria *imap.SearchCriteria) (uids []uint32, err error)
UidSearch is identical to Search, but UIDs are returned instead of message sequence numbers.
func (*Client) UidStore ¶
func (c *Client) UidStore(seqset *imap.SeqSet, item imap.StoreItem, value interface{}, ch chan *imap.Message) error
UidStore is identical to Store, but seqset is interpreted as containing unique identifiers instead of message sequence numbers.
func (*Client) Unselect ¶
Unselect frees server's resources associated with the selected mailbox and returns the server to the authenticated state. This command performs the same actions as Close, except that no messages are permanently removed from the currently selected mailbox.
If client does not support the UNSELECT extension, ErrExtensionUnsupported is returned.
func (*Client) Unsubscribe ¶
Unsubscribe removes the specified mailbox name from the server's set of "active" or "subscribed" mailboxes.
func (*Client) Upgrade ¶
func (c *Client) Upgrade(upgrader imap.ConnUpgrader) error
Upgrade a connection, e.g. wrap an unencrypted connection with an encrypted tunnel.
This function should not be called directly, it must only be used by libraries implementing extensions of the IMAP protocol.
func (*Client) Writer ¶
Writer returns the imap.Writer for this client's connection.
This function should not be called directly, it must only be used by libraries implementing extensions of the IMAP protocol.
type Dialer ¶
type Dialer interface { // Dial connects to the given address. Dial(network, addr string) (net.Conn, error) }
type ExpungeUpdate ¶
type ExpungeUpdate struct { SeqNum uint32 }
ExpungeUpdate is delivered when a message is deleted.
type IdleOptions ¶
type IdleOptions struct { // LogoutTimeout is used to avoid being logged out by the server when // idling. Each LogoutTimeout, the IDLE command is restarted. If set to // zero, a default is used. If negative, this behavior is disabled. LogoutTimeout time.Duration // Poll interval when the server doesn't support IDLE. If zero, a default // is used. If negative, polling is always disabled. PollInterval time.Duration }
IdleOptions holds options for Client.Idle.
type MailboxUpdate ¶
type MailboxUpdate struct { Mailbox *imap.MailboxStatus }
MailboxUpdate is delivered when a mailbox status changes.
type MessageUpdate ¶
MessageUpdate is delivered when a message attribute changes.
type StatusUpdate ¶
type StatusUpdate struct { Status *imap.StatusResp }
StatusUpdate is delivered when a status update is received.
type Update ¶
type Update interface {
// contains filtered or unexported methods
}
Update is an unilateral server update.
Source Files ¶
client.go cmd_any.go cmd_auth.go cmd_noauth.go cmd_selected.go tag.go
- Version
- v1.2.13 (latest)
- Published
- Jan 10, 2024
- Platform
- linux/amd64
- Imports
- 15 packages
- Last checked
- 2 days ago –
Tools for package owners.