/go-imap

:inbox_tray: An IMAP library for clients and servers

Primary LanguageGoMIT LicenseMIT

go-imap

GoDoc Build Status Codecov Go Report Card Unstable Gitter chat

An IMAP4rev1 library written in Go. It can be used to build a client and/or a server.

Note: new projects should use the v1 branch.

go get github.com/emersion/go-imap/...

Why?

Other IMAP implementations in Go:

  • Require to make many type assertions or conversions
  • Are not idiomatic or are ugly
  • Are not pleasant to use
  • Implement a server xor a client, not both
  • Don't implement unilateral updates (i.e. the server can't notify clients for new messages)
  • Do not have a good test coverage
  • Don't handle encoding and charset automatically

Usage

Client GoDoc

package main

import (
	"log"

	"github.com/emersion/go-imap/client"
	"github.com/emersion/go-imap"
)

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)

	messages := make(chan *imap.Message, 10)
	done = make(chan error, 1)
	go func() {
		done <- c.Fetch(seqset, []string{imap.EnvelopeMsgAttr}, 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!")
}

Server GoDoc

package main

import (
	"log"

	"github.com/emersion/go-imap/server"
	"github.com/emersion/go-imap/backend/memory"
)

func main() {
	// Create a memory backend
	be := memory.New()

	// Create a new server
	s := server.New(be)
	s.Addr = ":1143"
	// Since we will use this server for testing only, we can allow plain text
	// authentication over unencrypted connections
	s.AllowInsecureAuth = true

	log.Println("Starting IMAP server at localhost:1143")
	if err := s.ListenAndServe(); err != nil {
		log.Fatal(err)
	}
}

You can now use telnet localhost 1143 to manually connect to the server.

Extending go-imap

Extensions

Commands defined in IMAP extensions are available in other packages. See the wiki to learn how to use them.

Server backends

Related projects

  • go-message - parsing and formatting MIME and mail messages
  • go-pgpmail - decrypting and encrypting mails with OpenPGP
  • go-sasl - sending and receiving SASL authentications
  • go-smtp - building SMTP clients and servers
  • go-dkim - creating and verifying DKIM signatures

License

MIT