Merge pull request #138 from brycefisher/feat/rustls-support
(feat) Provide example integration with Rustls crate
This commit is contained in:
commit
c8288ea19b
5 changed files with 70 additions and 2 deletions
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
63
examples/rustls.rs
Normal 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))
|
||||||
|
}
|
||||||
|
|
@ -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> {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue