IMAP4rev1 library

OCaml-IMAP is a fully featured OCaml client library for the IMAP4rev1
protocol. It consists of two parts. Firstly, there is a low-level API that
follows the specification closely and is completely independent of any
particular I/O, error handling, or control flow mechanisms. Secondly, there is
a high-level API built on top of the low-level one and Lwt that liberates
the user from dealing with much of the low-level details necessary to interact
with an IMAP server. Additionally it can automatically open more than one
connection in the background for greater performance. Other concucurrency
frameworks (such as Async) could be supported with not too much effort.

This is a preliminary release.

The full IMAP4rev1 protocol is supported in addition of some common extensions
(see below).

Contact: Nicolas Ojeda Bar


This library (particularly the interface) has been greatly influenced by

Requirements and installation


opam install ssl lwt imap

UIDs and Sequence numbers

Emails in a mail folder are numbered in an increasing manner from one upwards
(in order of arrival). The number corresponding to each message is called its
sequence number.

These numbers are not very useful because they are not intrinsic to the message.
For example, if the first message in the mail folder is deleted the number of
every other message in the folder gets decreased by one. Since many clients
may be accessing the mail folder at the same time, if you delete a message by
specifying its sequence number you may end up deleting the wrong message.
Clearly this is not very convenient. See below for how to deal with this.

In the high-level API there is only function that uses sequence numbers:

A better way to specify messages in an IMAP folder is to use unique
identification numbers
(from now on, UIDs). As the name implies, they are
supposed to be unique (but only within the folder the message is residing in).
More importantly they are intrinsic to the message. This means that no matter
what operation you do, a message will never change its UID (actually I am lying
a little here. If you want to know how find out about UIDVALIDITY).

One downside of UIDs is that they are only valid within a folder, so if you copy
an email to another folder there is no reliable way in the base IMAP protocol to
know what is the UID of the copy. Similarly if you upload (append) a new
message to the folder. There is a common extension to the protocol
(UIDPLUS) that gives you this information.

Most of the high level API deals with UIDs and sets of UIDs to find, fetch, and
modify messages.


All the examples below are done using the utop toplevel using the high-level
Lwt API.

Setup the toplevel

# #require "imap.lwt";;
# #require "";;
# open ImapLwt;;

Creating and Authenticating a Session

# let s = create_session ~host:"" ~username:"myuser" ~password:"mysecret";;
val s : session = <abstr>

Note that you never need to connect or authenticate explicitly. It is all
taken care of automatically. The session will automatically disconnect
after a period of inactivity (default: 1min) and then reconnect as needed.

To terminate the session gracefully, use

# logout s;;
- : unit = ()

Finding out message UIDs

Before one can do anything with a message using IMAP it is often necessary to
know its UID. The easiest way to do this is use the imap SEARCH command.
In the library this is done with `search command':

# #show_val search;;
val search : session -> folder:string -> key:search_key -> UidSet.t Lwt.t

The only interesting argument is labeled key and specifies which messages one
is looking for. For example to find all messages from an email
"" in the INBOX folder, one can simply do:

# lwt uids = search s ~folder:"INBOX" ~key:(From "")
val uids : UidSet.t = <abstr>

Fetching message data

Once one has the UIDs of the messages one intends to manipulate, the actual
fetching of data is done with the function fetch_messages_by_uid. The following
will find out the size of all messages in INBOX.

# lwt msgs = fetch_messages_by_uid s ~folder:"inbox" ~request:[Size] ~uids:UidSet.all;;
val msgs : message list = [ ... ]

This function returns a list of message values. The message type is given by

# #show_type message;;
type message = {
  uid : UidSet.elt;
  size : int;
  mod_seq_value : Modseq.t;
  gmail_labels : string list;
  gmail_message_id : Gmsgid.t;
  gmail_thread_id : Gthrid.t;
  flags : message_flag list;
  internal_date : float;
  main_part : part option;
  envelope : envelope option;

Only the fields that were actually requested should be used (in this case, only
size should be used). The different information that can be requested like
this is specified by the type messages_request_type:

# #show_type messages_request_type;;
type messages_request_kind =
| Flags
| Headers
| Structure
| InternalDate
| FullHeaders
| HeaderSubject
| GmailLabels
| GmailMessageID
| GmailThreadID
| ExtraHeaders of string list
| Size

To fetch the full message corresponding to a given UID, one can use fetch_message_by_uid:

# fetch_message_by_uid s ~uid;;
- : string = "..."

Changing flags and labels

Suppose we have an UID set uids and we want to label (in the Gmail sense) the
corresponding messages with label MyLabel. It is very easy.

# add_labels s ~folder:"INBOX" ~uids ~labels:["MyLabel"]

There is also remove_labels to remove a label, and set_labels to completely
replace the existing labels.

There is a parallel set of function for flags: add_flags, remove_flags, set_flags that
allow to modify the flags of a message.

# #show_type message_flag;;
type message_flag = Seen | Answered | Flagged | Deleted | Draft | MDNSent | Forwarded | SubmitPending | Submitted


To see a debug trace of everything that gets sent and received, set the Lwt log level to Debug.

# Lwt_log.Section.set_level Lwt_log.Sectin.main Lwt_log.Debug;;

NOTE: This will print your username and password on the terminal.

Supported IMAP extensions


Any comments/suggestions/bug reports/etc are greatly appreciated! Please email me.

28 Sep 2014
Reverse Dependencies