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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal