imap

package module
v0.1.15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2025 License: MIT Imports: 22 Imported by: 10

README

Go IMAP Client (go-imap)

Go Reference CI Go Report Card

Simple, pragmatic IMAP client for Go (Golang) with TLS, LOGIN or XOAUTH2 (OAuth 2.0), IDLE notifications, robust reconnects, and batteries‑included helpers for searching, fetching, moving, and flagging messages.

Works great with Gmail, Office 365/Exchange, and most RFC‑compliant IMAP servers.

Features

  • TLS connections and timeouts (DialTimeout, CommandTimeout)
  • Authentication via LOGIN and XOAUTH2
  • Folders: SELECT/EXAMINE, list folders
  • Search: UID SEARCH helpers
  • Fetch: envelope, flags, size, text/HTML bodies, attachments
  • Mutations: move, set flags, delete + expunge
  • IMAP IDLE with event handlers for EXISTS, EXPUNGE, FETCH
  • Automatic reconnect with re‑auth and folder restore

Install

go get github.com/BrianLeishman/go-imap

Requires Go 1.24+ (see go.mod).

Quick Start (LOGIN)

package main

import (
    "fmt"
    imap "github.com/BrianLeishman/go-imap"
)

func main() {
    // Optional diagnostics
    imap.Verbose = false
    imap.RetryCount = 3

    // Timeouts (optional)
    // imap.DialTimeout = 10 * time.Second
    // imap.CommandTimeout = 30 * time.Second

    // Connect & login
    m, err := imap.New("username", "password", "mail.server.com", 993)
    if err != nil { panic(err) }
    defer m.Close()

    // List and select a folder
    folders, err := m.GetFolders()
    if err != nil { panic(err) }
    fmt.Println("Folders:", folders)
    if err := m.SelectFolder("INBOX"); err != nil { panic(err) }

    // Search & fetch
    uids, err := m.GetUIDs("ALL")
    if err != nil { panic(err) }
    emails, err := m.GetEmails(uids...)
    if err != nil { panic(err) }
    if len(emails) > 0 {
        fmt.Println(emails[0])
    }
}

Quick Start (XOAUTH2 / OAuth 2.0)

m, err := imap.NewWithOAuth2("user@example.com", accessToken, "imap.gmail.com", 993)
if err != nil { panic(err) }
defer m.Close()

if err := m.SelectFolder("INBOX"); err != nil { panic(err) }

IDLE Notifications

handler := &imap.IdleHandler{
    OnExists: func(e imap.ExistsEvent) { fmt.Println("exists:", e.MessageIndex) },
    OnExpunge: func(e imap.ExpungeEvent) { fmt.Println("expunge:", e.MessageIndex) },
    OnFetch: func(e imap.FetchEvent) {
        fmt.Printf("fetch idx=%d uid=%d flags=%v\n", e.MessageIndex, e.UID, e.Flags)
    },
}

if err := m.StartIdle(handler); err != nil { panic(err) }
// ... later, stop IDLE
// _ = m.StopIdle()

Reconnect Behavior

When a command fails, the library closes the socket, reconnects, re‑authenticates (LOGIN or XOAUTH2), and restores the previously selected folder. You can tune retry count via imap.RetryCount.

TLS & Certificates

Connections are TLS by default. For servers with self‑signed certs you can set imap.TLSSkipVerify = true, but be aware this disables certificate validation and can expose you to man‑in‑the‑middle attacks. Prefer real certificates in production.

Server Compatibility

Tested against common providers such as Gmail and Office 365/Exchange. The client targets RFC 3501 and common extensions used for search, fetch, and move.

CI & Quality

This repo runs Go 1.24+ on CI with vet and race‑enabled tests. We also track documentation on pkg.go.dev and Go Report Card.

Contributing

Issues and PRs are welcome! If adding public APIs, please include short docs and examples. Make sure go vet and go test -race ./... pass locally.

License

MIT © Brian Leishman


Built With

Documentation

Overview

Package imap provides a simple, pragmatic IMAP client for Go.

It focuses on the handful of operations most applications need:

  • Connecting over TLS (STARTTLS not required)
  • Authenticating with LOGIN or XOAUTH2 (OAuth 2.0)
  • Selecting/Examining folders, searching (UID SEARCH), and fetching messages
  • Moving messages, setting flags, deleting + expunging
  • IMAP IDLE with callbacks for EXISTS/EXPUNGE/FETCH
  • Automatic reconnect with re-authentication and folder restore

The API is intentionally small and easy to adopt without pulling in a full IMAP stack. See the README for end‑to‑end examples and guidance.

Index

Constants

View Source
const (
	IdleEventExists  = "EXISTS"
	IdleEventExpunge = "EXPUNGE"
	IdleEventFetch   = "FETCH"
)
View Source
const (
	StateDisconnected = iota
	StateConnected
	StateSelected
	StateIdlePending
	StateIdling
	StateStoppingIdle
)
View Source
const (
	EDate uint8 = iota
	ESubject
	EFrom
	ESender
	EReplyTo
	ETo
	ECC
	EBCC
	EInReplyTo
	EMessageID
)
View Source
const (
	EEName uint8 = iota
	// EESR is unused and should be ignored
	EESR
	EEMailbox
	EEHost
)
View Source
const TimeFormat = "_2-Jan-2006 15:04:05 -0700"

TimeFormat is the Go time version of the IMAP times

Variables

View Source
var AddSlashes = strings.NewReplacer(`"`, `\"`)

AddSlashes adds slashes to double quotes

View Source
var CommandTimeout time.Duration

CommandTimeout defines how long to wait for a command to complete. Zero means no timeout.

View Source
var DialTimeout time.Duration

DialTimeout defines how long to wait when establishing a new connection. Zero means no timeout.

View Source
var RemoveSlashes = strings.NewReplacer(`\"`, `"`)

RemoveSlashes removes slashes before double quotes

View Source
var RetryCount = 10

RetryCount is the number of times retired functions get retried

View Source
var SkipResponses = false

SkipResponses skips printing server responses in verbose mode

View Source
var TLSSkipVerify bool

TLSSkipVerify disables certificate verification when establishing new connections. Use with caution; skipping verification exposes the connection to man-in-the-middle attacks.

View Source
var Verbose = false

Verbose outputs every command and its response with the IMAP server

Functions

func GetTokenName

func GetTokenName(tokenType TType) string

GetTokenName returns the name of the given token type token

func IsLiteral

func IsLiteral(b rune) bool

IsLiteral returns if the given byte is an acceptable literal character

Types

type Attachment

type Attachment struct {
	Name     string
	MimeType string
	Content  []byte
}

Attachment is an Email attachment

func (Attachment) String

func (a Attachment) String() string

type Dialer

type Dialer struct {
	Folder    string
	ReadOnly  bool
	Username  string
	Password  string
	Host      string
	Port      int
	Connected bool
	ConnNum   int
	// contains filtered or unexported fields
}

Dialer is basically an IMAP connection

func New

func New(username string, password string, host string, port int) (d *Dialer, err error)

New makes a new imap

func NewWithOAuth2 added in v0.1.7

func NewWithOAuth2(username string, accessToken string, host string, port int) (d *Dialer, err error)

NewWithOAuth2 makes a new imap with OAuth2

func (*Dialer) Authenticate added in v0.1.7

func (d *Dialer) Authenticate(user string, accessToken string) (err error)

func (*Dialer) CheckType

func (d *Dialer) CheckType(token *Token, acceptableTypes []TType, tks []*Token, loc string, v ...interface{}) (err error)

CheckType validates a type against a list of acceptable types, if the type of the token isn't in the list, an error is returned

func (*Dialer) Clone

func (d *Dialer) Clone() (d2 *Dialer, err error)

Clone returns a new connection with the same connection information as the one this is being called on

func (*Dialer) Close

func (d *Dialer) Close() (err error)

Close closes the imap connection

func (*Dialer) DeleteEmail added in v0.1.9

func (d *Dialer) DeleteEmail(uid int) (err error)

DeleteEmail marks an email as deleted

func (*Dialer) ExamineFolder added in v0.1.8

func (d *Dialer) ExamineFolder(folder string) (err error)

ExamineFolder selects a folder

func (*Dialer) Exec

func (d *Dialer) Exec(command string, buildResponse bool, retryCount int, processLine func(line []byte) error) (response string, err error)

Exec executes the command on the imap connection

func (*Dialer) Expunge added in v0.1.9

func (d *Dialer) Expunge() (err error)

Expunge permanently removes messages marked as deleted in the current folder

func (*Dialer) GetEmails

func (d *Dialer) GetEmails(uids ...int) (emails map[int]*Email, err error)

GetEmails returns email with their bodies for the given UIDs in the current folder. If no UIDs are given, then everything in the current folder is selected

func (*Dialer) GetFolders

func (d *Dialer) GetFolders() (folders []string, err error)

GetFolders returns all folders

func (*Dialer) GetOverviews

func (d *Dialer) GetOverviews(uids ...int) (emails map[int]*Email, err error)

GetOverviews returns emails without bodies for the given UIDs in the current folder. If no UIDs are given, then everything in the current folder is selected

func (*Dialer) GetTotalEmailCount

func (d *Dialer) GetTotalEmailCount() (count int, err error)

GetTotalEmailCount returns the total number of emails in every folder

func (*Dialer) GetTotalEmailCountExcluding

func (d *Dialer) GetTotalEmailCountExcluding(excludedFolders []string) (count int, err error)

GetTotalEmailCountExcluding returns the total number of emails in every folder excluding the specified folders

func (*Dialer) GetTotalEmailCountStartingFrom

func (d *Dialer) GetTotalEmailCountStartingFrom(startFolder string) (count int, err error)

GetTotalEmailCountStartingFrom returns the total number of emails in every folder after the specified start folder

func (*Dialer) GetTotalEmailCountStartingFromExcluding

func (d *Dialer) GetTotalEmailCountStartingFromExcluding(startFolder string, excludedFolders []string) (count int, err error)

GetTotalEmailCountStartingFromExcluding returns the total number of emails in every folder after the specified start folder, excluding the specified folders

func (*Dialer) GetUIDs

func (d *Dialer) GetUIDs(search string) (uids []int, err error)

func (*Dialer) Login

func (d *Dialer) Login(username string, password string) (err error)

Login attempts to login

func (*Dialer) MarkSeen added in v0.1.8

func (d *Dialer) MarkSeen(uid int) (err error)

mark an emai as seen

func (*Dialer) MoveEmail added in v0.1.3

func (d *Dialer) MoveEmail(uid int, folder string) (err error)

Move a read email to a specified folder

func (*Dialer) ParseFetchResponse

func (d *Dialer) ParseFetchResponse(responseBody string) (records [][]*Token, err error)

func (*Dialer) Reconnect

func (d *Dialer) Reconnect() (err error)

Reconnect closes the current connection (if any) and establishes a new one

func (*Dialer) SelectFolder

func (d *Dialer) SelectFolder(folder string) (err error)

SelectFolder selects a folder

func (*Dialer) SetFlags added in v0.1.8

func (d *Dialer) SetFlags(uid int, flags Flags) (err error)

set system-flags and keywords

func (*Dialer) StartIdle added in v0.1.5

func (d *Dialer) StartIdle(handler *IdleHandler) error

func (*Dialer) State added in v0.1.8

func (d *Dialer) State() int

func (*Dialer) StopIdle added in v0.1.8

func (d *Dialer) StopIdle() error

type Email

type Email struct {
	Flags       []string
	Received    time.Time
	Sent        time.Time
	Size        uint64
	Subject     string
	UID         int
	MessageID   string
	From        EmailAddresses
	To          EmailAddresses
	ReplyTo     EmailAddresses
	CC          EmailAddresses
	BCC         EmailAddresses
	Text        string
	HTML        string
	Attachments []Attachment
}

Email is an email message

func (Email) String

func (e Email) String() string

type EmailAddresses

type EmailAddresses map[string]string

EmailAddresses are a map of email address to names

func (EmailAddresses) String

func (e EmailAddresses) String() string

type ExistsEvent added in v0.1.5

type ExistsEvent struct {
	MessageIndex int
}

type ExpungeEvent added in v0.1.5

type ExpungeEvent struct {
	MessageIndex int
}

type FetchEvent added in v0.1.5

type FetchEvent struct {
	MessageIndex int
	UID          uint32
	Flags        []string
}

type FlagSet added in v0.1.8

type FlagSet int
const (
	FlagUnset FlagSet = iota
	FlagAdd
	FlagRemove
)

type Flags added in v0.1.8

type Flags struct {
	Seen     FlagSet
	Answered FlagSet
	Flagged  FlagSet
	Deleted  FlagSet
	Draft    FlagSet
	Keywords map[string]bool
}

type IdleHandler added in v0.1.5

type IdleHandler struct {
	OnExists  func(event ExistsEvent)
	OnExpunge func(event ExpungeEvent)
	OnFetch   func(event FetchEvent)
}

type TType

type TType uint8

TType is the enum type for token values

const (
	// TUnset is an unset token; used by the parser
	TUnset TType = iota
	// TAtom is a string that's prefixed with `{n}`
	// where n is the number of bytes in the string
	TAtom
	// TNumber is a numeric literal
	TNumber
	// TLiteral is a literal (think string, ish, used mainly for field names, I hope)
	TLiteral
	// TQuoted is a quoted piece of text
	TQuoted
	// TNil is a nil value, nothing
	TNil
	// TContainer is a container of tokens
	TContainer
)

type Token

type Token struct {
	Type   TType
	Str    string
	Num    int
	Tokens []*Token
}

Token is a fetch response token (e.g. a number, or a quoted section, or a container, etc.)

func (Token) String

func (t Token) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL