From 36883692782ed2355a0ec12ccf9f82aa2edcc8c1 Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Sat, 10 Sep 2022 19:32:51 +0300 Subject: [PATCH] melib/smtp: add smtp test --- Cargo.lock | 311 +++++++++++++++++++++++++++++- melib/Cargo.toml | 4 + melib/src/smtp.rs | 220 ++++++++++++++++++++- melib/test_sample_longmessage.eml | 65 +++++++ 4 files changed, 596 insertions(+), 4 deletions(-) create mode 100644 melib/test_sample_longmessage.eml diff --git a/Cargo.lock b/Cargo.lock index a97432c9..7c20e254 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,6 +28,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "async-channel" version = "1.6.1" @@ -153,6 +162,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.9", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -200,6 +220,18 @@ dependencies = [ "once_cell", ] +[[package]] +name = "bufstream" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8" + +[[package]] +name = "bumpalo" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" + [[package]] name = "bytes" version = "1.2.1" @@ -239,6 +271,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-integer", + "num-traits", + "time 0.1.44", + "wasm-bindgen", + "winapi 0.3.9", +] + [[package]] name = "clap" version = "2.34.0" @@ -442,6 +489,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + [[package]] name = "encoding" version = "0.2.33" @@ -742,7 +795,7 @@ checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -792,6 +845,19 @@ dependencies = [ "itoa", ] +[[package]] +name = "iana-time-zone" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad2bfd338099682614d3ee3fe0cd72e0b6a41ca6a87f6a74a3bd593c91650501" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "js-sys", + "wasm-bindgen", + "winapi 0.3.9", +] + [[package]] name = "idna" version = "0.2.3" @@ -896,6 +962,15 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1003,7 +1078,35 @@ dependencies = [ "dirs-next", "objc-foundation", "objc_id", - "time", + "time 0.3.11", +] + +[[package]] +name = "mailin" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d0411d6d3cf6baacae37461dc5b0a32b9c68ae99ddef61bcd88174b8da890a" +dependencies = [ + "base64", + "either", + "log", + "nom", + "ternop", +] + +[[package]] +name = "mailin-embedded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2f29d14249fb45f7795bc8564175ca7b963254217f24e8cde84ba40d38b58cc" +dependencies = [ + "bufstream", + "lazy_static", + "log", + "mailin", + "rustls", + "rustls-pemfile", + "scoped_threadpool", ] [[package]] @@ -1074,6 +1177,7 @@ dependencies = [ "isahc", "libc", "libloading", + "mailin-embedded", "native-tls", "nix", "nom", @@ -1084,6 +1188,7 @@ dependencies = [ "serde_json", "smallvec", "smol", + "stderrlog", "unicode-segmentation", "uuid", "xdg", @@ -1249,6 +1354,25 @@ dependencies = [ "winrt-notification", ] +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.13.1" @@ -1537,6 +1661,21 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi 0.3.9", +] + [[package]] name = "rusqlite" version = "0.28.0" @@ -1551,6 +1690,27 @@ dependencies = [ "smallvec", ] +[[package]] +name = "rustls" +version = "0.20.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +dependencies = [ + "base64", +] + [[package]] name = "ryu" version = "1.0.10" @@ -1576,12 +1736,28 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "security-framework" version = "2.6.1" @@ -1715,6 +1891,25 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "stderrlog" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af95cb8a5f79db5b2af2a46f44da7594b5adbcbb65cbf87b8da0959bfdd82460" +dependencies = [ + "atty", + "chrono", + "log", + "termcolor", + "thread_local", +] + [[package]] name = "structopt" version = "0.3.26" @@ -1791,6 +1986,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + [[package]] name = "termion" version = "1.5.6" @@ -1803,6 +2007,12 @@ dependencies = [ "redox_termios", ] +[[package]] +name = "ternop" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d4ae32d0a4605a89c28534371b056919c12e7a070ee07505af75130ff030111" + [[package]] name = "textwrap" version = "0.11.0" @@ -1841,6 +2051,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi 0.3.9", +] + [[package]] name = "time" version = "0.3.11" @@ -1964,6 +2185,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" version = "2.2.2" @@ -2016,12 +2243,92 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" + +[[package]] +name = "web-sys" +version = "0.3.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "wepoll-ffi" version = "0.1.2" diff --git a/melib/Cargo.toml b/melib/Cargo.toml index 1d383d38..1399b2bf 100644 --- a/melib/Cargo.toml +++ b/melib/Cargo.toml @@ -49,6 +49,10 @@ uuid = { version = "^1", features = ["serde", "v4", "v5"] } xdg = "2.1.0" xdg-utils = "^0.4.0" +[dev-dependencies] +mailin-embedded = { version = "0.7", features = ["rtls"] } +stderrlog = "^0.5" + [features] default = ["unicode_algorithms", "imap_backend", "maildir_backend", "mbox_backend", "vcard", "sqlite3", "smtp", "deflate_compression"] diff --git a/melib/src/smtp.rs b/melib/src/smtp.rs index 6a57a494..75fc3629 100644 --- a/melib/src/smtp.rs +++ b/melib/src/smtp.rs @@ -155,11 +155,11 @@ pub struct SmtpAuthType { login: bool, } -fn true_val() -> bool { +const fn true_val() -> bool { true } -fn false_val() -> bool { +const fn false_val() -> bool { false } @@ -1048,3 +1048,219 @@ async fn read_lines<'r>( } Ok(reply) } + +#[cfg(test)] +mod test { + use super::*; + + use mailin_embedded::{Handler, Response, Server, SslConfig}; + use std::net::IpAddr; //, Ipv4Addr, Ipv6Addr}; + use std::sync::{Arc, Mutex}; + use std::thread; + + const ADDRESS: &str = "127.0.0.1:8825"; + #[derive(Debug, Clone)] + enum Message { + Helo, + Mail { + from: String, + }, + Rcpt { + from: String, + to: Vec, + }, + DataStart { + from: String, + to: Vec, + }, + Data { + #[allow(dead_code)] + from: String, + to: Vec, + buf: Vec, + }, + } + + #[derive(Debug, Clone)] + struct MyHandler { + mails: Arc>>, + stored: Arc>>, + } + use mailin_embedded::response::{INTERNAL_ERROR, OK}; + + impl Handler for MyHandler { + fn helo(&mut self, ip: IpAddr, domain: &str) -> Response { + eprintln!("helo ip {:?} domain {:?}", ip, domain); + self.mails + .lock() + .unwrap() + .push(((ip, domain.to_string()), Message::Helo)); + OK + } + + fn mail(&mut self, ip: IpAddr, domain: &str, from: &str) -> Response { + eprintln!("mail() ip {:?} domain {:?} from {:?}", ip, domain, from); + if let Some((_, message)) = self + .mails + .lock() + .unwrap() + .iter_mut() + .find(|((i, d), _)| (i, d.as_str()) == (&ip, domain)) + { + std::dbg!(&message); + if let Message::Helo = message { + *message = Message::Mail { + from: from.to_string(), + }; + return OK; + } + } + INTERNAL_ERROR + } + + fn rcpt(&mut self, _to: &str) -> Response { + eprintln!("rcpt() to {:?}", _to); + if let Some((_, message)) = self.mails.lock().unwrap().last_mut() { + std::dbg!(&message); + if let Message::Mail { from } = message { + *message = Message::Rcpt { + from: from.clone(), + to: vec![_to.to_string()], + }; + return OK; + } else if let Message::Rcpt { to, .. } = message { + to.push(_to.to_string()); + return OK; + } + } + INTERNAL_ERROR + } + + fn data_start( + &mut self, + _domain: &str, + _from: &str, + _is8bit: bool, + _to: &[String], + ) -> Response { + eprintln!( + "data_start() domain {:?} from {:?} is8bit {:?} to {:?}", + _domain, _from, _is8bit, _to + ); + if let Some(((_, d), ref mut message)) = self.mails.lock().unwrap().last_mut() { + if d != _domain { + return INTERNAL_ERROR; + } + std::dbg!(&message); + if let Message::Rcpt { from, to } = message { + *message = Message::DataStart { + from: from.to_string(), + to: to.to_vec(), + }; + return OK; + } + } + INTERNAL_ERROR + } + + fn data(&mut self, _buf: &[u8]) -> std::result::Result<(), std::io::Error> { + if let Some(((_, _), ref mut message)) = self.mails.lock().unwrap().last_mut() { + if let Message::DataStart { from, to } = message { + *message = Message::Data { + from: from.to_string(), + to: to.clone(), + buf: _buf.to_vec(), + }; + return Ok(()); + } else if let Message::Data { buf, .. } = message { + buf.extend(_buf.into_iter().copied()); + return Ok(()); + } + } + Ok(()) + } + + fn data_end(&mut self) -> Response { + eprintln!("datae_nd() "); + if let Some(((_, _), message)) = self.mails.lock().unwrap().pop() { + if let Message::Data { from: _, to, buf } = message { + for to in to { + match crate::Envelope::from_bytes(&buf, None) { + Ok(env) => { + std::dbg!(&env); + std::dbg!(env.other_headers()); + self.stored.lock().unwrap().push((to.clone(), env)); + } + Err(err) => { + eprintln!("envelope parse error {}", err); + } + } + } + return OK; + } + } + INTERNAL_ERROR + } + } + + fn get_smtp_conf() -> SmtpServerConf { + SmtpServerConf { + hostname: "127.0.0.1".into(), + port: 8825, + envelope_from: "foo-chat@example.com".into(), + auth: SmtpAuth::None, + security: SmtpSecurity::None, + extensions: Default::default(), + } + } + + #[test] + fn test_smtp() { + stderrlog::new() + .quiet(false) + .verbosity(0) + .show_module_names(true) + .timestamp(stderrlog::Timestamp::Millisecond) + .init() + .unwrap(); + + let handler = MyHandler { + mails: Arc::new(Mutex::new(vec![])), + stored: Arc::new(Mutex::new(vec![])), + }; + let handler2 = handler.clone(); + let _smtp_handle = thread::spawn(move || { + let mut server = Server::new(handler2); + + server + .with_name("example.com") + .with_ssl(SslConfig::None) + .unwrap() + .with_addr(ADDRESS) + .unwrap(); + eprintln!("Running smtp server at {}", ADDRESS); + server.serve().expect("Could not run server"); + }); + + let smtp_server_conf = get_smtp_conf(); + let input_str = include_str!("../test_sample_longmessage.eml"); + match crate::Envelope::from_bytes(input_str.as_bytes(), None) { + Ok(_envelope) => {} + Err(err) => { + panic!("Could not parse message: {}", err); + } + } + let mut connection = + futures::executor::block_on(SmtpConnection::new_connection(smtp_server_conf)).unwrap(); + futures::executor::block_on(connection.mail_transaction( + input_str, + /*tos*/ + Some(&[ + Address::try_from("foo-chat@example.com").unwrap(), + Address::try_from("webmaster@example.com").unwrap(), + ]), + )) + .unwrap(); + assert_eq!(handler.stored.lock().unwrap().len(), 2); + } +} diff --git a/melib/test_sample_longmessage.eml b/melib/test_sample_longmessage.eml new file mode 100644 index 00000000..67fe3a26 --- /dev/null +++ b/melib/test_sample_longmessage.eml @@ -0,0 +1,65 @@ +Return-Path: +Delivered-To: jonnny@miami-dice.co.uk +Received: from violet.xenserver.co.uk + by violet.xenserver.co.uk with LMTP + id qBHcI7LKml9FxzIAYrQLqw + (envelope-from ) + for ; Thu, 29 Oct 2020 13:59:14 +0000 +Return-path: +Envelope-to: jonnny@miami-dice.co.uk +Delivery-date: Thu, 29 Oct 2020 13:59:14 +0000 +Received: from mail-oln040092254105.outbound.protection.outlook.com ([40.92.254.105]:29481 helo=APC01-PU1-obe.outbound.protection.outlook.com) + by violet.xenserver.co.uk with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + (Exim 4.93) + (envelope-from ) + id 1kY8SJ-00DxYw-WD + for jonnny@miami-dice.co.uk; Thu, 29 Oct 2020 13:59:14 +0000 +ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; + b=KKU/kthPXLl8CnAmBXXsD1QQWr4evL4ymaLwgHgRi5eSnOe2d2sQxrhcZ1VvLSvW2DQEQoNAm6NUtTC5uRUnBDS0n+g1E5/t1z8oFbzdioCIT6rL77ta3MVcaQ/o+gRa6dIwiNfu8z5GxAujOOu57gCfnCw3/gLeOHH01KtP4ezEB/DvAU9bC8eyso1T7nv+HT0riTjZOywGwDHnVb1aIPPIUiOQrrEi+cfLQRiCer01d94U8Wp+FUECrVYbr4uZGl8mbTwU4oZL1rJ25ubYG54e1ktaPJRa2YEitgJEF5sS8Z503c3RjzzBvvHkc/Kl6ypXcovP9xxeoSrS7YIPKA== +ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; + s=arcselector9901; + h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; + bh=NUSuxgSF4fNUuTts93/OAIsK9q9w8XhbybHWH/oRmXo=; + b=VU2clBW8reAfnfCef0DeEDlBzcCU2u288YCjTvB0ekvBkJGSdI657WyS8KR7JSy0KcPWRfGbN9GJaETaasoa7bLdfuB6K9foup+vSqlA1witS5JQXQM/vJCKx67DbT8/8emLrKi7yDD2qjtRsb6HfvbwAGGvmPyUeyfTvRv6js+4YUbe5eN6CCdJEploBXDrWjFXHpSCwVCL1oF6rgrJf0+Td+ufX0QEHbOz2uJWj4yz0A8hK2yV+2JDVW7GiBwZMrO4yLNXYck/0HQRyYFe8I86xUBJWp/0IITCTe96x5L/H3lqmGkh4uRt8IsXT/2jBEm5CmXLxJZAMR8RONG9BQ== +ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; + dkim=none; arc=none +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=hotmail.com; + s=selector1; + h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; + bh=NUSuxgSF4fNUuTts93/OAIsK9q9w8XhbybHWH/oRmXo=; + b=JRkih9HxwazdzH6MSzSetJMcRwvDr+e97VnoDCQYJf9qQqgtQvzMZR0Z+d2Gu74Ip3ebcvx5oYlOpV15yVZAqUmUeirpF2rdkmMWQiaDQMq9SLiF09eMDkDfEdGLD4V+C36QIISRamgyagIsC72/UB6OyxpXoAjP0SFxbyItvWVgB9EVVsSJLOKXWgRWiYSZxMLye3OQUqdWoiQ9Tw/o8uywLTvcojOizZaS2SrYWajYScBmMiCh58dUarKzrfXmR/WisfBepCf1ia7BKttjalhuJBcMyKfM923X5IbZ+Yw+gVpLtzwGUyPt2cobOAxKna11whmpWdtoBeXRR/hKOg== +Received: from PU1APC01FT013.eop-APC01.prod.protection.outlook.com + (2a01:111:e400:7ebe::45) by + PU1APC01HT068.eop-APC01.prod.protection.outlook.com (2a01:111:e400:7ebe::323) + with Microsoft SMTP Server (version=TLS1_2, + cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3520.15; Thu, 29 Oct + 2020 13:58:16 +0000 +Received: from PS1PR0601MB3675.apcprd06.prod.outlook.com + (2a01:111:e400:7ebe::44) by PU1APC01FT013.mail.protection.outlook.com + (2a01:111:e400:7ebe::78) with Microsoft SMTP Server (version=TLS1_2, + cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3520.15 via Frontend + Transport; Thu, 29 Oct 2020 13:58:16 +0000 +Received: from PS1PR0601MB3675.apcprd06.prod.outlook.com + ([fe80::65ed:e320:1c31:1695]) by PS1PR0601MB3675.apcprd06.prod.outlook.com + ([fe80::65ed:e320:1c31:1695%7]) with mapi id 15.20.3499.027; Thu, 29 Oct 2020 + 13:58:16 +0000 +From: Jamaica Poe +To: +Subject: thankful that I had the chance to written report, that I could learn + and let alone the chance $4454.32 +Thread-Topic: thankful that I had the chance to written report, that I could + learn and let alone the chance $4454.32 +Thread-Index: AQHWrfuHFQ6EC5DxDEG0hktDfP8BQg== +Date: Thu, 29 Oct 2020 13:58:16 +0000 +Message-ID: + +Accept-Language: en-US +Content-Language: en-US +Content-Type: text/html +Content-Transfer-Encoding: base64 +MIME-Version: 1.0 + +PCFET0NUWVBFPjxodG1sPjxoZWFkPjx0aXRsZT5mb288L3RpdGxlPjwvaGVhZD48Ym9k +eT48dGFibGUgY2xhc3M9ImZvbyI+PHRoZWFkPjx0cj48dGQ+Zm9vPC90ZD48L3RoZWFk +Pjx0Ym9keT48dHI+PHRkPmZvbzE8L3RkPjwvdHI+PC90Ym9keT48L3RhYmxlPjwvYm9k +eT48L2h0bWw+