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::{info, 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 let recipients_display = recipients
44 .iter()
45 .map(|x| x.as_ref())
46 .collect::<Vec<&str>>()
47 .join(",");
48
49 let envelope =
50 Envelope::new(self.from.clone(), recipients.to_vec()).map_err(Error::Envelope)?;
51 let mail = SendableEmail::new(envelope, message);
52
53 if let Some(ref mut transport) = self.transport {
54 transport.send(mail).await.map_err(Error::SmtpSend)?;
55
56 let info_msg =
57 format!("Message len={message_len_bytes} was SMTP-sent to {recipients_display}");
58 info!(context, "{info_msg}.");
59 context.emit_event(EventType::SmtpMessageSent(info_msg));
60 self.last_success = Some(tools::Time::now());
61 } else {
62 warn!(
63 context,
64 "uh? SMTP has no transport, failed to send to {}", recipients_display
65 );
66 return Err(Error::NoTransport);
67 }
68 Ok(())
69 }
70}