Skip to content

Commit

Permalink
A significant documentation upgrade
Browse files Browse the repository at this point in the history
Fixes #77.
Touches on #74.
Fixes #70 through documentation (I think?)
Fixes #62.
  • Loading branch information
jonhoo committed Nov 21, 2018
1 parent bddfab3 commit f83742d
Show file tree
Hide file tree
Showing 17 changed files with 1,106 additions and 486 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]

name = "imap"
version = "0.8.1"
version = "0.9.0"
authors = ["Matt McCoy <[email protected]>",
"Jon Gjengset <[email protected]>"]
documentation = "https://docs.rs/imap/"
Expand Down
83 changes: 43 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,54 +10,57 @@
[![Build Status](https://ci.appveyor.com/api/projects/status/github/mattnenterprise/rust-imap?svg=true)](https://ci.appveyor.com/api/projects/status/github/mattnenterprise/rust-imap)
[![Coverage Status](https://coveralls.io/repos/github/mattnenterprise/rust-imap/badge.svg?branch=master)](https://coveralls.io/github/mattnenterprise/rust-imap?branch=master)

IMAP client bindings for Rust.
This crate lets you connect to and interact with servers that implement the IMAP protocol ([RFC
3501](https://tools.ietf.org/html/rfc3501)). After authenticating with the server, IMAP lets
you list, fetch, and search for e-mails, as well as monitor mailboxes for changes.

## Usage
To connect, use the `imap::connect` function. This gives you an unauthenticated `imap::Client`. You can
then use `Client::login` or `Client::authenticate` to perform username/password or
challenge/response authentication respectively. This in turn gives you an authenticated
`Session`, which lets you access the mailboxes at the server.

Here is a basic example of using the client.
See the `examples/` directory for more examples.
Below is a basic client example. See the `examples/` directory for more.

```rust
extern crate imap;
extern crate native_tls;

// To connect to the gmail IMAP server with this you will need to allow unsecure apps access.
// See: https://support.google.com/accounts/answer/6010255?hl=en
// Look at the `examples/gmail_oauth2.rs` for how to connect to gmail securely.
fn main() {
let domain = "imap.gmail.com";
let port = 993;
let socket_addr = (domain, port);
let ssl_connector = native_tls::TlsConnector::builder().build().unwrap();
let mut imap_socket = Client::secure_connect(socket_addr, domain, &ssl_connector).unwrap();

imap_socket.login("username", "password").unwrap();

match imap_socket.capabilities() {
Ok(capabilities) => {
for capability in capabilities.iter() {
println!("{}", capability);
}
}
Err(e) => println!("Error parsing capabilities: {}", e),
fn fetch_inbox_top() -> imap::error::Result<Option<String>> {
let domain = "imap.example.com";
let tls = native_tls::TlsConnector::builder().build().unwrap();

// we pass in the domain twice to check that the server's TLS
// certificate is valid for the domain we're connecting to.
let client = imap::connect((domain, 993), domain, &tls).unwrap();

// 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)?;

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

match imap_socket.select("INBOX") {
Ok(mailbox) => {
println!("{}", mailbox);
}
Err(e) => println!("Error selecting INBOX: {}", e),
};
// extract the message's body
let body = message.rfc822().expect("message did not have a body!");
let body = std::str::from_utf8(body)
.expect("message was not valid utf-8")
.to_string();

match imap_socket.fetch("2", "body[text]") {
Ok(messages) => {
for message in messages.iter() {
print!("{:?}", message);
}
}
Err(e) => println!("Error Fetching email 2: {}", e),
};
// be nice to the server and log out
imap_session.logout()?;

imap_socket.logout().unwrap();
Ok(Some(body))
}
```

Expand All @@ -71,5 +74,5 @@ at your option.
## Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.
for inclusion in the work by you, as defined in the Apache-2.0 license, shall
be dual licensed as above, without any additional terms or conditions.
4 changes: 2 additions & 2 deletions README.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ at your option.
## Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.
for inclusion in the work by you, as defined in the Apache-2.0 license, shall
be dual licensed as above, without any additional terms or conditions.
73 changes: 37 additions & 36 deletions examples/basic.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,47 @@
extern crate imap;
extern crate native_tls;

use native_tls::TlsConnector;

// To connect to the gmail IMAP server with this you will need to allow unsecure apps access.
// See: https://support.google.com/accounts/answer/6010255?hl=en
// Look at the gmail_oauth2.rs example on how to connect to a gmail server securely.
fn main() {
let domain = "imap.gmail.com";
let port = 993;
let socket_addr = (domain, port);
let ssl_connector = TlsConnector::builder().build().unwrap();
let client = imap::client::secure_connect(socket_addr, domain, &ssl_connector).unwrap();

let mut imap_session = match client.login("username", "password") {
Ok(c) => c,
Err((e, _unauth_client)) => {
eprintln!("failed to login: {}", e);
return;
}
};
// To connect to the gmail IMAP server with this you will need to allow unsecure apps access.
// See: https://support.google.com/accounts/answer/6010255?hl=en
// Look at the gmail_oauth2.rs example on how to connect to a gmail server securely.
fetch_inbox_top().unwrap();
}

match imap_session.capabilities() {
Ok(capabilities) => for capability in capabilities.iter() {
println!("{}", capability);
},
Err(e) => println!("Error parsing capability: {}", e),
};
fn fetch_inbox_top() -> imap::error::Result<Option<String>> {
let domain = "imap.example.com";
let tls = native_tls::TlsConnector::builder().build().unwrap();

match imap_session.select("INBOX") {
Ok(mailbox) => {
println!("{}", mailbox);
}
Err(e) => println!("Error selecting INBOX: {}", e),
};
// we pass in the domain twice to check that the server's TLS
// certificate is valid for the domain we're connecting to.
let client = imap::connect((domain, 993), domain, &tls).unwrap();

match imap_session.fetch("2", "body[text]") {
Ok(msgs) => for msg in &msgs {
print!("{:?}", msg);
},
Err(e) => println!("Error Fetching email 2: {}", e),
// 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)?;

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

imap_session.logout().unwrap();
// extract the message's body
let body = message.rfc822().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))
}
13 changes: 7 additions & 6 deletions examples/gmail_oauth2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ extern crate base64;
extern crate imap;
extern crate native_tls;

use imap::authenticator::Authenticator;
use native_tls::TlsConnector;

struct GmailOAuth2 {
user: String,
access_token: String,
}

impl Authenticator for GmailOAuth2 {
impl imap::Authenticator for GmailOAuth2 {
type Response = String;
#[allow(unused_variables)]
fn process(&self, data: &[u8]) -> Self::Response {
Expand All @@ -30,7 +29,7 @@ fn main() {
let port = 993;
let socket_addr = (domain, port);
let ssl_connector = TlsConnector::builder().build().unwrap();
let client = imap::client::secure_connect(socket_addr, domain, &ssl_connector).unwrap();
let client = imap::connect(socket_addr, domain, &ssl_connector).unwrap();

let mut imap_session = match client.authenticate("XOAUTH2", gmail_auth) {
Ok(c) => c,
Expand All @@ -46,9 +45,11 @@ fn main() {
};

match imap_session.fetch("2", "body[text]") {
Ok(msgs) => for msg in &msgs {
print!("{:?}", msg);
},
Ok(msgs) => {
for msg in &msgs {
print!("{:?}", msg);
}
}
Err(e) => println!("Error Fetching email 2: {}", e),
};

Expand Down
20 changes: 7 additions & 13 deletions src/authenticator.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
/// This will allow plugable authentication mechanisms.
///
/// This trait is used by `Client::authenticate` to [authenticate
/// using SASL](https://tools.ietf.org/html/rfc3501#section-6.2.2).
/// This trait allows for pluggable authentication schemes. It is used by `Client::authenticate` to
/// [authenticate using SASL](https://tools.ietf.org/html/rfc3501#section-6.2.2).
pub trait Authenticator {
/// Type of the response to the challenge. This will usually be a
/// `Vec<u8>` or `String`. It must not be Base64 encoded: the
/// library will do it.
/// The type of the response to the challenge. This will usually be a `Vec<u8>` or `String`.
type Response: AsRef<[u8]>;
/// For each server challenge is passed to `process`. The library
/// has already decoded the Base64 string into bytes.
///
/// The `process` function should return its response, not Base64
/// encoded: the library will do it.
fn process(&self, &[u8]) -> Self::Response;

/// Each base64-decoded server challenge is passed to `process`.
/// The returned byte-string is base64-encoded and then sent back to the server.
fn process(&self, challenge: &[u8]) -> Self::Response;
}
Loading

0 comments on commit f83742d

Please sign in to comment.