deltachat/smtp/
send.rs

1//! # SMTP message sending
2
3use 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    /// Send a prepared mail to recipients.
27    /// On successful send out Ok() is returned.
28    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            // Notify ratelimiter about sent message regardless of whether quota is exceeded or not.
36            // Checking whether sending is allowed for low-priority messages should be done by the
37            // caller.
38            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}