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