1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
//! In this examples runs a simple command line dialog to create a mail
//! and send it to an MSA
#[cfg(not(feature = "smtp"))]
compile_error!("example `send_mail` requires feature `smtp`");
#[macro_use]
extern crate mail;
extern crate rpassword;
extern crate futures;
extern crate tokio;
extern crate soft_ascii_string;
use std::io::{self, Write};
use futures::{Stream, future};
use soft_ascii_string::SoftAsciiString;
use mail::{
Mail,
HeaderTryFrom,
smtp::{
send_batch as send_mail_batch,
MailRequest,
ConnectionConfig,
ConnectionBuilder,
auth::{Plain as AuthPlain}
},
error::MailError,
default_impl::simple_context,
header_components::Domain
};
mod cli;
fn main() {
let msg_id_domain = Domain::try_from("company_a.test").unwrap();
let unique_part = SoftAsciiString::from_string("c207n521cec").unwrap();
let ctx = simple_context::new(msg_id_domain, unique_part).unwrap();
let (msa_info, mails) = read_data().unwrap();
let connection_config = create_connection_config(msa_info);
let mail_requests = create_mail_requests(mails).unwrap();
println!("[starting sending mails]");
// We run a tokio core "just" for sending the mails,
// normally we probably would schedule/spawn this task
// on a existing tokio runtime.
tokio::run(future::lazy(move || {
send_mail_batch(mail_requests, connection_config, ctx)
.then(|res| Ok(res))
.for_each(|res| {
match res {
Ok(_) => println!("[mail send]"),
Err(err) => println!("[sending mail failed] {:?}", err)
}
Ok(())
})
}));
println!("[DONE]");
}
fn create_connection_config(msa_info: cli::MsaInfo) -> ConnectionConfig<AuthPlain> {
let cli::MsaInfo { domain, auth } = msa_info;
ConnectionBuilder::new(domain)
.expect("could not resolve domain/host name of MSA")
.auth(AuthPlain::from_username(auth.username, auth.password)
.expect("used \\0 in username or password"))
.build()
}
fn create_mail_requests(mails: Vec<cli::SimpleMail>) -> Result<Vec<MailRequest>, MailError> {
use mail::headers::*;
let requests = mails
.into_iter()
.map(|simple_mail| {
let cli::SimpleMail { from, to, subject, text_body } = simple_mail;
let mut mail = Mail::plain_text(text_body);
mail.insert_headers(headers! {
_From: [from],
_To: [to],
Subject: subject
}?);
Ok(MailRequest::from(mail))
})
.collect::<Result<Vec<_>,_>>();
requests
}
fn read_data() -> Result<(cli::MsaInfo, Vec<cli::SimpleMail>), io::Error> {
cli::with_dialog(|mut dialog| {
let msa_info = dialog.read_msa_info()?;
let mut mails = Vec::new();
let mut more = true;
writeln!(dialog.stdout(), "\nreading mails:")?;
while more {
let mail = dialog.read_simple_mail()?;
mails.push(mail);
dialog.prompt("Another Mail? [y/n]")?;
more = dialog.read_yn()?;
}
writeln!(dialog.stdout(), "[collecting data done]")?;
Ok((msa_info, mails))
})
}
|