notify: add sendmail plugin
This plugin uses the 'sendmail' command to send an email to one or more recipients. Signed-off-by: Lukas Wagner <l.wagner@proxmox.com>
This commit is contained in:
parent
714ef27786
commit
7c42752690
@ -8,12 +8,17 @@ repository.workspace = true
|
||||
exclude.workspace = true
|
||||
|
||||
[dependencies]
|
||||
handlebars = { workspace = true, optional = true }
|
||||
lazy_static.workspace = true
|
||||
log.workspace = true
|
||||
openssl.workspace = true
|
||||
proxmox-schema = { workspace = true, features = ["api-macro", "api-types"]}
|
||||
proxmox-section-config = { workspace = true }
|
||||
proxmox-sys.workspace = true
|
||||
proxmox-sys = { workspace = true, optional = true }
|
||||
regex.workspace = true
|
||||
serde.workspace = true
|
||||
serde = { workspace = true, features = ["derive"]}
|
||||
serde_json.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["sendmail"]
|
||||
sendmail = ["dep:handlebars", "dep:proxmox-sys"]
|
@ -13,6 +13,18 @@ lazy_static! {
|
||||
fn config_init() -> SectionConfig {
|
||||
let mut config = SectionConfig::new(&BACKEND_NAME_SCHEMA);
|
||||
|
||||
#[cfg(feature = "sendmail")]
|
||||
{
|
||||
use crate::endpoints::sendmail::{SendmailConfig, SENDMAIL_TYPENAME};
|
||||
|
||||
const SENDMAIL_SCHEMA: &ObjectSchema = SendmailConfig::API_SCHEMA.unwrap_object_schema();
|
||||
config.register_plugin(SectionConfigPlugin::new(
|
||||
SENDMAIL_TYPENAME.to_string(),
|
||||
Some(String::from("name")),
|
||||
SENDMAIL_SCHEMA,
|
||||
));
|
||||
}
|
||||
|
||||
config
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,2 @@
|
||||
#[cfg(feature = "sendmail")]
|
||||
pub mod sendmail;
|
89
proxmox-notify/src/endpoints/sendmail.rs
Normal file
89
proxmox-notify/src/endpoints/sendmail.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use crate::schema::{EMAIL_SCHEMA, ENTITY_NAME_SCHEMA, USER_SCHEMA};
|
||||
use crate::{Endpoint, Error, Notification};
|
||||
|
||||
use proxmox_schema::api_types::COMMENT_SCHEMA;
|
||||
use proxmox_schema::{api, Updater};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub(crate) const SENDMAIL_TYPENAME: &str = "sendmail";
|
||||
|
||||
#[api(
|
||||
properties: {
|
||||
name: {
|
||||
schema: ENTITY_NAME_SCHEMA,
|
||||
},
|
||||
mailto: {
|
||||
type: Array,
|
||||
items: {
|
||||
schema: EMAIL_SCHEMA,
|
||||
},
|
||||
},
|
||||
comment: {
|
||||
optional: true,
|
||||
schema: COMMENT_SCHEMA,
|
||||
},
|
||||
},
|
||||
)]
|
||||
#[derive(Debug, Serialize, Deserialize, Updater, Default)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
/// Config for Sendmail notification endpoints
|
||||
pub struct SendmailConfig {
|
||||
/// Name of the endpoint
|
||||
#[updater(skip)]
|
||||
pub name: String,
|
||||
/// Mail recipients
|
||||
pub mailto: Vec<String>,
|
||||
/// `From` address for the mail
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub from_address: Option<String>,
|
||||
/// Author of the mail
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub author: Option<String>,
|
||||
/// Comment
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub comment: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum DeleteableSendmailProperty {
|
||||
FromAddress,
|
||||
Author,
|
||||
Comment,
|
||||
}
|
||||
|
||||
/// A sendmail notification endpoint.
|
||||
pub struct SendmailEndpoint {
|
||||
pub config: SendmailConfig,
|
||||
}
|
||||
|
||||
impl Endpoint for SendmailEndpoint {
|
||||
fn send(&self, notification: &Notification) -> Result<(), Error> {
|
||||
let recipients: Vec<&str> = self.config.mailto.iter().map(String::as_str).collect();
|
||||
|
||||
// Note: OX has serious problems displaying text mails,
|
||||
// so we include html as well
|
||||
let html = format!(
|
||||
"<html><body><pre>\n{}\n<pre>",
|
||||
handlebars::html_escape(¬ification.body)
|
||||
);
|
||||
|
||||
// proxmox_sys::email::sendmail will set the author to
|
||||
// "Proxmox Backup Server" if it is not set.
|
||||
let author = self.config.author.as_deref().or(Some(""));
|
||||
|
||||
proxmox_sys::email::sendmail(
|
||||
&recipients,
|
||||
¬ification.title,
|
||||
Some(¬ification.body),
|
||||
Some(&html),
|
||||
self.config.from_address.as_deref(),
|
||||
author,
|
||||
)
|
||||
.map_err(|err| Error::NotifyFailed(self.config.name.clone(), err.into()))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
&self.config.name
|
||||
}
|
||||
}
|
@ -200,6 +200,24 @@ impl Bus {
|
||||
pub fn from_config(config: &Config) -> Result<Self, Error> {
|
||||
let mut endpoints = HashMap::new();
|
||||
|
||||
// Instantiate endpoints
|
||||
|
||||
#[cfg(feature = "sendmail")]
|
||||
{
|
||||
use endpoints::sendmail::SENDMAIL_TYPENAME;
|
||||
use endpoints::sendmail::{SendmailConfig, SendmailEndpoint};
|
||||
endpoints.extend(
|
||||
parse_endpoints_without_private_config!(
|
||||
config,
|
||||
SendmailConfig,
|
||||
SendmailEndpoint,
|
||||
SENDMAIL_TYPENAME
|
||||
)?
|
||||
.into_iter()
|
||||
.map(|e| (e.name().into(), e)),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Bus { endpoints })
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user