:inbox_tray: An IMAP library for clients and servers

Overview

go-imap

godocs.io builds.sr.ht status Codecov

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

Usage

Client godocs.io

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 subtract 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, []imap.FetchItem{imap.FetchEnvelope}, 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 godocs.io

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.

Extensions

Support for several IMAP extensions is included in go-imap itself. This includes:

Support for other extensions is provided via separate packages. See below.

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-msgauth - handle DKIM, DMARC and Authentication-Results
  • go-pgpmail - decrypting and encrypting mails with OpenPGP
  • go-sasl - sending and receiving SASL authentications
  • go-smtp - building SMTP clients and servers

License

MIT

Comments
  • K9-Mail Compatibility:  list special-use type error

    K9-Mail Compatibility: list special-use type error

    To get K-9 Mail working, I changed the follwing

     s := make([]string, len(fields))
     for i, v := range fields {
        s[i] = fmt.Sprint(v)
      }
     
       if mailbox, err := imap.ParseString(s[0]); err != nil {
    ...
    

    to line: https://github.com/emersion/go-imap/blob/master/commands/list.go#L41

    Please excuse my go. I've only been writing it for one day.

    references: https://stackoverflow.com/questions/44027826/convert-interface-to-string-in-golang

    opened by iot-resister 30
  • Lots of Server-side fixes and improvements

    Lots of Server-side fixes and improvements

    I have been using Dovecot's ImapTest program to stress test the server in go-imap using the memory backend.

    The memory backend is now more feature complete and a good starting point for new backends.

    In the core server code, I fixed some data races and deadlocks.

    The Backend updates support was very broken.

    opened by Neopallium 25
  • Deadlock when executing commands in a loop

    Deadlock when executing commands in a loop

    @emersion Hello, I want to count number of messages in folders(mailboxes). I made infinity loop only for tests.

    It's look like my problem from IDLE, that last command is not finished and next is ignored causing to block.

    It's code from example, I only added code inside for reading from channel.

        for {
    
            c, err := client.Dial("localhost:143")
            if err != nil {
                log.Fatal(err)
            }
            log.Println("Connected")
    
            if err := c.Login("user", "password"); err != nil {
                panic(err)
            }
            log.Println("Logged in")
    
            // List mailboxes
            mailboxes := make(chan *imap.MailboxInfo, 10)
            go func() {
            if err := c.List("", "*", mailboxes); err != nil {
                    log.Fatal(err)
                }
            }()
    
            log.Println("Mailboxes:")
            for m := range mailboxes {
                log.Println("* " + m.Name)
    
                mbox, err := c.Select(m.Name, true)
                if err != nil {
                    log.Println("Error", err)
                    return
                }
                fmt.Println(m.Name, " + ", mbox.Messages)
                c.Close()
    
            }
    
            c.Logout()
        }
    
    E336w OK [READ-ONLY] Examine completed (0.000 secs).
    * OK [CLOSED] Previous mailbox closed.
    * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
    * OK [PERMANENTFLAGS ()] Read-only mailbox.
    * 26 EXISTS
    * 0 RECENT
    * OK [UIDVALIDITY 1484216700] UIDs valid
    * OK [UIDNEXT 27] Predicted next UID
    * OK [NOMODSEQ] No permanent modsequences
    36w OK [READ-ONLY] Examine completed (0.000 secs).
    imap/client: 2017/02/23 11:00:15 response has not been handled: &{* OK NOMODSEQ [] No permanent modsequences}
    lE336w EXAMINE Sent
    36w EXAMINE Sent
    
    bug client 
    opened by delldesign 16
  • Hide the output messages

    Hide the output messages

    When I select a folder with

    mbox, err := i.Client.Select(mailbox.Name, false)
    

    I get this output messages:

    imap/client: 2017/12/26 22:49:10 response has not been handled: &{* OK CLOSED [] Previous mailbox closed.}
    imap/client: 2017/12/26 22:49:10 response has not been handled: &{* OK HIGHESTMODSEQ [1] Highest}
    

    Is there a way to hide / suppress this output?

    opened by matiux 13
  • Fix custom delimiter bug

    Fix custom delimiter bug

    This Pull Request does fix the bug that makes it impossible to have every custom delimiter. For example, the character with hex 0x1C was encoded by UTF-7 and would become &HA-. IMAP clients like Thunderbird then could not detect it being an delimiter. Therefore, I removed all UTF-7 encoding of the folders and added it to the backend.

    Then, if you use the hex 0x1C as delimiter, then you should encode your folder name in the backend like this: When you have a folder with name folder having a folder subfolder having a folder subsubfolder, then encode this folder names seperate from each other. Then append this names together with your delimiter (in this case the hex 0x1C). You will get foldersubfoldersubsubfolder, where  is your delimiter.

    opened by ben221199 12
  • When I use client.search then client.fetch returns an error

    When I use client.search then client.fetch returns an error

    Logged in Hotmail and after selecting a mailbox.

    seqSet := new(imap.SeqSet)
    searchCriteria := imap.NewSearchCriteria()
    searchCriteria.Since = time.Now().AddDate(0, -10, 0)
    searchRes, _ := es.EmailClient.Search(searchCriteria)
    
    ......
    
    go func() {
        messagesErrorChannel <- es.EmailClient.Fetch(seqSet, []imap.FetchItem{bodySection.FetchItem()}, messagesChannel)
    }()
    

    Then 'messageErrorChannel' raises an error: The specified message set is invalid.

    opened by KidoThunder 12
  • Example for MOVE

    Example for MOVE

    Hi,

    Thanks for maintaining this library.

    I am trying to move a message from one mailbox to another and I can't figure it out.

    Is it possible to add an example snippet towards the end of this code on the wiki?

    .
    .
    .
    // Process each message's part
    for {
      .
      .
      .
    }
    
    // Move message from inbox to processed
    .
    .
    .
    

    Also, is it possible to create a new mailbox (if it does not exist)?

    Thanks.

    opened by samstride 10
  • Fix imap idle when multiple connections are present

    Fix imap idle when multiple connections are present

    If there are multiple connections, we need to send them each the same updates. This currently doesn't work correctly because messages and sequence numbers are held in a channel which is emptied after the first connection's updates are sent out, leaving none for subsequent connections.

    We avoid this by just doing the whole process anew for each connection. Perhaps not the best solution but the simplest given that channels are used in many places and switching to something that doesn't empty on first pass (like a slice) would be a much larger change.

    Furthermore, updates are sent on the responses channel in serial as opposed to in parallel. This is to ensure order is preserved. Suppose two updates are sent in quick succession: we create two goroutines, each tasked with writing one update to the responses channel, but who knows which is actually executed first, so it's possible the latter update is written to the responses channel first, mixing up the order of imap updates. This change circumvents this issue, though still waits on all updates in separate goroutines so as to not block too much.

    opened by leakybits 10
  • Fetch on timeout blocks reading messages - suggested documentation change

    Fetch on timeout blocks reading messages - suggested documentation change

    Part of example I'm talking about:

    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)
    }
    

    If Client.Timeout is set and we're pulling a lot of emails, or doing a lot of processing on them, c.Fetch(...) can reach the Timeout. If so, it sends on done, and the loop is stuck waiting for a new message for infinity. My suggestion is closing the channel msg on timeout, because to my knowledge the only way around this issue for now is changing the loop to:

    loop:
    for {
      select {
      case err := <-done:
        // probably get `err` out of scope of function and check if outside
        break loop
      case msg := <-messages:
        select {
          case err := <-done:
            // probably get `err` out of scope of function and check if outside
            break loop
          default:
        }
        log.Println("* " + msg.Envelope.Subject)
      }
    }
    

    However because the messages channel is buffered in the example, we can skip some messages (I think?).

    Looking forward for your reply :)

    question client 
    opened by jakubdal 10
  • How to get the message content?

    How to get the message content?

    Hi! Maybe it is not the site to ask this, but i dont know where to ask this..

    I have been trying to get the message content, but i havent been able to do that.. Could someone tell if it is possible to do with this lib and how i could do that?

    Im coding a simple terminal client in Go (http://i.imgur.com/4pPaB3T.png), I need to show the messages, at least the HTML/Text messages..

    Thanks!

    invalid 
    opened by segura2010 10
  • =1.13 with Yahoo">

    "SELECT Command is not valid in this state" while using go >=1.13 with Yahoo

    When I use this package to get mail from aol or yahoo,get error message "SELECT Command is not valid in this state",then I tried different go version,1.12 works fine.

    opened by 0fv 9
  • parse email body error

    parse email body error

    i found something wrong like this:

    imap/client: 2022/11/03 21:07:59 error reading response: expected a space imap/client: 2022/11/03 21:07:59 error reading response: fields are not separated by a space imap/client: 2022/11/03 21:07:59 error reading response: atom contains forbidden char: " imap/client: 2022/11/03 21:07:59 error reading response: line doesn't end with a CR imap/client: 2022/11/03 21:07:59 error reading response: expected a space imap/client: 2022/11/03 21:07:59 error reading response: quoted string cannot contain backslash followed by a non-quoted-specials char imap/client: 2022/11/03 21:07:59 error reading response: expected a space imap/client: 2022/11/03 21:07:59 error reading response: fields are not separated by a space imap/client: 2022/11/03 21:07:59 error reading response: atom contains forbidden char: " imap/client: 2022/11/03 21:07:59 error reading response: line doesn't end with a CR imap/client: 2022/11/03 21:07:59 error reading response: expected a space imap/client: 2022/11/03 21:07:59 error reading response: quoted string cannot contain backslash followed by a non-quoted-specials char imap/client: 2022/11/03 21:07:59 error reading response: expected a space

    the mail body image

    image

    can you help me

    opened by liudijing07 1
  • Fetch feed nils into the channel

    Fetch feed nils into the channel

    seqset := new(imap.SeqSet)
    seqset.AddRange(mbox.UnseenSeqNum, mbox.Messages)
    errCh <- p.cl.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope}, rawMsgCh)
    

    will feed nils into the channel. How come?

    opened by ivanjaros 0
  • Reading emails

    Reading emails

    How am I supposed to actually get to the content of the email like actual text, attachments or embedded assets? That whole(cyclical) BodyStructure thing doesn't make any sense to me. Could you provide examples in the readme file?

    opened by ivanjaros 1
  • Allow using context.Context instead of a channel

    Allow using context.Context instead of a channel

    It would be great to have the possibility to use a context instead of a channel in function calls, since they pretty much do exactly what the stop channel is supposed to do as well. With network libraries it's more common to use a context which also allows for easy implementation of timeouts and cancellation that's passed through multiple child contexts.

    • breaking the API can be avoided by adding a *Ctx function which just accepts context.Context instead of a stop channel
    • code duplication can be avoided by just calling the *Ctx-function from the channel-function
    opened by mpldr 0
Releases(v1.2.1)
Owner
Simon Ser
I work on open-source software.
Simon Ser
A simple Go POP3 client library for connecting and reading mails from POP3 servers.

go-pop3 A simple Go POP3 client library for connecting and reading mails from POP3 servers. This is a full rewrite of TheCreeper/go-pop3 with bug fixe

Kailash Nadh 44 Dec 17, 2022
VMail - check the markup (HTML, CSS) of HTML email template compatibility with email clients

VMail - check the markup (HTML, CSS) of HTML email template compatibility with email clients Email clients use different rendering standards. This is

Alexey Vasiliev 22 Dec 17, 2022
Monitoring and automation for Open Source email servers, starting with Postfix.

Welcome to Lightmeter Control Center, the Open Source mailops monitoring application.

Lightmeter 88 Dec 19, 2022
Disposable webmail server (similar to Mailinator) with built in SMTP, POP3, RESTful servers; no DB required.

Disposable webmail server (similar to Mailinator) with built in SMTP, POP3, RESTful servers; no DB required.

Inbucket 1.1k Jan 1, 2023
Robust and flexible email library for Go

email Robust and flexible email library for Go Email for humans The email package is designed to be simple to use, but flexible enough so as not to be

Jordan Wright 2.2k Dec 30, 2022
:envelope: A streaming Go library for the Internet Message Format and mail messages

go-message A Go library for the Internet Message Format. It implements: RFC 5322: Internet Message Format RFC 2045, RFC 2046 and RFC 2047: Multipurpos

Simon Ser 288 Dec 26, 2022
:white_check_mark: A Go library for email verification without sending any emails.

email-verifier ✉️ A Go library for email verification without sending any emails. Features Email Address Validation: validates if a string contains a

AfterShip Ltd. 601 Dec 30, 2022
Go library for sending mail with the Mailgun API.

Mailgun with Go Go library for interacting with the Mailgun API. Usage package main import ( "context" "fmt" "log" "time" "githu

Mailgun Team 626 Dec 25, 2022
The Official Twilio SendGrid Led, Community Driven Golang API Library

NEW: Subscribe to email notifications for releases and breaking changes. The default branch name for this repository has been changed to main as of 07

Twilio SendGrid 872 Dec 15, 2022
✉️ A Go library for email verification without sending any emails.

email-verifier ✉️ A Go library for email verification without sending any emails. Features Email Address Validation: validates if a string contains a

AfterShip Ltd. 248 Jun 24, 2021
go-pst is a library for reading PST files (written in Go/Golang).

go-pst A library for reading PST files (written in Go/Golang). Introduction go-pst is a library for reading PST files (written in Go/Golang). The PFF

Mooij Technologies 131 Dec 29, 2022
Mail_sender - This library is for sending emails from your mail

Mail Sender This library is for sending emails from your mail Installation mail_

null 1 Dec 30, 2021
Mcopa - A library allows for parsing an email message into a more convenient form than the net/mail provides

Mail content parsing This library allows for parsing an email message into a mor

Mr Chen 0 Jan 1, 2022
Golang library for sending email using gmail credentials

library for sending email using gmail credentials

@Yassine Messaoudi 0 Jan 22, 2022
A simple CSS parser and inliner in Go

douceur A simple CSS parser and inliner in Golang. Parser is vaguely inspired by CSS Syntax Module Level 3 and corresponding JS parser. Inliner only p

Aymerick 226 Dec 12, 2022
Golang package for send email. Support keep alive connection, TLS and SSL. Easy for bulk SMTP.

Go Simple Mail The best way to send emails in Go with SMTP Keep Alive and Timeout for Connect and Send. IMPORTANT Examples in this README are for v2.2

Santiago De la Cruz 415 Jan 8, 2023
Using Mailchain, blockchain users can now send and receive rich-media HTML messages with attachments via a blockchain address.

Mailchain Introduction Mailchain enables blockchain-based email-like messaging with plain or rich text and attachment capabilities. Using blockchain p

Mailchain 133 Dec 28, 2022
Web and API based SMTP testing

MailHog Inspired by MailCatcher, easier to install. Download and run MailHog Configure your outgoing SMTP server View your outgoing email in a web UI

MailHog 11.3k Jan 4, 2023
High performance, self-hosted newsletter and mailing list manager with a modern dashboard. Single binary app.

listmonk is a standalone, self-hosted, newsletter and mailing list manager. It is fast, feature-rich, and packed into a single binary. It uses a Postg

Kailash Nadh 9.2k Dec 30, 2022