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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! A SMTP server that can be embedded into another program
//!
//! This library provides a simple embeddable SMTP server. The
//! server uses blocking IO and a threadpool.
//! # Examples
//! ```no_run
//! use mailin_embedded::{Server, SslConfig, Handler};
//! # use mailin_embedded::err::Error;
//!
//! #[derive(Clone)]
//! struct MyHandler {}
//! impl Handler for MyHandler{}
//!
//! let handler = MyHandler {};
//! let mut server = Server::new(handler);
//!
//! server.with_name("example.com")
//!    .with_ssl(SslConfig::None)?
//!    .with_addr("127.0.0.1:25")?;
//! server.serve();
//! # Ok::<(), Error>(())
//! ```

#![forbid(unsafe_code)]
#![forbid(missing_docs)]

/// Custom error type for mailin_embedded
pub mod err;

cfg_if::cfg_if! {
    if #[cfg(feature = "ossl")] {
        mod ossl;
        use crate::ossl::SslImpl;
    } else {
        mod rtls;
        use crate::rtls::SslImpl;
    }
}

mod running;
mod ssl;

use crate::err::Error;
pub use crate::ssl::SslConfig;
pub use mailin::response;
pub use mailin::{Action, AuthMechanism, Handler, Response};
use std::net::{SocketAddr, TcpListener, ToSocketAddrs};

/// `Server` is used to configure and start the SMTP server
pub struct Server<H>
where
    H: Handler + Clone + Send,
{
    handler: H,
    name: String,
    ssl: Option<SslImpl>,
    num_threads: u32,
    auth: Vec<AuthMechanism>,
    tcp_listener: Option<TcpListener>,
    socket_address: Vec<SocketAddr>,
}

impl<H> Server<H>
where
    H: Handler + Clone + Send,
{
    /// Create a new server with the given Handler
    pub fn new(handler: H) -> Self {
        Self {
            handler,
            name: "localhost".to_owned(),
            ssl: None,
            num_threads: 4,
            auth: Vec::with_capacity(4),
            tcp_listener: None,
            socket_address: Vec::with_capacity(4),
        }
    }

    /// Give the server a name
    pub fn with_name<T>(&mut self, name: T) -> &mut Self
    where
        T: Into<String>,
    {
        self.name = name.into();
        self
    }

    /// Set the SSL configuration of the server
    pub fn with_ssl(&mut self, ssl_config: SslConfig) -> Result<&mut Self, Error> {
        self.ssl = SslImpl::setup(ssl_config)?;
        Ok(self)
    }

    /// Set the size of the threadpool which is equal to the maximum number of
    /// concurrent SMTP sessions.
    pub fn with_num_threads(&mut self, num_threads: u32) -> &mut Self {
        self.num_threads = num_threads;
        self
    }

    /// Add an authentication mechanism that will supported by the server
    pub fn with_auth(&mut self, auth: AuthMechanism) -> &mut Self {
        self.auth.push(auth);
        self
    }

    /// Set a tcp listener from an already open socket
    pub fn with_tcp_listener(&mut self, listener: TcpListener) -> &mut Self {
        self.tcp_listener = Some(listener);
        self
    }

    /// Add ip addresses and ports to listen on.
    /// Returns an error if the given socket addresses are not valid.
    /// ```
    /// # use mailin_embedded::{Server, Handler};
    /// # use mailin_embedded::err::Error;
    /// # #[derive(Clone)]
    /// # struct EmptyHandler {}
    /// # impl Handler for EmptyHandler {}
    /// # let mut server = Server::new(EmptyHandler {});
    /// server.with_addr("127.0.0.1:25")?;
    /// # Ok::<(), Error>(())
    /// ```
    pub fn with_addr<A: ToSocketAddrs>(&mut self, addr: A) -> Result<&mut Self, Error> {
        for addr in addr
            .to_socket_addrs()
            .map_err(|e| Error::with_source("Invalid socket address", e))?
        {
            self.socket_address.push(addr);
        }
        Ok(self)
    }

    /// Start the SMTP server and run forever
    pub fn serve(self) -> Result<(), Error> {
        running::serve(self)
    }
}