GithubHelp home page GithubHelp logo

go-imap's Introduction

go-imap's People

Contributors

mxk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-imap's Issues

How to authenticate with this capabilities?

CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE STARTTLS LOGINDISABLED

I can't use Login function. And I don't understand how to use Authenticate

Thunderbird connects to server by STARTTLS using login and password w/o encryption.

Please, help me to connect to my imap server.

Including an IMAP server

There is IMAP server implementation here (still very much WIP): https://github.com/alienscience/imapsrv

It's not functional yet, but there is a lot of enthusiasm of making this server work and collaborations are slowly coming in. I also use go-imap. So I thought: Wouldn't it be convenient to have both the client and the server in the same repo or package? A heterogenous API for both the client and the server would be very nice for people looking for an imap implementation in golang.

Another advantage would be: testing! Instead of using a mock (the case now), it would be nicer to bootstrap a server that listens on a real port and do the testing.

Not to say that there will be more people testing out/contributing to the client/server.

Before opening up this issue I talked to the author of the server and he is not opposed to the idea of merging, but doesn't have the time to do it. I do have the time though.

What do you think? Can we work together?

BODYSTRUCTURE

How do I parse BODYSTRUCTURE, as I want to find the attachments..

Using

cmd, err := imap.Wait( client.UIDFetch(uidlist, "FLAGS", "INTERNALDATE", "RFC822.SIZE", "RFC822.HEADER", "BODYSTRUCTURE") )

and then,

for _, bsv := range imap.AsList(rsp.MessageInfo().Attrs["BODYSTRUCTURE"]) {
    if  imap.TypeOf(bsv) == imap.List {
        vvv := imap.AsList(bsv)
        fmt.Println(" ==", vvv)
    }
}

Prints

 == [["text" "plain" ["charset" "UTF-8"] <nil> <nil> "7bit" 34 1 <nil> <nil> <nil> <nil>] ["text" "html" ["charset" "UTF-8"] <nil> <nil> "7bit" 55 1 <nil> <nil> <nil> <nil>] "alternative" ["boundary" "001a1145bb103402220524805d18"] <nil> <nil> <nil>]

 == ["application" "pdf" ["name" "White Paper - On-train fiber optic connectivity.pdf"] <nil> <nil> "base64" 1718302 <nil> ["attachment" ["filename" "White Paper - On-train fiber optic connectivity.pdf"]] <nil> <nil>]

 == ["application" "pdf" ["name" "Interim Report 23.11.14.pdf"] <nil> <nil> "base64" 447908 <nil> ["attachment" ["filename" "Interim Report 23.11.14.pdf"]] <nil> <nil>]

 == ["image" "jpeg" ["name" "ana.jpeg"] <nil> <nil> "base64" 882306 <nil> ["attachment" ["filename" "ana.jpeg"]] <nil> <nil>]

 == ["boundary" "001a1145bb103402290524805d1a"]

Support thirdparty logger through interface

Hi, I am having trouble using a thirdpary logger like logrus. The SetLogger() only accept std logger. It might be better if it accept an interface which contains the compatible API with std logger. Thank you.

Repo renaming

Currently in order to import this package one needs to do this:

import "github.com/mxk/go-imap/imap"

Imho this is a bit ugly and doesn't work well with the go get command as it expects the package to be in the root of the repo. I suggest renaming the package name to a nicer:

import "github.com/mxk/imap"

Dropping 'go-' from the name might be a bit confusing for people looking for imap libs from other languages, but I think that confusion will be quickly removed as soon as they see that it's written in go.

Andrew Gerrand had a similar suggestion in his talk here: http://talks.golang.org/2014/names.slide#17

Should support SEARCH response with trailing whitespace?

Hi,

While testing the client with different servers, I found that Yahoo IMAP is returning an unexpected trailing whitespace on the SEARCH results, e.g: "* SEARCH 61 62 63 "
I'm far from an IMAP expert, so I wanted to ask: could this case be supported?

A test case to reproduce it:

--- a/imap/reader_test.go
+++ b/imap/reader_test.go
@@ -469,6 +469,9 @@ func TestReaderParse(t *testing.T) {
                {`* SEARCH 2 84 882`,
                        &Response{Tag: "*", Type: Data, Label: "SEARCH", Fields: []Field{"SEARCH", uint32(2), uint32(84), uint32(882)}}},

+               {`* SEARCH 2 84 882 `,
+                       &Response{Tag: "*", Type: Data, Label: "SEARCH", Fields: []Field{"SEARCH", uint32(2), uint32(84), uint32(882)}}},
+
                // Page 66
                {`* OK [ALERT] System shutdown in 10 minutes`,
                        &Response{Tag: "*", Type: Status, Status: OK, Info: "System shutdown in 10 minutes", Label: "ALERT", Fields: []Field{"ALERT"}}},

I still getting familiar with the code (reader.go) but will try to get a patch with a fix.

How do you set mailbox flags

I have written a Go program that uses mxk/go-imap to copy an IMAP email account
to another IMAP email account and to compare two IMAP accounts. It all works fine,
including the copying of message flags and the comparing of mailbox flags.

However, I can't find anything in the mxk/go-imap interface that enables me to WRITE
mailbox flags. I can read them by examining mailboxinfo.attrs which I can obtain
by calling func (rsp *Response) MailboxInfo() *MailboxInfo but I can't see anything
in the interface that allows me to write them. The method
func (c *Client) Create(mbox string) (cmd *Command, err error)
does not allow me to specify a set of flags, and there seems to be no additional
method to allow me to do so.

I would really appreciate some help here because this is the last missing piece
for an IMAP copy program that is otherwise copying and comparing everything
else in an IMAP account perfectly. The mailbox flags is the only thing it doesn't
copy correctly.

Ross Williams

Allow for custom handlers in client

Not sure how to categorise this, but currently the IMAP client is spewing all kinds of warnings like such:

imap/client: 2016/10/21 17:31:52 response has not been handled: &{* OK HIGHESTMODSEQ [394056] Highest}

Maybe I'm wrong, but I don't seem to be able to specify custom handlers in the client; having such an option would allow me to catch expected "unhandled" messages while preserving the capability to warn if an unexpected unhandled response arises.

My server is running dovecot2 from Debian (jessie) by the way.

Can't delete Message via UID

Hi,

I've tried all day to delete messages. No matter what I try, it just doesn't work.

My code in its entirety that deals with looping through the mailbox.

I want to be able to select WHICH UIDs I delete. That's all.

Thanks

for cmd.InProgress() {
        // Wait for the next response (no timeout)
        c.Recv(-1)

        // Process command data
        for _, rsp = range cmd.Data {
            uid := imap.AsNumber(rsp.MessageInfo().UID)
            //msg_no := imap.AsNumber(rsp.MessageInfo().Seq)
            header := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.HEADER"])
            body := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.TEXT"])

            if msg, _ := mail.ReadMessage(bytes.NewReader(header)); msg != nil {
                xheaders := make(map[string]string)

                // Add X- Headers
                r := regexp.MustCompile("^X-(.*): (.*)")
                s_body := strings.Split(string(body), "\n")

                for _, value := range s_body {
                    res := r.FindAllString(value, -1)

                    if len(res) > 0 {
                        s_res := strings.Split(res[0], ": ")

                        h_key := s_res[0]
                        h_value := s_res[1]

                        // Fix up
                        h_key = strings.Replace(h_key, "[", "", -1)
                        h_value = strings.Replace(h_value, "\r", "", -1)

                        xheaders[h_key] = h_value
                    }
                }

                // Remove non Mailer-* headers
                for key, _ := range xheaders {
                    if !strings.Contains(key, "X-Mailer") {
                        delete(xheaders, key)
                    }
                }

                // Fix Date
                date := msg.Header.Get("Date")
                s_date := strings.Split(date, " (")

                mail := &Mail{
                    Uid:      uid,
                    Xheaders: xheaders,
                    From:     msg.Header.Get("FROM"),
                    Subject:  msg.Header.Get("Subject"),
                    Body:     string(body),
                    Time:     s_date[0],
                }

                res := process_message(mailbox_type, *mail)

                if res {
                    delset, _ := imap.NewSeqSet(string(uid))
                    c.UIDStore(delset, "+FLAGS.SILENT", imap.NewFlagSet(`\Deleted`))
                }

                fmt.Println(uid)
            }
        }

        c.Expunge(nil)

        cmd.Data = nil

        // Process unilateral server data
        /*for _, rsp = range c.Data {
            fmt.Println("Server data:", rsp)
        }*/
        c.Data = nil
    }

Invalid memory address or nil pointer dereference

I'm trying to get the library to connect to a Gmail server using some of the example code provided at http://godoc.org/github.com/mxk/go-imap/imap. I've stripped out all unnecessary code in order to just connect to a server. This is my example code:

package main

import "code.google.com/p/go-imap/go1/imap"
import "fmt"

func main() {
  client, _ := imap.Dial("imap.gmail.com")

  fmt.Println("Server says hello:", client.Data[0].Info)

  if client.State() == imap.Login {
    client.Login("<example e-mail>", "<example password>")
  }
}

For the sake of clarity and isolating the problem, I've removed the deferring of the logout and so on. Running the above code results in this error:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x21bc]

goroutine 16 [running]:
runtime.panic(0x22adc0, 0x3a24a4)
    /usr/local/Cellar/go/1.3.1/libexec/src/pkg/runtime/panic.c:279 +0xf5
main.main()
    /Users/kasper/go/src/test/imap.go:9 +0x1bc

goroutine 19 [finalizer wait]:
runtime.park(0x145d0, 0x3a5a60, 0x3a4569)
    /usr/local/Cellar/go/1.3.1/libexec/src/pkg/runtime/proc.c:1369 +0x89
runtime.parkunlock(0x3a5a60, 0x3a4569)
    /usr/local/Cellar/go/1.3.1/libexec/src/pkg/runtime/proc.c:1385 +0x3b
runfinq()
    /usr/local/Cellar/go/1.3.1/libexec/src/pkg/runtime/mgc0.c:2644 +0xcf
runtime.goexit()
    /usr/local/Cellar/go/1.3.1/libexec/src/pkg/runtime/proc.c:1445

goroutine 17 [syscall]:
runtime.goexit()
    /usr/local/Cellar/go/1.3.1/libexec/src/pkg/runtime/proc.c:1445
exit status 2

I've seen this problem referenced elsewhere, but I've been unable to find a solution. Any suggestions as to what might be wrong?

read: connection reset by peer

I'm having issues connecting to mail.privateemail.com, I'm using the same configuration that mbsync and others use to retrieve email from the server and mbsync works without issues.

The relevant code starts here, hosted on Gitlab

The configuration file looks like this:

{
  "host": "mail.privateemail.com",
  "port": 993,
  "tls": true,
  "tlsOptions": { "rejectUnauthorized": true },
  "username": "[email protected]",
  "password": "mysecretpassword",
  "onNewMail": "/home/jorge/.local/bin/getmail.sh",
  "onNewMailPost": "emacsclient  -e '(mu4e-update-index)'",
  "boxes": ["INBOX"],
  "__comment": "touch"
}

Please note: My code ignores tlsOptions at the moment.

This is the output my application shows:

[imap] 21:29:49 Connected to 198.54.122.60:993 (Tag=KFRUH)
[imap] 21:30:00 S:  (read tcp 192.168.0.10:59164->198.54.122.60:993: read: connection reset by peer)
[imap] 21:30:00 Close reason: protocol error
[imap] 21:30:00 Connection closing (flush=false)
[imap] 21:30:00 Greeting error: read tcp 192.168.0.10:59164->198.54.122.60:993: read: connection reset by peer
2017/08/22 21:30:00 [ERR] Cannot connect to mail.privateemail.com:993: read tcp 192.168.0.10:59164->198.54.122.60:993: read: connection reset by peer

This is the output if I use a non-encrypted port, basically it works fine:

[imap] 21:31:44 Connected to 198.54.122.60:143 (Tag=KTLIV)
[imap] 21:31:45 S: * OK [CAPABILITY STARTTLS IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN AUTH=LOGIN] Dovecot ready.
[imap] 21:31:45 Server greeting: Dovecot ready.
Server says hello: Dovecot ready.
[imap] 21:31:45 C: KTLIV1 STARTTLS
[imap] 21:31:45 S: KTLIV1 OK Begin TLS negotiation now
[imap] 21:31:45 TLS encryption enabled (cipher=0xC030)
[imap] 21:31:45 C: KTLIV2 CAPABILITY
[imap] 21:31:45 S: * CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN AUTH=LOGIN
[imap] 21:31:45 S: KTLIV2 OK Pre-login capabilities listed, post-login capabilities have more.
[imap] 21:31:45 C: KTLIV3 LOGIN "[email protected]" "mysecretpassword"
[imap] 21:31:46 S: * CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=O
RDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARC
HRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE NOTIFY METADATA QUOTA                                                                         
[imap] 21:31:46 S: KTLIV3 OK Logged in
[imap] 21:31:46 C: KTLIV4 CAPABILITY
[imap] 21:31:46 S: * CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=O
RDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARC
HRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE NOTIFY METADATA QUOTA                                                                         
[imap] 21:31:46 S: KTLIV4 OK Capability completed (0.001 + 0.000 secs).
[imap] 21:31:46 C: KTLIV5 EXAMINE "INBOX"
[imap] 21:31:46 S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
[imap] 21:31:46 S: * OK [PERMANENTFLAGS ()] Read-only mailbox.
[imap] 21:31:46 S: * 2 EXISTS
[imap] 21:31:46 S: * 0 RECENT
[imap] 21:31:46 S: * OK [UNSEEN 2] First unseen.
[imap] 21:31:46 S: * OK [UIDVALIDITY 1500785846] UIDs valid
[imap] 21:31:46 S: * OK [UIDNEXT 364] Predicted next UID
[imap] 21:31:46 S: * OK [HIGHESTMODSEQ 1026] Highest
[imap] 21:31:46 S: KTLIV5 OK [READ-ONLY] Examine completed (0.006 + 0.000 + 0.005 secs).
[imap] 21:31:46 C: KTLIV6 IDLE
[imap] 21:31:46 S: + idling

Debugging idea: log progress of a data transfer

It would be useful for debugging to have the built-in debug log display the progress of a data literal send over time, assuming this is even possible. Perhaps only in an imap.Wait() call?

Example, when doing a UID FETCH something BODY[] with imap.LogAll enabled, instead of:

[imap] 13:20:20 S:  BODY[] {2120811}
[imap] 13:20:20 S: literal 111 bytes
[imap] 13:20:37 S: literal 2048 bytes
[imap] 13:21:34 S: literal 2048 bytes
[imap] 13:21:34 S: literal 2048 bytes
[imap] 13:21:34 S: literal 496 bytes
[imap] 13:21:34 S: literal 2048 bytes
[imap] 13:21:34 S: literal 2048 bytes

it would say something like

[imap] 13:20:20 S:  BODY[] {2120811}
[imap] 13:20:20 S: literal 111 bytes (111/2120811 bytes received)
[imap] 13:20:37 S: literal 2048 bytes (2159/2120811 bytes received)
[imap] 13:21:34 S: literal 2048 bytes (4207/2120811 bytes received)
[imap] 13:21:34 S: literal 2048 bytes (6255/2120811 bytes received)
[imap] 13:21:34 S: literal 496 bytes (6751/2120811 bytes received)
[imap] 13:21:34 S: literal 2048 bytes (8799/2120811 bytes received)
[imap] 13:21:34 S: literal 2048 bytes (10847/2120811 bytes received)

Is this possible? I'm not familiar enough with either IMAP or the package's source to tell myself. Thanks!

IDLE can't be interrupted using idleTerm()

Here's a sample code:

  idleChannel := make(chan int8)
  for {
    interrupted := false
    log.Printf("before idle\n");
    _, idleErr := c.Idle()
    log.Printf("after idle %v\n", idling);

    go func() {
      log.Printf("receiving data\n");
      c.Recv(-1)
      log.Printf("received data xx\n");
      if (!interrupted) {
        idleChannel <- 1 // received
      }
    }()

    log.Printf("select")
    timeout := time.After(2 * time.Second)
        select {
    case value := <- idleChannel:
      if (value == 1) {
        log.Printf("received data %v\n", c.Data);
      }
      c.IdleTerm()
    case timeValue := <- timeout:
      log.Printf("interrupted %v\n", timeValue)
      interrupted = true
      c.IdleTerm()
      log.Printf("interrupted done\n")
    }
    log.Printf("out of select")
  }

When calling, c.IdleTerm() it will interrupt IDLE but the execution flow will be blocked at c.IdleTerm().
The log "interrupted done" won't show.

@iragsdale has a suggestion of fix here:
boxer@796926b

And it seems like it's the right thing to do:

  • don't try to read and parse the response in c.IdleTerm()
  • let c.Recv() do the receiving and parsing work

STORE command returning unexpected status using Exchange

I'm trying to get store of \Deleted flag working with Microsoft Exchange. I've adopted the code from demo1, I get back logging like this:

--- STORE ---
imap: unexpected completion status ("PQZGK7 NO Command received in Invalid state.")

Logout reason: Microsoft Exchange Server 2010 IMAP4 server signing off.
Close reason: end of stream
Connection closing (flush=false)

I've tried browsing the source code and I'm not getting very far with that.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.