Add footer

- Add a footer to each mail resulting from a split into an encrypted and
  an unencrypted version. The footer contains the recipients of the mail
  which are excluded in the corresponding stream.
- Move the construction of the `HuskContext` to the `mail`
  milter-command, as `helo` is used by scrapers to detect mailservers.
- Use `CertD::trust_root()` to get the trust root - it creates one if no
  root can be found.
- Add `chrono` dependency.
This commit is contained in:
Malte Meiboom
2026-07-14 11:28:34 +02:00
parent 8b2f284916
commit d54cc480b4
6 changed files with 102 additions and 54 deletions
+54
View File
@@ -11,8 +11,10 @@ use lettre::transport::smtp::{
use lettre::Address;
use tokio::task::JoinSet;
use std::time::Duration;
use chrono::Utc;
use crate::types::cheader::CHeader;
use crate::types::defaults;
use crate::types::errors::HuskError;
use crate::types::recipient::Recipient;
@@ -128,3 +130,55 @@ pub async fn smtp_inject(from: String, to: &Vec<Recipient<'_>>, header: CHeader,
}
}
pub fn generate_footer(rcpts: &Vec<Recipient>) -> String {
internal_generate_footer(Utc::now().to_rfc2822(), rcpts)
}
pub(crate) fn internal_generate_footer(now: String, other_rpcts: &Vec<Recipient>) -> String {
let mut footer = defaults::FOOTER.replace("{date}", now.as_str());
if ! other_rpcts.is_empty() {
let rcpts = other_rpcts.iter()
.map(|r| r.email.clone())
.collect::<Vec<String>>()
.join(", ");
footer.push_str(
defaults::FOOTER_RECIPIENTS.replace(
"{rcpts}",
&rcpts).as_str()
);
}
footer
}
#[cfg(test)]
pub mod tests {
use crate::mail::internal_generate_footer;
use crate::types::recipient::Recipient;
#[test]
fn test_footer() {
let rcpts = vec![
Recipient {
email: "alice@example.com".to_string(),
certs: Vec::new()
},
Recipient {
email: "bob@example.com".to_string(),
certs: Vec::new()
}
];
let footer = internal_generate_footer(
"1.1.1970".to_string(),
&rcpts
);
assert!(footer.contains("1.1.1970"));
assert!(footer.contains("alice@example.com"));
assert!(footer.contains("bob@example.com"));
}
}