GithubHelp home page GithubHelp logo

imap-server's Introduction

go-IMAP Logo

This project is no longer active

Check out this much more active and mature project instead:

https://github.com/emersion/go-imap

Go IMAP Server

Travis CI Build Status

Barebones IMAP4rev1 server for golang. Designed for integration into a backend app to provide email client access.

Features a simple API for implementing your own email storage by implementing golang interfaces. Currently a dummy (in-memory) storage is included, with plans to include MySQL storage. This would make it simple to integrate into a backend application to allow users to drag-drop emails into the application, without messing around with maildir.

Although it would be possible to implement and plug in a maildir storage interface, that would defeat the purpose of this project and there are much better, tried and tested open source and commercial solutions that have been around for a long time (Courier, Dovecot etc). The goal of this project is to provide simple IMAP access to some kind of existing system without the overhead of installing a full-blown IMAP/POP3 mail server.

NOT READY FOR PRODUCTION USE

Currently only plaintext authentication is implemented. This is really bad, don't use it in any kind of environment where actual passwords or sensitive emails exists. Actually don't use it anywhere.

Supported Commands

Command Planned Implemented Tests
CAPABILITY
NOOP
LOGOUT
AUTHENTICATE
LOGIN
STARTTLS
EXAMINE
CREATE
DELETE
RENAME
SUBSCRIBE - -
UNSUBSCRIBE - -
LIST
LSUB
STATUS
APPEND
CHECK ?
CLOSE
EXPUNGE
SEARCH
FETCH
STORE
COPY
UID

imap-server's People

Contributors

guns avatar ishbir avatar jordwest 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

imap-server's Issues

Finish implementing DummyMailstore to provide full in-memory storage functionality

DummyMailstore currently returns fixed responses for some requests. It should be capable of storing emails in-memory. Currently some of this work is done, with a few sample emails stored in a slice. However functions like MessageSetBySequenceNumber still return hardcoded responses. DummyMailstore should be a full demonstration implementation of a mail storage.

Prevent data race between Listen() and Close()

The Go Race detector complains about a data race between Listen() and Close(). To illustrate, apply the following patch to create an example test case:

diff --git a/server_test.go b/server_test.go
index a242138..c50dd16 100644
--- a/server_test.go
+++ b/server_test.go
@@ -6,6 +6,7 @@ import (
        "os"
        "regexp"
        "testing"
+       "time"

        "github.com/jordwest/imap-server/conn"
        "github.com/jordwest/imap-server/mailstore"
@@ -288,3 +289,13 @@ func TestFetchFullMessageByUID(t *testing.T) {
        r.expect(t, " UID 11)")
        r.expect(t, "abcd.123 OK UID FETCH Completed")
 }
+
+func TestDataRace(t *testing.T) {
+       s := NewServer(mailstore.NewDummyMailstore())
+       s.Addr = "127.0.0.1:10143"
+       go func() {
+               s.ListenAndServe()
+       }()
+       time.Sleep(time.Millisecond)
+       s.Close()
+}

Then run go test -race -run=DataRace. The race detector should dump something like the following: (edited for readability)

==================
WARNING: DATA RACE
Read by goroutine 5:
  github.com/jordwest/imap-server.(*Server).Close()
      …/src/github.com/jordwest/imap-server/server.go:83 +0xcf
  github.com/jordwest/imap-server.TestDataRace()
      …/src/github.com/jordwest/imap-server/server_test.go:300 +0x2cd
…

Previous write by goroutine 6:
  github.com/jordwest/imap-server.(*Server).Listen()
      …/src/github.com/jordwest/imap-server/server.go:55 +0x481
  github.com/jordwest/imap-server.(*Server).ListenAndServe()
      …/src/github.com/jordwest/imap-server/server.go:36 +0x47
…
==================
==================
WARNING: DATA RACE
Read by goroutine 5:
  net.(*TCPListener).Close()
      …/go-1.4.2/src/net/tcpsock_posix.go:254 +0x4f
  github.com/jordwest/imap-server.(*Server).Close()
      …/src/github.com/jordwest/imap-server/server.go:86 +0x229
…

Previous write by goroutine 6:
  net.ListenTCP()
      …/go-1.4.2/src/net/tcpsock_posix.go:298 +0x4aa
  net.Listen()
      …/go-1.4.2/src/net/dial.go:266 +0x559
  github.com/jordwest/imap-server.(*Server).Listen()
      …/src/github.com/jordwest/imap-server/server.go:50 +0x307
  github.com/jordwest/imap-server.(*Server).ListenAndServe()
      …/src/github.com/jordwest/imap-server/server.go:36 +0x47
…
==================

As this project is young and there are many ways to address this (RWMutex, signaling over chans, etc), I am not submitting a pull request.

This is also not a critical race, since it happens on shutdown, but it does clutter the output of go test -race, which makes it harder to sort out application races.

Thanks again!

Implement `COPY` command

From the RFC:

Arguments: sequence set, mailbox name
Responses: no specific responses for this command
Result:
OK - copy completed
NO - copy error: can't copy those messages or to that name
BAD - command unknown or arguments invalid

The COPY command copies the specified message(s) to the end of the specified destination mailbox. The flags and internal date of the message(s) SHOULD be preserved, and the Recent flag SHOULD be set,
in the copy.

If the destination mailbox does not exist, a server SHOULD return an error. It SHOULD NOT automatically create the mailbox. Unless it is certain that the destination mailbox can not be created, the server MUST send the response code "[TRYCREATE]" as the prefix of the text of the tagged NO response. This gives a hint to the client that it can attempt a CREATE command and retry the COPY if the CREATE is successful.

If the COPY command is unsuccessful for any reason, server implementations MUST restore the destination mailbox to its state before the COPY attempt.

Example: C: A003 COPY 2:4 MEETING
S: A003 OK COPY completed

Proposal
Flags, headers and body of the message except the UID and sequence numbers MUST be preserved. The UID MUST change to the latest unassigned value for the given mailbox and sequence number will also have the latest value. The server MUST NOT automatically create the target mailbox.

Specs of example conversations with particular clients

Some mail clients do unusual things - eg Apple mail uses it's own flags which are currently not recognised by the server.

Create test specs of sample conversations for various mail clients based on observed conversations.

  • Apple Mail
  • Thunderbird
  • MS Outlook
  • Gmail

Project Status

Are you planning on adding other features like the mail store? or have you stopped working on the project?

Implement STARTTLS

This would reduce the impact of PLAIN-only authentication a bit.

Possible approach that I took in my toy server:

cert, err := tls.LoadX509KeyPair("/tmp/goimapd.crt", "/tmp/goimapd.key")
if err != nil {
  fmt.Printf("loadkeys: %s\n", err)
  textconn.PrintfLine("%s BAD Sorry, server-side problem loading certs.", tag, cmd)
  return
}
tlsconfig := &tls.Config{
  Certificates: []tls.Certificate{cert},
}

textconn.PrintfLine("%s OK STARTTLS commencing.", tag)
conn = tls.Server(conn, tlsconfig)
textconn = textproto.NewConn(conn)

It looks like a similar approach could be implemented in imap-server, too: the STARTTLS command could replace c.Rwc with an instance of tls.Server.

Support non system flags

STORE command is not recognised when Apple Mail tries to store it's own user defined flags, partly because of a $ character in the flag name.

Should support storage of user-defined flags if the Mailstore implementor chooses to.

Implement `CHECK` command

A CHECK should be the same as a NOOP, but also call a function on the Mailstore to prompt it to do any cleanup, refreshing, re-caching etc. as required

Automate testing and build process

Restarting server and running tests manually during development is tedious, set up fswatch for re-running tests and restarting server

  • Watch for changes, rerun go test
  • Watch for changes, build and restart demo server

Interpret IMAP message ID ranges and request the relevant messages

Create a MessageRangeSpecifier type which handles numeric identification of messages and distinguishes between single messages (UID 5, or 2), ranges of messages (UID 3:10, 15:17), or unbounded ranges (UID 6:*)

Create helper function that interprets the message UID/sequence number range and calls the relevant function on the Mailbox interface, returning the list of Messages.

cmdFetch expected literal parens around final argument to FETCH

When mutt attempts to fetch the body of a message, the client sends:

C: a0006 UID FETCH 10 BODY.PEEK[]

Which doesn't match the pattern in conn/commands.go:

    registerCommand("((?i)UID )?(?i:FETCH) ("+sequenceSet+") \\(([A-z0-9\\s\\(\\)\\[\\]\\.-]+)\\)", cmdFetch)

Do you have a client that has explicit parens around the 'BODY.PEEK[]' part? I'm not seeing anything to that effect in http://tools.ietf.org/html/rfc3501#section-6.4.5

PS, you may want to check out string literals specified with backticks instead of double-quotes when writing regexps. It saves on some of the backslash escaping.

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.