385 lines
11 KiB
Rust
385 lines
11 KiB
Rust
extern crate chrono;
|
|
extern crate imap;
|
|
extern crate lettre;
|
|
extern crate lettre_email;
|
|
extern crate native_tls;
|
|
|
|
use chrono::{FixedOffset, TimeZone};
|
|
use lettre::Transport;
|
|
use std::net::TcpStream;
|
|
|
|
fn tls() -> native_tls::TlsConnector {
|
|
native_tls::TlsConnector::builder()
|
|
.danger_accept_invalid_certs(true)
|
|
.danger_accept_invalid_hostnames(true)
|
|
.build()
|
|
.unwrap()
|
|
}
|
|
|
|
fn session(user: &str) -> imap::Session<native_tls::TlsStream<TcpStream>> {
|
|
let mut s = imap::connect(
|
|
&format!(
|
|
"{}:3993",
|
|
std::env::var("TEST_HOST").unwrap_or("127.0.0.1".to_string())
|
|
),
|
|
"imap.example.com",
|
|
&tls(),
|
|
)
|
|
.unwrap()
|
|
.login(user, user)
|
|
.unwrap();
|
|
s.debug = true;
|
|
s
|
|
}
|
|
|
|
fn smtp(user: &str) -> lettre::SmtpTransport {
|
|
let creds = lettre::smtp::authentication::Credentials::new(user.to_string(), user.to_string());
|
|
lettre::SmtpClient::new(
|
|
&format!(
|
|
"{}:3465",
|
|
std::env::var("TEST_HOST").unwrap_or("127.0.0.1".to_string())
|
|
),
|
|
lettre::ClientSecurity::Wrapper(lettre::ClientTlsParameters {
|
|
connector: tls(),
|
|
domain: "smpt.example.com".to_string(),
|
|
}),
|
|
)
|
|
.unwrap()
|
|
.credentials(creds)
|
|
.transport()
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn connect_insecure_then_secure() {
|
|
let host = std::env::var("TEST_HOST").unwrap_or("127.0.0.1".to_string());
|
|
let stream = TcpStream::connect((host.as_ref(), 3143)).unwrap();
|
|
|
|
// ignored because of https://github.com/greenmail-mail-test/greenmail/issues/135
|
|
imap::Client::new(stream)
|
|
.secure("imap.example.com", &tls())
|
|
.unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn connect_secure() {
|
|
imap::connect(
|
|
&format!(
|
|
"{}:3993",
|
|
std::env::var("TEST_HOST").unwrap_or("127.0.0.1".to_string())
|
|
),
|
|
"imap.example.com",
|
|
&tls(),
|
|
)
|
|
.unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn login() {
|
|
session("readonly-test@localhost");
|
|
}
|
|
|
|
#[test]
|
|
fn logout() {
|
|
let mut s = session("readonly-test@localhost");
|
|
s.logout().unwrap();
|
|
}
|
|
|
|
#[test]
|
|
fn inbox_zero() {
|
|
// https://github.com/greenmail-mail-test/greenmail/issues/265
|
|
let mut s = session("readonly-test@localhost");
|
|
s.select("INBOX").unwrap();
|
|
let inbox = s.search("ALL").unwrap();
|
|
assert_eq!(inbox.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn inbox() {
|
|
let to = "inbox@localhost";
|
|
|
|
// first log in so we'll see the unsolicited e-mails
|
|
let mut c = session(to);
|
|
c.select("INBOX").unwrap();
|
|
|
|
// then send the e-mail
|
|
let mut s = smtp(to);
|
|
let e = lettre_email::Email::builder()
|
|
.from("sender@localhost")
|
|
.to(to)
|
|
.subject("My first e-mail")
|
|
.text("Hello world from SMTP")
|
|
.build()
|
|
.unwrap();
|
|
s.send(e.into()).unwrap();
|
|
|
|
// now we should see the e-mail!
|
|
let inbox = c.search("ALL").unwrap();
|
|
// and the one message should have the first message sequence number
|
|
assert_eq!(inbox.len(), 1);
|
|
assert!(inbox.contains(&1));
|
|
|
|
// we should also get two unsolicited responses: Exists and Recent
|
|
c.noop().unwrap();
|
|
let mut unsolicited = Vec::new();
|
|
while let Ok(m) = c.unsolicited_responses.try_recv() {
|
|
unsolicited.push(m);
|
|
}
|
|
assert_eq!(unsolicited.len(), 2);
|
|
assert!(unsolicited
|
|
.iter()
|
|
.any(|m| m == &imap::types::UnsolicitedResponse::Exists(1)));
|
|
assert!(unsolicited
|
|
.iter()
|
|
.any(|m| m == &imap::types::UnsolicitedResponse::Recent(1)));
|
|
|
|
// let's see that we can also fetch the e-mail
|
|
let fetch = c.fetch("1", "(ALL UID)").unwrap();
|
|
assert_eq!(fetch.len(), 1);
|
|
let fetch = &fetch[0];
|
|
assert_eq!(fetch.message, 1);
|
|
assert_ne!(fetch.uid, None);
|
|
assert_eq!(fetch.size, Some(138));
|
|
let e = fetch.envelope().unwrap();
|
|
assert_eq!(e.subject, Some(&b"My first e-mail"[..]));
|
|
assert_ne!(e.from, None);
|
|
assert_eq!(e.from.as_ref().unwrap().len(), 1);
|
|
let from = &e.from.as_ref().unwrap()[0];
|
|
assert_eq!(from.mailbox, Some(&b"sender"[..]));
|
|
assert_eq!(from.host, Some(&b"localhost"[..]));
|
|
assert_ne!(e.to, None);
|
|
assert_eq!(e.to.as_ref().unwrap().len(), 1);
|
|
let to = &e.to.as_ref().unwrap()[0];
|
|
assert_eq!(to.mailbox, Some(&b"inbox"[..]));
|
|
assert_eq!(to.host, Some(&b"localhost"[..]));
|
|
let date_opt = fetch.internal_date();
|
|
assert!(date_opt.is_some());
|
|
|
|
// and let's delete it to clean up
|
|
c.store("1", "+FLAGS (\\Deleted)").unwrap();
|
|
c.expunge().unwrap();
|
|
|
|
// the e-mail should be gone now
|
|
let inbox = c.search("ALL").unwrap();
|
|
assert_eq!(inbox.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn inbox_uid() {
|
|
let to = "inbox-uid@localhost";
|
|
|
|
// first log in so we'll see the unsolicited e-mails
|
|
let mut c = session(to);
|
|
c.select("INBOX").unwrap();
|
|
|
|
// then send the e-mail
|
|
let mut s = smtp(to);
|
|
let e = lettre_email::Email::builder()
|
|
.from("sender@localhost")
|
|
.to(to)
|
|
.subject("My first e-mail")
|
|
.text("Hello world from SMTP")
|
|
.build()
|
|
.unwrap();
|
|
s.send(e.into()).unwrap();
|
|
|
|
// now we should see the e-mail!
|
|
let inbox = c.uid_search("ALL").unwrap();
|
|
// and the one message should have the first message sequence number
|
|
assert_eq!(inbox.len(), 1);
|
|
let uid = inbox.into_iter().next().unwrap();
|
|
|
|
// we should also get two unsolicited responses: Exists and Recent
|
|
c.noop().unwrap();
|
|
let mut unsolicited = Vec::new();
|
|
while let Ok(m) = c.unsolicited_responses.try_recv() {
|
|
unsolicited.push(m);
|
|
}
|
|
assert_eq!(unsolicited.len(), 2);
|
|
assert!(unsolicited
|
|
.iter()
|
|
.any(|m| m == &imap::types::UnsolicitedResponse::Exists(1)));
|
|
assert!(unsolicited
|
|
.iter()
|
|
.any(|m| m == &imap::types::UnsolicitedResponse::Recent(1)));
|
|
|
|
// let's see that we can also fetch the e-mail
|
|
let fetch = c.uid_fetch(format!("{}", uid), "(ALL UID)").unwrap();
|
|
assert_eq!(fetch.len(), 1);
|
|
let fetch = &fetch[0];
|
|
assert_eq!(fetch.uid, Some(uid));
|
|
let e = fetch.envelope().unwrap();
|
|
assert_eq!(e.subject, Some(&b"My first e-mail"[..]));
|
|
let date_opt = fetch.internal_date();
|
|
assert!(date_opt.is_some());
|
|
|
|
// and let's delete it to clean up
|
|
c.uid_store(format!("{}", uid), "+FLAGS (\\Deleted)")
|
|
.unwrap();
|
|
c.expunge().unwrap();
|
|
|
|
// the e-mail should be gone now
|
|
let inbox = c.search("ALL").unwrap();
|
|
assert_eq!(inbox.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn list() {
|
|
let mut s = session("readonly-test@localhost");
|
|
s.select("INBOX").unwrap();
|
|
let subdirs = s.list(None, Some("%")).unwrap();
|
|
assert_eq!(subdirs.len(), 0);
|
|
|
|
// TODO: make a subdir
|
|
}
|
|
|
|
#[test]
|
|
fn append() {
|
|
let to = "inbox-append1@localhost";
|
|
|
|
// make a message to append
|
|
let e: lettre::SendableEmail = lettre_email::Email::builder()
|
|
.from("sender@localhost")
|
|
.to(to)
|
|
.subject("My second e-mail")
|
|
.text("Hello world")
|
|
.build()
|
|
.unwrap()
|
|
.into();
|
|
|
|
// connect
|
|
let mut c = session(to);
|
|
let mbox = "INBOX";
|
|
c.select(mbox).unwrap();
|
|
//append
|
|
c.append(mbox, e.message_to_string().unwrap()).unwrap();
|
|
|
|
// now we should see the e-mail!
|
|
let inbox = c.uid_search("ALL").unwrap();
|
|
// and the one message should have the first message sequence number
|
|
assert_eq!(inbox.len(), 1);
|
|
let uid = inbox.into_iter().next().unwrap();
|
|
|
|
// fetch the e-mail
|
|
let fetch = c.uid_fetch(format!("{}", uid), "(ALL UID)").unwrap();
|
|
assert_eq!(fetch.len(), 1);
|
|
let fetch = &fetch[0];
|
|
assert_eq!(fetch.uid, Some(uid));
|
|
let e = fetch.envelope().unwrap();
|
|
assert_eq!(e.subject, Some(&b"My second e-mail"[..]));
|
|
|
|
// and let's delete it to clean up
|
|
c.uid_store(format!("{}", uid), "+FLAGS (\\Deleted)")
|
|
.unwrap();
|
|
c.expunge().unwrap();
|
|
|
|
// the e-mail should be gone now
|
|
let inbox = c.search("ALL").unwrap();
|
|
assert_eq!(inbox.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn append_with_flags() {
|
|
use imap::types::Flag;
|
|
|
|
let to = "inbox-append2@localhost";
|
|
|
|
// make a message to append
|
|
let e: lettre::SendableEmail = lettre_email::Email::builder()
|
|
.from("sender@localhost")
|
|
.to(to)
|
|
.subject("My third e-mail")
|
|
.text("Hello world")
|
|
.build()
|
|
.unwrap()
|
|
.into();
|
|
|
|
// connect
|
|
let mut c = session(to);
|
|
let mbox = "INBOX";
|
|
c.select(mbox).unwrap();
|
|
//append
|
|
let flags: &[Flag] = &[Flag::Seen, Flag::Flagged];
|
|
c.append_with_flags(mbox, e.message_to_string().unwrap(), flags)
|
|
.unwrap();
|
|
|
|
// now we should see the e-mail!
|
|
let inbox = c.uid_search("ALL").unwrap();
|
|
// and the one message should have the first message sequence number
|
|
assert_eq!(inbox.len(), 1);
|
|
let uid = inbox.into_iter().next().unwrap();
|
|
|
|
// fetch the e-mail
|
|
let fetch = c.uid_fetch(format!("{}", uid), "(ALL UID)").unwrap();
|
|
assert_eq!(fetch.len(), 1);
|
|
let fetch = &fetch[0];
|
|
assert_eq!(fetch.uid, Some(uid));
|
|
let e = fetch.envelope().unwrap();
|
|
assert_eq!(e.subject, Some(&b"My third e-mail"[..]));
|
|
|
|
// check the flags
|
|
let setflags = fetch.flags();
|
|
assert!(setflags.contains(&Flag::Seen));
|
|
assert!(setflags.contains(&Flag::Flagged));
|
|
|
|
// and let's delete it to clean up
|
|
c.uid_store(format!("{}", uid), "+FLAGS (\\Deleted)")
|
|
.unwrap();
|
|
c.expunge().unwrap();
|
|
|
|
// the e-mail should be gone now
|
|
let inbox = c.search("ALL").unwrap();
|
|
assert_eq!(inbox.len(), 0);
|
|
}
|
|
|
|
#[test]
|
|
fn append_with_flags_and_date() {
|
|
use imap::types::Flag;
|
|
|
|
let to = "inbox-append3@localhost";
|
|
|
|
// make a message to append
|
|
let e: lettre::SendableEmail = lettre_email::Email::builder()
|
|
.from("sender@localhost")
|
|
.to(to)
|
|
.subject("My third e-mail")
|
|
.text("Hello world")
|
|
.build()
|
|
.unwrap()
|
|
.into();
|
|
|
|
// connect
|
|
let mut c = session(to);
|
|
let mbox = "INBOX";
|
|
c.select(mbox).unwrap();
|
|
// append
|
|
let flags: &[Flag] = &[Flag::Seen, Flag::Flagged];
|
|
let date = FixedOffset::east(8 * 3600)
|
|
.ymd(2020, 12, 13)
|
|
.and_hms(13, 36, 36);
|
|
c.append_with_flags_and_date(mbox, e.message_to_string().unwrap(), flags, Some(date))
|
|
.unwrap();
|
|
|
|
// now we should see the e-mail!
|
|
let inbox = c.uid_search("ALL").unwrap();
|
|
// and the one message should have the first message sequence number
|
|
assert_eq!(inbox.len(), 1);
|
|
let uid = inbox.into_iter().next().unwrap();
|
|
|
|
// fetch the e-mail
|
|
let fetch = c.uid_fetch(format!("{}", uid), "(ALL UID)").unwrap();
|
|
assert_eq!(fetch.len(), 1);
|
|
let fetch = &fetch[0];
|
|
assert_eq!(fetch.uid, Some(uid));
|
|
assert_eq!(fetch.internal_date(), Some(date));
|
|
|
|
// and let's delete it to clean up
|
|
c.uid_store(format!("{}", uid), "+FLAGS (\\Deleted)")
|
|
.unwrap();
|
|
c.expunge().unwrap();
|
|
|
|
// the e-mail should be gone now
|
|
let inbox = c.search("ALL").unwrap();
|
|
assert_eq!(inbox.len(), 0);
|
|
}
|