Skip to main content

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::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
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}