dust_mail/
error.rs

1use std::{error, fmt, num::ParseIntError, result};
2
3#[cfg(feature = "pop")]
4use async_pop::error::Error as PopError;
5
6#[cfg(feature = "imap")]
7use async_imap::error::Error as ImapError;
8
9#[cfg(feature = "smtp")]
10use async_smtp::error::Error as SmtpError;
11
12use async_native_tls::Error as TlsError;
13
14use chrono::ParseError as ParseTimeError;
15
16use email::results::ParsingError as AddressParseError;
17
18use mailparse::MailParseError;
19
20#[cfg(feature = "runtime-tokio")]
21use tokio::io::Error as IoError;
22
23#[cfg(feature = "runtime-async-std")]
24use async_std::io::Error as IoError;
25
26macro_rules! impl_from_error {
27    ($error_type:ty, $error_kind:expr, $error_msg:expr) => {
28        impl From<$error_type> for Error {
29            fn from(err: $error_type) -> Self {
30                Error::new($error_kind(err), $error_msg)
31            }
32        }
33    };
34}
35
36macro_rules! err {
37    ($kind:expr, $($arg:tt)*) => {{
38		use crate::error::Error;
39
40        let kind = $kind;
41        let message = format!($($arg)*);
42        return Err(Error::new( kind, message ));
43    }};
44}
45
46#[derive(Debug)]
47pub enum ErrorKind {
48    MessageNotFound,
49    /// The server responded with some unexpected data.
50    UnexpectedBehavior,
51    /// The requested feature/function is unsupported for this client type.
52    Unsupported,
53    Io(IoError),
54    #[cfg(feature = "imap")]
55    /// An error from the Imap server.
56    Imap(ImapError),
57    #[cfg(feature = "pop")]
58    /// An error from the Pop server.
59    Pop(PopError),
60    #[cfg(feature = "smtp")]
61    Smtp(SmtpError),
62    Tls(TlsError),
63    #[cfg(feature = "maildir")]
64    Maildir(maildir::MaildirError),
65    #[cfg(feature = "maildir")]
66    MailEntry(maildir::MailEntryError),
67    /// Failed to parse a date/time from the server.
68    ParseTime(ParseTimeError),
69    ParseInt(ParseIntError),
70    /// Failed to parse a socket address which is used to connect to the remote mail server
71    ParseAddress,
72    /// Failed to parse provided login config.
73    InvalidLoginConfig,
74    /// Failed to parse mail message.
75    ParseMessage(MailParseError),
76    InvalidMessage,
77    /// Error from the remote mail server.
78    MailServer,
79    /// Failed to serialize the given data to JSON.
80    SerializeJSON,
81    /// Could not detect a config from the given email address.
82    ConfigNotFound,
83    ParseEmailAddress(AddressParseError),
84    MailBoxNotFound,
85    NoClientAvailable,
86}
87
88#[derive(Debug)]
89pub struct Error {
90    message: String,
91    kind: ErrorKind,
92}
93
94impl Error {
95    pub fn new<S: Into<String>>(kind: ErrorKind, msg: S) -> Self {
96        Self {
97            message: msg.into(),
98            kind,
99        }
100    }
101
102    pub fn kind(&self) -> &ErrorKind {
103        &self.kind
104    }
105}
106
107impl error::Error for Error {
108    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
109        match self.kind() {
110            #[cfg(feature = "pop")]
111            ErrorKind::Pop(e) => e.source(),
112            #[cfg(feature = "imap")]
113            ErrorKind::Imap(e) => e.source(),
114            ErrorKind::Io(e) => e.source(),
115            ErrorKind::Tls(e) => e.source(),
116            ErrorKind::ParseMessage(e) => e.source(),
117            _ => None,
118        }
119    }
120}
121
122#[cfg(feature = "pop")]
123impl_from_error!(PopError, |err| ErrorKind::Pop(err), "Error from pop server");
124#[cfg(feature = "imap")]
125impl_from_error!(
126    ImapError,
127    |err| ErrorKind::Imap(err),
128    "Error from imap server"
129);
130#[cfg(feature = "smtp")]
131impl_from_error!(
132    SmtpError,
133    |err| ErrorKind::Smtp(err),
134    "Error from smtp server"
135);
136impl_from_error!(
137    TlsError,
138    |err| ErrorKind::Tls(err),
139    "Error creating a secure connection"
140);
141impl_from_error!(IoError, |err| ErrorKind::Io(err), "Io operation failed");
142impl_from_error!(
143    ParseTimeError,
144    |err| ErrorKind::ParseTime(err),
145    "Failed to parse date time"
146);
147impl_from_error!(
148    MailParseError,
149    |err| ErrorKind::ParseMessage(err),
150    "Failed to parse mail message"
151);
152impl_from_error!(
153    AddressParseError,
154    |err| ErrorKind::ParseEmailAddress(err),
155    "Failed to parse email address"
156);
157impl_from_error!(
158    ParseIntError,
159    |err| ErrorKind::ParseInt(err),
160    "Failed to parse integer value from string"
161);
162#[cfg(feature = "maildir")]
163impl_from_error!(
164    maildir::MaildirError,
165    |err| ErrorKind::Maildir(err),
166    "Failed to store email in local directory"
167);
168#[cfg(feature = "maildir")]
169impl_from_error!(
170    maildir::MailEntryError,
171    |err| ErrorKind::MailEntry(err),
172    "Failed to retrieve email from local directory"
173);
174
175impl fmt::Display for Error {
176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177        write!(f, "{}", self.message)
178    }
179}
180
181pub(crate) use err;
182
183pub type Result<T> = result::Result<T, Error>;