send messages via SMTP in configurable chunks

providers may have a maximum for the SMTP RCPT TO: header,
therefore, an outgoing message is split into several chunks.
the chunk size defaults to 50, however, if known to be larger or smaller
by a dedicated provider, this setting may be changed.

this does not affect the MIME To: headers,
if a provider has a maximum here, this is change would not help.
This commit is contained in:
B. Petersen
2020-10-29 22:15:18 +01:00
parent 04a4424664
commit 8232a148aa
3 changed files with 40 additions and 29 deletions

View File

@@ -3,6 +3,7 @@
use super::Smtp;
use async_smtp::*;
use crate::config::Config;
use crate::context::Context;
use crate::events::EventType;
use itertools::Itertools;
@@ -33,38 +34,41 @@ impl Smtp {
job_id: u32,
) -> Result<()> {
let message_len_bytes = message.len();
let chunk_size = context.get_config_int(Config::MaxSmtpRcptTo).await as usize;
let recipients_display = recipients.iter().map(|x| x.to_string()).join(",");
for recipients_chunk in recipients.chunks(chunk_size).into_iter() {
let recipients = recipients_chunk.to_vec();
let recipients_display = recipients.iter().map(|x| x.to_string()).join(",");
let envelope =
Envelope::new(self.from.clone(), recipients).map_err(Error::EnvelopeError)?;
let mail = SendableEmail::new(
envelope,
format!("{}", job_id), // only used for internal logging
message,
);
if let Some(ref mut transport) = self.transport {
// The timeout is 1min + 3min per MB.
let timeout = 60 + (180 * message_len_bytes / 1_000_000) as u64;
transport
.send_with_timeout(mail, Some(&Duration::from_secs(timeout)))
.await
.map_err(Error::SendError)?;
context.emit_event(EventType::SmtpMessageSent(format!(
"Message len={} was smtp-sent to {}",
message_len_bytes, recipients_display
)));
self.last_success = Some(std::time::SystemTime::now());
Ok(())
} else {
warn!(
context,
"uh? SMTP has no transport, failed to send to {}", recipients_display
let envelope =
Envelope::new(self.from.clone(), recipients).map_err(Error::EnvelopeError)?;
let mail = SendableEmail::new(
envelope,
format!("{}", job_id), // only used for internal logging
&message,
);
Err(Error::NoTransport)
if let Some(ref mut transport) = self.transport {
// The timeout is 1min + 3min per MB.
let timeout = 60 + (180 * message_len_bytes / 1_000_000) as u64;
transport
.send_with_timeout(mail, Some(&Duration::from_secs(timeout)))
.await
.map_err(Error::SendError)?;
context.emit_event(EventType::SmtpMessageSent(format!(
"Message len={} was smtp-sent to {}",
message_len_bytes, recipients_display
)));
self.last_success = Some(std::time::SystemTime::now());
} else {
warn!(
context,
"uh? SMTP has no transport, failed to send to {}", recipients_display
);
return Err(Error::NoTransport);
}
}
Ok(())
}
}