1use async_smtp::{EmailAddress, Envelope, SendableEmail};
4
5use super::Smtp;
6use crate::config::Config;
7use crate::context::Context;
8use crate::events::EventType;
9use crate::log::warn;
10use crate::tools;
11
12pub type Result<T> = std::result::Result<T, Error>;
13
14#[derive(Debug, thiserror::Error)]
15pub enum Error {
16 #[error("Envelope error: {}", _0)]
17 Envelope(anyhow::Error),
18 #[error("Send error: {}", _0)]
19 SmtpSend(async_smtp::error::Error),
20 #[error("SMTP has no transport")]
21 NoTransport,
22 #[error("{}", _0)]
23 Other(#[from] anyhow::Error),
24}
25
26impl Smtp {
27 pub async fn send(
30 &mut self,
31 context: &Context,
32 recipients: &[EmailAddress],
33 message: &[u8],
34 ) -> Result<()> {
35 if !context.get_config_bool(Config::Bot).await? {
36 context.ratelimit.write().await.send();
40 }
41
42 let message_len_bytes = message.len();
43
44 let envelope =
45 Envelope::new(self.from.clone(), recipients.to_vec()).map_err(Error::Envelope)?;
46 let mail = SendableEmail::new(envelope, message);
47
48 let Some(ref mut transport) = self.transport else {
49 warn!(
50 context,
51 "Failed to send a message because SMTP client has no SmtpTransport."
52 );
53 return Err(Error::NoTransport);
54 };
55
56 transport.send(mail).await.map_err(Error::SmtpSend)?;
57
58 let info_msg = format!(
59 "Message len={message_len_bytes} was SMTP-sent to {} recipients.",
60 recipients.len()
61 );
62 info!(context, "{info_msg}.");
63 context.emit_event(EventType::SmtpMessageSent(info_msg));
64 self.last_success = Some(tools::Time::now());
65 Ok(())
66 }
67}