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 UnexpectedBehavior,
51 Unsupported,
53 Io(IoError),
54 #[cfg(feature = "imap")]
55 Imap(ImapError),
57 #[cfg(feature = "pop")]
58 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 ParseTime(ParseTimeError),
69 ParseInt(ParseIntError),
70 ParseAddress,
72 InvalidLoginConfig,
74 ParseMessage(MailParseError),
76 InvalidMessage,
77 MailServer,
79 SerializeJSON,
81 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>;