Merge pull request #138 from brycefisher/feat/rustls-support

(feat) Provide example integration with Rustls crate
This commit is contained in:
Jon Gjengset 2019-09-18 12:23:31 -04:00 committed by GitHub
commit c8288ea19b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 70 additions and 2 deletions

View file

@ -34,3 +34,4 @@ lazy_static = "1.4"
[dev-dependencies] [dev-dependencies]
lettre = "0.9" lettre = "0.9"
lettre_email = "0.9" lettre_email = "0.9"
rustls-connector = "0.8.0"

View file

@ -9,12 +9,12 @@ stages:
# This represents the minimum Rust version supported. # This represents the minimum Rust version supported.
# Tests are not run as tests may require newer versions of rust. # Tests are not run as tests may require newer versions of rust.
- stage: msrv - stage: msrv
displayName: "Minimum supported Rust version: 1.32.0" displayName: "Minimum supported Rust version: 1.36.0"
dependsOn: [] dependsOn: []
jobs: jobs:
- template: azure/cargo-check.yml@templates - template: azure/cargo-check.yml@templates
parameters: parameters:
rust: 1.32.0 rust: 1.36.0
- stage: test - stage: test
displayName: Test suite displayName: Test suite
dependsOn: check dependsOn: check

View file

@ -6,3 +6,4 @@ This directory contains examples of working with the IMAP client.
Examples: Examples:
* basic - This is a very basic example of using the client. * basic - This is a very basic example of using the client.
* gmail_oauth2 - This is an example using oauth2 for logging into gmail as a secure appplication. * gmail_oauth2 - This is an example using oauth2 for logging into gmail as a secure appplication.
* rustls - This demonstrates how to use Rustls instead of Openssl for secure connections (helpful for cross compilation).

63
examples/rustls.rs Normal file
View file

@ -0,0 +1,63 @@
extern crate imap;
extern crate rustls_connector;
use std::{env, error::Error, net::TcpStream};
use rustls_connector::RustlsConnector;
fn main() -> Result<(), Box<dyn Error>> {
// Read config from environment or .env file
let host = env::var("HOST").expect("missing envvar host");
let user = env::var("MAILUSER").expect("missing envvar USER");
let password = env::var("PASSWORD").expect("missing envvar password");
let port = 993;
if let Some(email) = fetch_inbox_top(host, user, password, port)? {
println!("{}", &email);
}
Ok(())
}
fn fetch_inbox_top(
host: String,
user: String,
password: String,
port: u16,
) -> Result<Option<String>, Box<dyn Error>> {
// Setup Rustls TcpStream
let stream = TcpStream::connect((host.as_ref(), port))?;
let tls = RustlsConnector::default();
let tlsstream = tls.connect(&host, stream)?;
// 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::Client::new(tlsstream);
// 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(&user, &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);
};
// 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))
}

View file

@ -222,6 +222,9 @@ macro_rules! ok_or_unauth_client_err {
impl<T: Read + Write> Client<T> { impl<T: Read + Write> Client<T> {
/// Creates a new client over the given stream. /// Creates a new client over the given stream.
/// ///
/// For an example of how to use this method to provide a pure-Rust TLS integration, see the
/// rustls.rs in the examples/ directory.
///
/// This method primarily exists for writing tests that mock the underlying transport, but can /// This method primarily exists for writing tests that mock the underlying transport, but can
/// also be used to support IMAP over custom tunnels. /// also be used to support IMAP over custom tunnels.
pub fn new(stream: T) -> Client<T> { pub fn new(stream: T) -> Client<T> {