From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id A42011FF138 for ; Mon, 15 Jun 2026 15:21:37 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 338F415B0D; Mon, 15 Jun 2026 15:21:36 +0200 (CEST) Mime-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=UTF-8 Date: Mon, 15 Jun 2026 15:21:00 +0200 Message-Id: Subject: Re: [PATCH proxmox 1/1] sendmail: add additional header map To: "Nicolas Frey" , X-Mailer: aerc 0.20.0 References: <20260615092015.101174-1-n.frey@proxmox.com> In-Reply-To: <20260615092015.101174-1-n.frey@proxmox.com> From: "Shannon Sterz" X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1781529607184 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.108 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [lib.rs] Message-ID-Hash: MGOLYXYFDHF3REVMKJGSCWTLFFGBWZBD X-Message-ID-Hash: MGOLYXYFDHF3REVMKJGSCWTLFFGBWZBD X-MailFrom: s.sterz@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: On Mon Jun 15, 2026 at 11:20 AM CEST, Nicolas Frey wrote: > with corresponding methods to add them. > generally i like the idea of allowing callers to specify additional headers, but i wonder if this is a bit too lenient. usually, we try to handle all encoding and formatting for the caller here, so we can deal with being in compliance with all rfcs and mail related conventions here instead of all call-sites. also this would allow setting headers that are set by proxmox-sendmail anyway twice. that's probably not ideal either. so imo, we should either: * expose at least the formatting helpers here publically so callers can use them. * allow only a limitted set of headers, maybe we an enum. we can then handle formatting for the caller be seeing which enum type was provided what do you think? > this does not check for duplicates for the ones already set by other > fields/defaults (e.g. To, From, Content-Type, etc.) > > Signed-off-by: Nicolas Frey > --- > proxmox-sendmail/src/lib.rs | 47 +++++++++++++++++++++++++++++++++++++ > 1 file changed, 47 insertions(+) > > diff --git a/proxmox-sendmail/src/lib.rs b/proxmox-sendmail/src/lib.rs > index db751305..355a84c2 100644 > --- a/proxmox-sendmail/src/lib.rs > +++ b/proxmox-sendmail/src/lib.rs > @@ -3,6 +3,7 @@ > //! and alternative html parts to one or multiple receivers via ``sendma= il``. > //! > > +use std::collections::HashMap; > use std::io::Write; > use std::process::{Command, Stdio}; > > @@ -247,6 +248,7 @@ pub struct Mail<'a> { > attachments: Vec>, > mask_participants: bool, > noreply: Option, > + additional_headers: HashMap, > } > > impl<'a> Mail<'a> { > @@ -265,6 +267,7 @@ impl<'a> Mail<'a> { > attachments: Vec::new(), > mask_participants: true, > noreply: None, > + additional_headers: HashMap::new(), > } > } > > @@ -393,6 +396,20 @@ impl<'a> Mail<'a> { > self > } > > + /// Set an arbitrary header to be sent in addition to the default on= es already set up by other > + /// methods. > + pub fn set_header(&mut self, name: S, body: S) { > + self.additional_headers > + .insert(name.to_string(), body.to_string()); > + } > + > + /// Builder-style method to set an arbitrary header in addition to t= he default ones already > + /// set up by other methods. > + pub fn with_header(mut self, name: S, body: S) -> Self = { > + self.set_header(name, body); > + self > + } > + > /// Sends the email. This will fail if no recipients have been added= . > /// > /// Note: An `Auto-Submitted: auto-generated` header is added to avo= id triggering OOO and > @@ -584,6 +601,11 @@ impl<'a> Mail<'a> { > let rfc2822_date =3D proxmox_time::epoch_to_rfc2822(now) > .with_context(|| "could not convert epoch to rfc2822 date")?= ; > writeln!(header, "Date: {rfc2822_date}")?; > + > + for (name, body) in &self.additional_headers { > + writeln!(header, "{name}: {body}")?; > + } > + > header.push_str("Auto-Submitted: auto-generated;\n"); > > Ok(header) > @@ -681,6 +703,31 @@ mod test { > assert!(result.is_err()); > } > > + #[test] > + fn additional_headers() { > + let mail =3D Mail::new("Sender", "mail@example.com", "hi", "body= ") > + .with_recipient_and_name("Jane Doe", "j.doe@example.com") > + .with_header("Reply-To", "mail@example.com") > + .with_header("CC", "cc1@example.com,cc2@example.com"); > + let body =3D mail.format_mail(0).expect("could not format mail")= ; > + > + assert_lines_equal_ignore_date( > + &body, > + r#"Subject: hi > +From: Sender > +To: Jane Doe > +Date: Thu, 01 Jan 1970 01:00:00 +0100 > +Reply-To: mail@example.com > +CC: cc1@example.com,cc2@example.com > +Auto-Submitted: auto-generated; > +Content-Type: text/plain; > + charset=3D"UTF-8" > +Content-Transfer-Encoding: 7bit > + > +body"#, > + ) > + } > + > #[test] > fn simple_ascii_text_mail() { > let mail =3D Mail::new(