rust-imap: an IMAP client library for Rust
IMAP client library for Rust
At a glance
- What is it?
- The imap crate is a Rust client for the IMAP protocol, built around three types you move through in order, a client, an authenticated session and a connection. It is currently published as a 3.0.0 alpha, and the README asks for maintainers, which is the most important operational fact about it.
- Who is it for?
- imap fits a Rust developer building a mail client, a backup tool or a bot that needs to read a mailbox over IMAP with a typed API and either OpenSSL or rustls for TLS, and it does not fit a project that needs a stable release today. Before adopting it, read the version in your lockfile, because 3.0.0 is an alpha, and if you rely on the crate long term, weigh the README's request for maintainers against that risk.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 76 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Three types, in the order you use them
The imap crate lets you connect to and interact with servers that implement the IMAP protocol, RFC 3501 and various extensions. After authenticating with the server, IMAP lets you list, fetch and search for e-mails, and monitor mailboxes for changes, which is the full set of operations the protocol defines.
The API is organised as a progression, and the README is explicit about it. You construct a ClientBuilder, which gives you an unauthenticated Client. From there you use Client::login or Client::authenticate, for username and password or for challenge and response authentication respectively. Either one gives you an authenticated Session, and that is what lets you access the mailboxes at the server.
The three types are worth separating in your head, because each one has a different set of capabilities. The client can only authenticate. The session can select mailboxes, fetch, search and store. The connection is the lower level object underneath, which is what an extension such as IDLE sits on.
On maintenance, two facts stand out. The crate supports at least the latest three stable Rust releases, and possibly older ones, with the CI results linked for the detail. And the README carries a line in bold saying the crate is looking for maintainers, with a request to reach out. That is the kind of line a project only prints when the person who has been running it wants to hand it on, and it should shape how you weigh the rest of the release history.
The licence is a choice between two, which is a detail that matters more than it sounds and is covered further down.
The example shows the shape of every operation
The README's basic example is short enough to read in full, and it doubles as the documentation for how the crate expects to be used.
fn fetch_inbox_top() -> imap::error::Result<Option<String>> {
let client = imap::ClientBuilder::new("imap.example.com", 993).connect()?;
// the client we have here is unauthenticated.
// to do anything useful with the e-mails, we need to log in
let mut imap_session = client
.login("[email protected]", "password")
.map_err(|e| e.0)?;The connect call takes the host and the port, 993 in the example, which is the implicit TLS port. The login call returns something you have to unwrap, and the map_err with e.0 picks the error out of a tuple, which is a small sign that the login error type carries more than one thing.
Once you have a session, the operations read the way the protocol reads.
// we want to fetch the first email in the INBOX mailbox
imap_session.select("INBOX")?;
// fetch message number 1 in this mailbox, along with its RFC822 field.
// RFC 822 dictates the format of the body of e-mails
let messages = imap_session.fetch("1", "RFC822")?;
let message = if let Some(m) = messages.iter().next() {
m
} else {
return Ok(None);
};Selecting a mailbox is a separate step from fetching, and the fetch takes a sequence set and a set of data items, here RFC822 for the raw message. The body is then pulled out of the message and decoded as UTF-8.
// extract the message's body
let body = message.body().expect("message did not have a body!");
let body = std::str::from_utf8(body)
.expect("message was not valid utf-8")
.to_string();
// be nice to the server and log out
imap_session.logout()?;
Ok(Some(body))
}The final step is a logout, and the comment about being nice to the server is a reminder that an IMAP session is a long lived connection with real state on the other end, not a request and response API.
Two TLS paths, and a good reason to take the second
The crate's default feature set pulls in native_tls, which is the OpenSSL binding, and the README explains how to opt out of it for situations where using openssl becomes problematic.
The reason it gives is cross-compiling, and that is the honest one. A crate that links to the system OpenSSL is a crate that needs an OpenSSL on the target, matching the platform's expectations, and that is a recurring pain in cross-compiled Rust builds, particularly for static musl targets. Turning off the default feature and enabling the rustls-tls feature instead gives you a pure Rust TLS stack with no system library requirement.
The example file for that path is examples/rustls.rs, and the Cargo.toml shows the feature names: rustls-tls pulls in the rustls-connector crate, and the default feature set is native-tls. The example files are declared explicitly in the manifest, with the rustls example requiring the rustls-tls feature and the others requiring the default one, so a build with default features turned off simply skips the examples that need OpenSSL.
The dependency list shows the two choices side by side. native-tls at 0.2.2 is optional, and rustls-connector at 0.22.0 is optional, and each is enabled by a different feature.
For an adopter, the practical decision is short. If you build for a platform where OpenSSL is awkward or unavailable, take rustls. If you have an existing OpenSSL in your build and a reason to keep one TLS stack across your dependencies, take the default. What you should not do is assume the default is the only option, because the crate is explicit that it is not.
The examples directory is the feature map
The examples directory is where the crate documents its capabilities, and the file names are a good index of what it actually supports.
There is basic.rs for the ordinary case, gmail_oauth2.rs for authenticating against Gmail with OAuth2 rather than a password, idle.rs for the push extension that notifies the client of new mail, plaintext.rs for an unencrypted session, rustls.rs for the pure Rust TLS path, starttls.rs for upgrading a plain connection, and timeout.rs for setting timeouts on the connection. There is also a README.md in the directory and the main README points at it for more.
Two of those files answer questions that come up immediately. The OAuth2 example exists because password authentication is not what Gmail offers, and an IMAP client that cannot talk to the most common consumer mailbox is a niche tool. The IDLE example exists because the whole point of monitoring a mailbox for changes is that you do not want to poll.
The feature flags in the manifest line up with the examples and the tests. There is rustls-tls for the pure Rust TLS path, default for native-tls, test_helpers, described as exposing helpers in the imap::testing module to build response objects, and test-full-imap, described as activating the full integration tests when running against a more complete IMAP server.
That last flag is a hint about how the project is tested, which is the subject of the next section. The crate is not a thin wrapper around a protocol description; it has a testing story that assumes you can stand up a server.
Running the tests means standing up a real IMAP server
The README says that to run the integration tests you need GreenMail running, and that the easiest way is with Docker. The image is pulled with a specific tag and then run with the server options set through an environment variable, with a set of ports published for the various protocols the test suite exercises.
$ docker pull greenmail/standalone:1.6.15
$ docker run -it --rm -e GREENMAIL_OPTS='-Dgreenmail.setup.test.all -Dgreenmail.hostname=0.0.0.0 -Dgreenmail.auth.disabled -Dgreenmail.verbose' -p 3025:3025 -p 3110:3110 -p 3143:3143 -p 3465:3465 -p 3993:3993 -p 3995:3995 greenmail/standalone:1.6.15The options configure GreenMail with all the test setups, with a hostname of 0.0.0.0 so it is reachable from outside the container, with authentication disabled for the test run, and in verbose mode. The published ports cover the plaintext, TLS and IMAP ports the suite needs.
There is a second option, and the README recommends it for a specific reason. You can test against cyrus imapd, which it describes as a more complete IMAP implementation than GreenMail, since GreenMail does not support quotas and ACLs. The image is the outoforder cyrus-imapd-tester, run with its own port mapping.
$ docker pull outoforder/cyrus-imapd-tester
$ docker run -it --rm -p 3025:25 -p 3110:110 -p 3143:143 -p 3465:465 -p 3993:993 outoforder/cyrus-imapd-tester:latestThat is what the test-full-imap feature is for. The full integration tests need the server features that a minimal test server does not implement, and this is the shape of the testing effort a protocol library has to make: not unit tests of a parser, but a conversation with a real server.
The protocol layer is already a separate crate
The dependency list explains a lot about the architecture, because one entry in particular stands out.
imap-proto at 0.16.1 is the protocol implementation, and this crate sits on top of it. The imap crate is the client, the session and the connection, and the parsing and state machine of the protocol itself live in a separate crate. That separation is why the test suite can use helper functions in an imap::testing module to build response objects, and it is the difference between a crate you can use and a crate you can also extend at the protocol level.
Around that sit the usual parsing dependencies: nom at 7.1.0 with default features off, base64, chrono with default features off, regex, bufstream for buffered reading, lazy_static, and ouroboros at 0.18.0, which is the crate for self-referential structs, and a self-referential struct is exactly what a connection object with an internal buffer is.
The dev dependencies are small and tell you what the maintainers use to test: lettre for sending email, which means the test suite can generate real messages, rustls-connector for the alternative TLS path, and clap with the derive feature for the example binaries.
There is a small piece of craft in the manifest worth noting. A target-specific dependency table for cfg(any()) pins openssl and openssl-macros, with a comment saying it is there to make -Zminimal-versions work. That is the nightly tool for testing your dependencies against their lowest allowed versions, and adding an unreachable target is the trick for making the optional OpenSSL dependency visible to it. It is a two line trick that saves a class of surprise upgrades.
Dual licensed, alpha versioned, and asking for help
The licence is a choice, not a single grant. The crate is licensed under either the Apache License, Version 2.0, or the MIT license, at your option, and the contribution section says that unless you explicitly state otherwise, any contribution intentionally submitted for inclusion is dual licensed the same way, with no additional terms or conditions.
For a library that most users will pull in rather than vendor, the practical effect is the one that matters: you can depend on it in a proprietary product under either grant, and the dependency-status badge points at a repository that tracks the dependency tree.
The version is the thing to look at before you commit to it. The manifest says 3.0.0-alpha.15, and the repository has no GitHub releases, because the crate is published on crates.io rather than through GitHub tags. So the artefact you install is a 3.0.0 alpha, which in semver terms means the interface may still change before 3.0.0 is final. The last push was on 2026-08-08 and the repository is not archived.
That combination, a maintained repository, an alpha version and an explicit request for maintainers, is the profile of a project that works well today and may need attention later. The documentation makes the same point gently: the documentation within the crate borrows heavily from the various RFCs, but should not be considered a complete reference, and if anything is unclear you should follow the links to the RFCs embedded in the documentation and read the raw text there. For a protocol library, that is a reasonable and honest instruction, and it is also a sign that the crate is a layer over the specification rather than a replacement for it.
Editorial conclusion
imap fits a Rust developer building a mail client, a backup tool or a bot that needs to read a mailbox over IMAP with a typed API and either OpenSSL or rustls for TLS, and it does not fit a project that needs a stable release today. Before adopting it, read the version in your lockfile, because 3.0.0 is an alpha, and if you rely on the crate long term, weigh the README's request for maintainers against that risk.
Frequently asked questions
How do I connect to an IMAP server with the imap crate?
Build a ClientBuilder with the host and port and call connect, which gives you an unauthenticated Client. Then call Client::login for username and password or Client::authenticate for challenge and response, and you have a Session that can access the mailboxes.
Can I use rustls instead of native_tls with the imap crate?
Yes. The default feature set uses native_tls, and the README explains that for situations where openssl becomes problematic, such as cross-compiling, you can turn the default features off and enable the rustls-tls feature instead, which uses the pure Rust rustls crate. The examples/rustls.rs file has a working example.
What do I need to run the imap crate's integration tests?
A running IMAP server. The README says GreenMail is the easiest option and shows a Docker run with the test options and the required ports, and it also points at the cyrus-imapd-tester image, which is a more complete implementation supporting quotas and ACLs that GreenMail lacks.
Which Rust versions does the imap crate support?
It supports at least the latest three stable Rust releases, and the README says possibly even older ones, with the CI results linked for the details. The crate is also published as 3.0.0-alpha.15, so the 3.0 line is still in alpha.
What licence does the imap crate use?
It is licensed under either the Apache License, Version 2.0 or the MIT license, at your option, with both licence files in the repository. Contributions are dual licensed the same way unless you state otherwise.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/jonhoo-rust-imap)Was this useful?