From: Lukas Wagner <l.wagner@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH v4 proxmox 04/11] notify: add mechanisms for email message forwarding
Date: Wed, 8 Nov 2023 16:39:58 +0100 [thread overview]
Message-ID: <20231108154005.895814-5-l.wagner@proxmox.com> (raw)
In-Reply-To: <20231108154005.895814-1-l.wagner@proxmox.com>
As preparation for the integration of `proxmox-mail-foward` into the
notification system, this commit makes a few changes that allow us to
forward raw email messages (as passed from postfix).
For mail-based notification targets, the email will be forwarded
as-is, including all headers. The only thing that changes is the
message envelope.
For other notification targets, the mail is parsed using the
`mail-parser` crate, which allows us to extract a subject and a body.
As a body we use the plain-text version of the mail. If an email is
HTML-only, the `mail-parser` crate will automatically attempt to
transform the HTML into readable plain text.
Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
---
Cargo.toml | 1 +
proxmox-notify/Cargo.toml | 2 ++
proxmox-notify/src/endpoints/gotify.rs | 3 ++
proxmox-notify/src/endpoints/sendmail.rs | 5 +++
proxmox-notify/src/lib.rs | 41 ++++++++++++++++++++++++
5 files changed, 52 insertions(+)
diff --git a/Cargo.toml b/Cargo.toml
index f8bc181..3d81d85 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -64,6 +64,7 @@ lazy_static = "1.4"
ldap3 = { version = "0.11", default-features = false }
libc = "0.2.107"
log = "0.4.17"
+mail-parser = "0.8.2"
native-tls = "0.2"
nix = "0.26.1"
once_cell = "1.3.1"
diff --git a/proxmox-notify/Cargo.toml b/proxmox-notify/Cargo.toml
index 4812896..f2b4db5 100644
--- a/proxmox-notify/Cargo.toml
+++ b/proxmox-notify/Cargo.toml
@@ -12,6 +12,7 @@ anyhow.workspace = true
handlebars = { workspace = true }
lazy_static.workspace = true
log.workspace = true
+mail-parser = { workspace = true, optional = true }
once_cell.workspace = true
openssl.workspace = true
proxmox-http = { workspace = true, features = ["client-sync"], optional = true }
@@ -28,5 +29,6 @@ serde_json.workspace = true
[features]
default = ["sendmail", "gotify"]
+mail-forwarder = ["dep:mail-parser"]
sendmail = ["dep:proxmox-sys"]
gotify = ["dep:proxmox-http"]
diff --git a/proxmox-notify/src/endpoints/gotify.rs b/proxmox-notify/src/endpoints/gotify.rs
index 1c307a4..5713d99 100644
--- a/proxmox-notify/src/endpoints/gotify.rs
+++ b/proxmox-notify/src/endpoints/gotify.rs
@@ -19,6 +19,7 @@ fn severity_to_priority(level: Severity) -> u32 {
Severity::Notice => 3,
Severity::Warning => 5,
Severity::Error => 9,
+ Severity::Unknown => 3,
}
}
@@ -94,6 +95,8 @@ impl Endpoint for GotifyEndpoint {
(rendered_title, rendered_message)
}
+ #[cfg(feature = "mail-forwarder")]
+ Content::ForwardedMail { title, body, .. } => (title.clone(), body.clone()),
};
// We don't have a TemplateRenderer::Markdown yet, so simply put everything
diff --git a/proxmox-notify/src/endpoints/sendmail.rs b/proxmox-notify/src/endpoints/sendmail.rs
index a601744..3ef33b6 100644
--- a/proxmox-notify/src/endpoints/sendmail.rs
+++ b/proxmox-notify/src/endpoints/sendmail.rs
@@ -134,6 +134,11 @@ impl Endpoint for SendmailEndpoint {
)
.map_err(|err| Error::NotifyFailed(self.config.name.clone(), err.into()))
}
+ #[cfg(feature = "mail-forwarder")]
+ Content::ForwardedMail { raw, uid, .. } => {
+ proxmox_sys::email::forward(&recipients_str, &mailfrom, raw, *uid)
+ .map_err(|err| Error::NotifyFailed(self.config.name.clone(), err.into()))
+ }
}
}
diff --git a/proxmox-notify/src/lib.rs b/proxmox-notify/src/lib.rs
index 9997cef..ada1b0a 100644
--- a/proxmox-notify/src/lib.rs
+++ b/proxmox-notify/src/lib.rs
@@ -102,6 +102,8 @@ pub enum Severity {
Warning,
/// Error
Error,
+ /// Unknown severity (e.g. forwarded system mails)
+ Unknown,
}
impl Display for Severity {
@@ -111,6 +113,7 @@ impl Display for Severity {
Severity::Notice => f.write_str("notice"),
Severity::Warning => f.write_str("warning"),
Severity::Error => f.write_str("error"),
+ Severity::Unknown => f.write_str("unknown"),
}
}
}
@@ -123,6 +126,7 @@ impl FromStr for Severity {
"notice" => Ok(Self::Notice),
"warning" => Ok(Self::Warning),
"error" => Ok(Self::Error),
+ "unknown" => Ok(Self::Unknown),
_ => Err(Error::Generic(format!("invalid severity {s}"))),
}
}
@@ -148,6 +152,18 @@ pub enum Content {
/// Data that can be used for template rendering.
data: Value,
},
+ #[cfg(feature = "mail-forwarder")]
+ ForwardedMail {
+ /// Raw mail contents
+ raw: Vec<u8>,
+ /// Fallback title
+ title: String,
+ /// Fallback body
+ body: String,
+ /// UID to use when calling sendmail
+ #[allow(dead_code)] // Unused in some feature flag permutations
+ uid: Option<u32>,
+ },
}
#[derive(Debug, Clone)]
@@ -190,6 +206,31 @@ impl Notification {
},
}
}
+ #[cfg(feature = "mail-forwarder")]
+ pub fn new_forwarded_mail(raw_mail: &[u8], uid: Option<u32>) -> Result<Self, Error> {
+ let message = mail_parser::Message::parse(raw_mail)
+ .ok_or_else(|| Error::Generic("could not parse forwarded email".to_string()))?;
+
+ let title = message.subject().unwrap_or_default().into();
+ let body = message.body_text(0).unwrap_or_default().into();
+
+ Ok(Self {
+ // Unfortunately we cannot reasonably infer the severity from the
+ // mail contents, so just set it to the highest for now so that
+ // it is not filtered out.
+ content: Content::ForwardedMail {
+ raw: raw_mail.into(),
+ title,
+ body,
+ uid,
+ },
+ metadata: Metadata {
+ severity: Severity::Unknown,
+ additional_fields: Default::default(),
+ timestamp: proxmox_time::epoch_i64(),
+ },
+ })
+ }
}
/// Notification configuration
--
2.39.2
next prev parent reply other threads:[~2023-11-08 15:40 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-11-08 15:39 [pve-devel] [PATCH v4 many 00/11] notifications: add SMTP endpoint Lukas Wagner
2023-11-08 15:39 ` [pve-devel] [PATCH v4 debcargo-conf 01/11] cherry-pick chumsky 0.9.2 from debian unstable Lukas Wagner
2023-11-08 15:39 ` [pve-devel] [PATCH v4 debcargo-conf 02/11] update lettre to 0.11.1 Lukas Wagner
2023-11-08 15:39 ` [pve-devel] [PATCH v4 proxmox 03/11] sys: email: add `forward` Lukas Wagner
2023-11-08 15:39 ` Lukas Wagner [this message]
2023-11-08 15:39 ` [pve-devel] [PATCH v4 proxmox 05/11] notify: add 'smtp' endpoint Lukas Wagner
2023-11-08 15:40 ` [pve-devel] [PATCH v4 proxmox 06/11] notify: add api for smtp endpoints Lukas Wagner
2023-11-08 15:40 ` [pve-devel] [PATCH v4 proxmox-perl-rs 07/11] notify: add bindings for smtp API calls Lukas Wagner
2023-11-08 15:40 ` [pve-devel] [PATCH v4 pve-manager 08/11] notify: add API routes for smtp endpoints Lukas Wagner
2023-11-08 15:40 ` [pve-devel] [PATCH v4 proxmox-widget-toolkit 09/11] panel: notification: add gui for SMTP endpoints Lukas Wagner
2023-11-08 15:40 ` [pve-devel] [PATCH v4 pve-docs 10/11] notifications: document " Lukas Wagner
2023-11-08 15:40 ` [pve-devel] [PATCH v4 pve-docs 11/11] notifications: document 'comment' option for targets/matchers Lukas Wagner
2023-11-08 15:52 ` [pve-devel] [PATCH v4 many 00/11] notifications: add SMTP endpoint Dietmar Maurer
2023-11-09 10:23 ` Lukas Wagner
2023-11-09 12:16 ` Dietmar Maurer
2023-11-09 12:34 ` Lukas Wagner
2023-11-09 13:10 ` Thomas Lamprecht
2023-11-09 15:35 ` Dietmar Maurer
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=20231108154005.895814-5-l.wagner@proxmox.com \
--to=l.wagner@proxmox.com \
--cc=pve-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.