Files
inbuxa-server/crates/smtp/src/reporting/send.rs
T
jcoffey-dev 7dae9b29fd Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f
Enterprise-only files removed or emptied: 63
Enterprise-only snippets removed: 117 in 50 files
Dangling module declarations removed: 5
Cargo edits turning enterprise off: 14
Verification: clean
Enterprise feature gates left for rebuilt features: 19 in 18 files

Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
2026-09-18 10:21:56 -07:00

151 lines
4.6 KiB
Rust

/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use crate::{
inbound::dkim::DkimSign,
queue::{
MessageSource,
spool::{QueueParams, SmtpSpool},
},
};
use common::{Server, expr::if_block::IfBlock, ipc::ReportingEvent};
pub trait MtaReportSend: Sync + Send {
fn is_local_report_domain(
&self,
domain: &str,
session_id: u64,
) -> impl Future<Output = bool> + Send;
fn send_report(
&self,
from_addr: &str,
rcpts: impl Iterator<Item = impl AsRef<str> + Sync + Send> + Sync + Send,
report: Vec<u8>,
sign_config: &IfBlock,
deliver_now: bool,
parent_session_id: u64,
) -> impl Future<Output = ()> + Send;
fn send_autogenerated(
&self,
from_addr: impl AsRef<str> + Sync + Send,
rcpts: impl Iterator<Item = impl AsRef<str> + Sync + Send> + Sync + Send,
raw_message: Vec<u8>,
sign_config: Option<&IfBlock>,
parent_session_id: u64,
) -> impl Future<Output = ()> + Send;
fn schedule_report(
&self,
report: impl Into<ReportingEvent> + Sync + Send,
) -> impl Future<Output = ()> + Send;
}
impl MtaReportSend for Server {
async fn is_local_report_domain(&self, domain: &str, session_id: u64) -> bool {
match self.domain(domain).await {
Ok(domain) => domain.is_some(),
Err(err) => {
trc::error!(
err.caused_by(trc::location!())
.span_id(session_id)
.details("Failed to lookup local domain")
);
false
}
}
}
async fn send_report(
&self,
from_addr: &str,
rcpts: impl Iterator<Item = impl AsRef<str> + Sync + Send> + Sync + Send,
report: Vec<u8>,
sign_config: &IfBlock,
deliver_now: bool,
parent_session_id: u64,
) {
// Build message
let mut message = self.new_message(from_addr, MessageSource::Report, parent_session_id);
for rcpt_ in rcpts {
message.add_expanded_recipient(rcpt_.as_ref(), self).await;
}
// Schedule delivery at a random time between now and the next 3 hours
if !deliver_now {
#[cfg(not(feature = "test_mode"))]
{
use common::config::smtp::queue::QueueExpiry;
use rand::RngExt;
let delivery_time = rand::rng().random_range(0u64..10800u64);
for rcpt in &mut message.message.recipients {
rcpt.retry.due += delivery_time;
rcpt.notify.due += delivery_time;
if let QueueExpiry::Ttl(expires) = &mut rcpt.expires {
*expires += delivery_time;
}
}
}
}
// Queue message
let dkim_signers = self
.eval_signers(sign_config, &message.message, parent_session_id)
.await;
message
.queue(
QueueParams::new(&report, parent_session_id, self).with_dkim_signers(dkim_signers),
)
.await;
}
async fn send_autogenerated(
&self,
from_addr: impl AsRef<str> + Sync + Send,
rcpts: impl Iterator<Item = impl AsRef<str> + Sync + Send> + Sync + Send,
raw_message: Vec<u8>,
sign_config: Option<&IfBlock>,
parent_session_id: u64,
) {
// Build message
let mut message = self.new_message(
from_addr.as_ref(),
MessageSource::Autogenerated,
parent_session_id,
);
for rcpt in rcpts {
message.add_expanded_recipient(rcpt, self).await;
}
// Queue message
let dkim_signers = if let Some(sign_config) = sign_config {
self.eval_signers(sign_config, &message.message, parent_session_id)
.await
} else {
None
};
message
.queue(
QueueParams::new(&raw_message, parent_session_id, self)
.with_dkim_signers(dkim_signers),
)
.await;
}
async fn schedule_report(&self, report: impl Into<ReportingEvent> + Sync + Send) {
if self.inner.ipc.report_tx.send(report.into()).await.is_err() {
trc::event!(
Server(trc::ServerEvent::ThreadError),
CausedBy = trc::location!(),
Details = "Failed to send event to ReportScheduler"
);
}
}
}