From: Shannon Sterz <s.sterz@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox v3 2/4] notify: switch sendmail endpoint over to new crate
Date: Mon, 2 Dec 2024 15:16:53 +0100 [thread overview]
Message-ID: <20241202141655.254472-2-s.sterz@proxmox.com> (raw)
In-Reply-To: <20241202141655.254472-1-s.sterz@proxmox.com>
use the new `proxmox-sendmail` crate instead of the bespoke
implementation in `proxmox-notify`.
Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
proxmox-notify/Cargo.toml | 3 +-
proxmox-notify/src/endpoints/sendmail.rs | 172 ++---------------------
2 files changed, 10 insertions(+), 165 deletions(-)
diff --git a/proxmox-notify/Cargo.toml b/proxmox-notify/Cargo.toml
index b5b3719e..6e94930a 100644
--- a/proxmox-notify/Cargo.toml
+++ b/proxmox-notify/Cargo.toml
@@ -32,6 +32,7 @@ proxmox-human-byte.workspace = true
proxmox-schema = { workspace = true, features = ["api-macro", "api-types"] }
proxmox-section-config = { workspace = true }
proxmox-serde.workspace = true
+proxmox-sendmail = { workspace = true, optional = true }
proxmox-sys = { workspace = true, optional = true }
proxmox-time.workspace = true
proxmox-uuid = { workspace = true, features = ["serde"] }
@@ -39,7 +40,7 @@ proxmox-uuid = { workspace = true, features = ["serde"] }
[features]
default = ["sendmail", "gotify", "smtp", "webhook"]
mail-forwarder = ["dep:mail-parser", "dep:proxmox-sys"]
-sendmail = ["dep:proxmox-sys", "dep:base64"]
+sendmail = ["dep:proxmox-sys", "dep:base64", "dep:proxmox-sendmail"]
gotify = ["dep:proxmox-http"]
pve-context = ["dep:proxmox-sys"]
pbs-context = ["dep:proxmox-sys"]
diff --git a/proxmox-notify/src/endpoints/sendmail.rs b/proxmox-notify/src/endpoints/sendmail.rs
index d31b9672..c5e16fe4 100644
--- a/proxmox-notify/src/endpoints/sendmail.rs
+++ b/proxmox-notify/src/endpoints/sendmail.rs
@@ -137,15 +137,14 @@ impl Endpoint for SendmailEndpoint {
.clone()
.unwrap_or_else(|| context().default_sendmail_author());
- sendmail(
- &recipients_str,
- &subject,
- &text_part,
- &html_part,
- &mailfrom,
- &author,
- )
- .map_err(|err| Error::NotifyFailed(self.config.name.clone(), err.into()))
+ let mut mail = Mail::new(&author, &mailfrom, &subject, &text_part)
+ .with_html_alt(&html_part)
+ .with_unmasked_recipients();
+
+ recipients_str.iter().for_each(|r| mail.add_recipient(r));
+
+ mail.send()
+ .map_err(|err| Error::NotifyFailed(self.config.name.clone(), err.into()))
}
#[cfg(feature = "mail-forwarder")]
Content::ForwardedMail { raw, uid, .. } => {
@@ -165,107 +164,6 @@ impl Endpoint for SendmailEndpoint {
}
}
-/// Sends multi-part mail with text and/or html to a list of recipients
-///
-/// Includes the header `Auto-Submitted: auto-generated`, so that auto-replies
-/// (i.e. OOO replies) won't trigger.
-/// ``sendmail`` is used for sending the mail.
-fn sendmail(
- mailto: &[&str],
- subject: &str,
- text: &str,
- html: &str,
- mailfrom: &str,
- author: &str,
-) -> Result<(), Error> {
- if mailto.is_empty() {
- return Err(Error::Generic(
- "At least one recipient has to be specified!".into(),
- ));
- }
- let now = proxmox_time::epoch_i64();
- let body = format_mail(mailto, mailfrom, author, subject, text, html, now)?;
-
- let mut sendmail_process = Command::new("/usr/sbin/sendmail")
- .arg("-B")
- .arg("8BITMIME")
- .arg("-f")
- .arg(mailfrom)
- .arg("--")
- .args(mailto)
- .stdin(Stdio::piped())
- .spawn()
- .map_err(|err| Error::Generic(format!("could not spawn sendmail process: {err}")))?;
-
- sendmail_process
- .stdin
- .take()
- .expect("stdin already taken")
- .write_all(body.as_bytes())
- .map_err(|err| Error::Generic(format!("couldn't write to sendmail stdin: {err}")))?;
-
- sendmail_process
- .wait()
- .map_err(|err| Error::Generic(format!("sendmail did not exit successfully: {err}")))?;
-
- Ok(())
-}
-
-fn format_mail(
- mailto: &[&str],
- mailfrom: &str,
- author: &str,
- subject: &str,
- text: &str,
- html: &str,
- timestamp: i64,
-) -> Result<String, Error> {
- use std::fmt::Write as _;
-
- let recipients = mailto.join(",");
- let boundary = format!("----_=_NextPart_001_{timestamp}");
-
- let mut body = String::new();
-
- // Format email header
- body.push_str("Content-Type: multipart/alternative;\n");
- let _ = writeln!(body, "\tboundary=\"{boundary}\"");
- body.push_str("MIME-Version: 1.0\n");
-
- if !subject.is_ascii() {
- let _ = writeln!(body, "Subject: =?utf-8?B?{}?=", base64::encode(subject));
- } else {
- let _ = writeln!(body, "Subject: {subject}");
- }
- let _ = writeln!(body, "From: {author} <{mailfrom}>");
- let _ = writeln!(body, "To: {recipients}");
- let rfc2822_date = proxmox_time::epoch_to_rfc2822(timestamp)
- .map_err(|err| Error::Generic(format!("failed to format time: {err}")))?;
- let _ = writeln!(body, "Date: {rfc2822_date}");
- body.push_str("Auto-Submitted: auto-generated;\n");
- body.push('\n');
-
- // Format email body
- body.push_str("This is a multi-part message in MIME format.\n");
- let _ = write!(body, "\n--{boundary}\n");
-
- body.push_str("Content-Type: text/plain;\n");
- body.push_str("\tcharset=\"UTF-8\"\n");
- body.push_str("Content-Transfer-Encoding: 8bit\n");
- body.push('\n');
- body.push_str(text);
- let _ = write!(body, "\n--{boundary}\n");
-
- body.push_str("Content-Type: text/html;\n");
- body.push_str("\tcharset=\"UTF-8\"\n");
- body.push_str("Content-Transfer-Encoding: 8bit\n");
- body.push('\n');
- body.push_str(html);
- let _ = write!(body, "\n--{boundary}--");
-
- Ok(body)
-}
-
/// Forwards an email message to a given list of recipients.
///
/// ``sendmail`` is used for sending the mail, thus `message` must be
@@ -313,57 +211,3 @@ fn forward(mailto: &[&str], mailfrom: &str, message: &[u8], uid: Option<u32>) ->
Ok(())
}
-
-#[cfg(test)]
-mod test {
- use super::*;
-
- #[test]
- fn email_without_recipients() {
- let result = sendmail(&[], "Subject2", "", "<b>HTML</b>", "root", "Proxmox");
- assert!(result.is_err());
- }
-
- #[test]
- fn test_format_mail_multipart() {
- let message = format_mail(
- &["Tony Est <test@example.com>"],
- "foobar@example.com",
- "Fred Oobar",
- "This is the subject",
- "This is the plain body",
- "<body>This is the HTML body</body>",
- 1718977850,
- )
- .expect("format_message failed");
-
- assert_eq!(
- message,
- r#"Content-Type: multipart/alternative;
- boundary="----_=_NextPart_001_1718977850"
-MIME-Version: 1.0
-Subject: This is the subject
-From: Fred Oobar <foobar@example.com>
-To: Tony Est <test@example.com>
-Date: Fri, 21 Jun 2024 15:50:50 +0200
-Auto-Submitted: auto-generated;
-
-This is a multi-part message in MIME format.
-
-------_=_NextPart_001_1718977850
-Content-Type: text/plain;
- charset="UTF-8"
-Content-Transfer-Encoding: 8bit
-
-This is the plain body
-------_=_NextPart_001_1718977850
-Content-Type: text/html;
- charset="UTF-8"
-Content-Transfer-Encoding: 8bit
-
-<body>This is the HTML body</body>
-------_=_NextPart_001_1718977850--"#
- .to_owned()
- );
- }
-}
--
2.39.5
_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel
next prev parent reply other threads:[~2024-12-02 14:17 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-12-02 14:16 [pbs-devel] [PATCH proxmox v3 1/4] sendmail: add sendmail crate Shannon Sterz
2024-12-02 14:16 ` Shannon Sterz [this message]
2024-12-02 14:16 ` [pbs-devel] [PATCH proxmox v3 3/4] sendmail: add mail-forwarder feature Shannon Sterz
2024-12-02 14:16 ` [pbs-devel] [PATCH proxmox v3 4/4] notify: use proxmox-sendmail forward implementation Shannon Sterz
2024-12-02 14:22 ` [pbs-devel] [PATCH proxmox v3 1/4] sendmail: add sendmail crate Shannon Sterz
2024-12-02 14:33 ` Lukas Wagner
2024-12-02 14:42 ` Shannon Sterz
2024-12-02 14:45 ` [pbs-devel] applied-series: " Thomas Lamprecht
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241202141655.254472-2-s.sterz@proxmox.com \
--to=s.sterz@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox