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