use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum MailError {
#[error("email provider not configured")]
NotConfigured,
#[error("configuration error: {0}")]
Configuration(String),
#[error("missing required field: {0}")]
MissingField(&'static str),
#[error("invalid email address: {0}")]
InvalidAddress(String),
#[error("attachment error: {0}")]
AttachmentError(String),
#[error("attachment has no content: {0}")]
AttachmentMissingContent(String),
#[error("attachment file not found: {0}")]
AttachmentFileNotFound(String),
#[error("failed to read attachment {path}: {source}")]
AttachmentReadError {
path: String,
#[source]
source: std::io::Error,
},
#[error("build error: {0}")]
BuildError(String),
#[error("send error: {0}")]
SendError(String),
#[error("unsupported feature: {0}")]
UnsupportedFeature(String),
#[error("provider error ({provider}): {message}")]
ProviderError {
provider: &'static str,
message: String,
status: Option<u16>,
},
#[cfg(feature = "_http")]
#[error("HTTP error: {0}")]
HttpError(#[from] reqwest::Error),
#[error("JSON error: {0}")]
JsonError(#[from] serde_json::Error),
#[error("template error: {0}")]
TemplateError(String),
#[cfg(feature = "templates")]
#[error("template error: {0}")]
TemplateRenderError(#[from] askama::Error),
#[cfg(all(
feature = "smtp",
not(all(target_family = "wasm", target_os = "unknown"))
))]
#[error("build error: {0}")]
LettreBuildError(#[from] lettre::error::Error),
#[cfg(all(
feature = "smtp",
not(all(target_family = "wasm", target_os = "unknown"))
))]
#[error("send error: {0}")]
SmtpError(#[from] lettre::transport::smtp::Error),
#[cfg(all(
feature = "smtp",
not(all(target_family = "wasm", target_os = "unknown"))
))]
#[error("invalid email address: {0}")]
LettreAddressError(#[from] lettre::address::AddressError),
#[error("internal error: {0}")]
Internal(String),
}
impl MailError {
pub fn provider(provider: &'static str, message: impl Into<String>) -> Self {
Self::ProviderError {
provider,
message: message.into(),
status: None,
}
}
pub fn provider_with_status(
provider: &'static str,
message: impl Into<String>,
status: u16,
) -> Self {
Self::ProviderError {
provider,
message: message.into(),
status: Some(status),
}
}
pub fn kind(&self) -> &'static str {
match self {
MailError::NotConfigured => "not_configured",
MailError::Configuration(_) => "configuration",
MailError::MissingField(_) => "missing_field",
MailError::InvalidAddress(_) => "invalid_address",
MailError::AttachmentError(_) => "attachment_error",
MailError::AttachmentMissingContent(_) => "attachment_missing_content",
MailError::AttachmentFileNotFound(_) => "attachment_file_not_found",
MailError::AttachmentReadError { .. } => "attachment_read_error",
MailError::BuildError(_) => "build_error",
MailError::SendError(_) => "send_error",
MailError::UnsupportedFeature(_) => "unsupported_feature",
MailError::ProviderError { .. } => "provider_error",
#[cfg(feature = "_http")]
MailError::HttpError(_) => "http_error",
MailError::JsonError(_) => "json_error",
MailError::TemplateError(_) => "template_error",
#[cfg(feature = "templates")]
MailError::TemplateRenderError(_) => "template_error",
#[cfg(all(
feature = "smtp",
not(all(target_family = "wasm", target_os = "unknown"))
))]
MailError::LettreBuildError(_) => "build_error",
#[cfg(all(
feature = "smtp",
not(all(target_family = "wasm", target_os = "unknown"))
))]
MailError::SmtpError(_) => "send_error",
#[cfg(all(
feature = "smtp",
not(all(target_family = "wasm", target_os = "unknown"))
))]
MailError::LettreAddressError(_) => "invalid_address",
MailError::Internal(_) => "internal",
}
}
pub fn provider_status(&self) -> Option<u16> {
match self {
MailError::ProviderError { status, .. } => *status,
_ => None,
}
}
}