You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-08-06 06:02:40 +03:00
Flatten the email config
This commit is contained in:
@@ -16,7 +16,7 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use mas_config::{
|
use mas_config::{
|
||||||
BrandingConfig, DatabaseConfig, EmailConfig, EmailSmtpMode, EmailTransportConfig,
|
BrandingConfig, DatabaseConfig, EmailConfig, EmailSmtpMode, EmailTransportKind,
|
||||||
PasswordsConfig, PolicyConfig, TemplatesConfig,
|
PasswordsConfig, PolicyConfig, TemplatesConfig,
|
||||||
};
|
};
|
||||||
use mas_email::{MailTransport, Mailer};
|
use mas_email::{MailTransport, Mailer};
|
||||||
@@ -61,17 +61,28 @@ pub fn mailer_from_config(
|
|||||||
) -> Result<Mailer, anyhow::Error> {
|
) -> Result<Mailer, anyhow::Error> {
|
||||||
let from = config.from.parse()?;
|
let from = config.from.parse()?;
|
||||||
let reply_to = config.reply_to.parse()?;
|
let reply_to = config.reply_to.parse()?;
|
||||||
let transport = match &config.transport {
|
let transport = match config.transport() {
|
||||||
EmailTransportConfig::Blackhole => MailTransport::blackhole(),
|
EmailTransportKind::Blackhole => MailTransport::blackhole(),
|
||||||
EmailTransportConfig::Smtp {
|
EmailTransportKind::Smtp => {
|
||||||
mode,
|
// This should have been set ahead of time
|
||||||
hostname,
|
let hostname = config
|
||||||
credentials,
|
.hostname()
|
||||||
port,
|
.context("invalid configuration: missing hostname")?;
|
||||||
} => {
|
|
||||||
let credentials = credentials
|
let mode = config
|
||||||
.clone()
|
.mode()
|
||||||
.map(|c| mas_email::SmtpCredentials::new(c.username, c.password));
|
.context("invalid configuration: missing mode")?;
|
||||||
|
|
||||||
|
let credentials = match (config.username(), config.password()) {
|
||||||
|
(Some(username), Some(password)) => Some(mas_email::SmtpCredentials::new(
|
||||||
|
username.to_owned(),
|
||||||
|
password.to_owned(),
|
||||||
|
)),
|
||||||
|
(None, None) => None,
|
||||||
|
_ => {
|
||||||
|
anyhow::bail!("invalid configuration: missing username or password");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mode = match mode {
|
let mode = match mode {
|
||||||
EmailSmtpMode::Plain => mas_email::SmtpMode::Plain,
|
EmailSmtpMode::Plain => mas_email::SmtpMode::Plain,
|
||||||
@@ -79,12 +90,10 @@ pub fn mailer_from_config(
|
|||||||
EmailSmtpMode::Tls => mas_email::SmtpMode::Tls,
|
EmailSmtpMode::Tls => mas_email::SmtpMode::Tls,
|
||||||
};
|
};
|
||||||
|
|
||||||
MailTransport::smtp(mode, hostname, port.as_ref().copied(), credentials)
|
MailTransport::smtp(mode, hostname, config.port(), credentials)
|
||||||
.context("failed to build SMTP transport")?
|
.context("failed to build SMTP transport")?
|
||||||
}
|
}
|
||||||
EmailTransportConfig::Sendmail { command } => MailTransport::sendmail(command),
|
EmailTransportKind::Sendmail => MailTransport::sendmail(config.command()),
|
||||||
#[allow(deprecated)]
|
|
||||||
EmailTransportConfig::AwsSes => anyhow::bail!("AWS SESv2 backend has been removed"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Mailer::new(templates.clone(), transport, from, reply_to))
|
Ok(Mailer::new(templates.clone(), transport, from, reply_to))
|
||||||
|
@@ -19,7 +19,7 @@ use std::num::NonZeroU16;
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{de::Error, Deserialize, Serialize};
|
||||||
|
|
||||||
use super::ConfigurationSection;
|
use super::ConfigurationSection;
|
||||||
|
|
||||||
@@ -47,55 +47,27 @@ pub enum EmailSmtpMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// What backend should be used when sending emails
|
/// What backend should be used when sending emails
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, Default)]
|
||||||
#[serde(tag = "transport", rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum EmailTransportConfig {
|
pub enum EmailTransportKind {
|
||||||
/// Don't send emails anywhere
|
/// Don't send emails anywhere
|
||||||
|
#[default]
|
||||||
Blackhole,
|
Blackhole,
|
||||||
|
|
||||||
/// Send emails via an SMTP relay
|
/// Send emails via an SMTP relay
|
||||||
Smtp {
|
Smtp,
|
||||||
/// Connection mode to the relay
|
|
||||||
mode: EmailSmtpMode,
|
|
||||||
|
|
||||||
/// Hostname to connect to
|
|
||||||
#[schemars(with = "crate::schema::Hostname")]
|
|
||||||
hostname: String,
|
|
||||||
|
|
||||||
/// Port to connect to. Default is 25 for plain, 465 for TLS and 587 for
|
|
||||||
/// StartTLS
|
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
||||||
port: Option<NonZeroU16>,
|
|
||||||
|
|
||||||
/// Set of credentials to use
|
|
||||||
#[serde(flatten, default)]
|
|
||||||
credentials: Option<Credentials>,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Send emails by calling sendmail
|
/// Send emails by calling sendmail
|
||||||
Sendmail {
|
Sendmail,
|
||||||
/// Command to execute
|
|
||||||
#[serde(default = "default_sendmail_command")]
|
|
||||||
command: String,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Send emails via the AWS SESv2 API
|
|
||||||
#[deprecated(note = "The AWS SESv2 backend has be removed.")]
|
|
||||||
AwsSes,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for EmailTransportConfig {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Blackhole
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_email() -> String {
|
fn default_email() -> String {
|
||||||
r#""Authentication Service" <root@localhost>"#.to_owned()
|
r#""Authentication Service" <root@localhost>"#.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_sendmail_command() -> String {
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
"sendmail".to_owned()
|
fn default_sendmail_command() -> Option<String> {
|
||||||
|
Some("sendmail".to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration related to sending emails
|
/// Configuration related to sending emails
|
||||||
@@ -112,8 +84,85 @@ pub struct EmailConfig {
|
|||||||
pub reply_to: String,
|
pub reply_to: String,
|
||||||
|
|
||||||
/// What backend should be used when sending emails
|
/// What backend should be used when sending emails
|
||||||
#[serde(flatten, default)]
|
transport: EmailTransportKind,
|
||||||
pub transport: EmailTransportConfig,
|
|
||||||
|
/// SMTP transport: Connection mode to the relay
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
mode: Option<EmailSmtpMode>,
|
||||||
|
|
||||||
|
/// SMTP transport: Hostname to connect to
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
#[schemars(with = "Option<crate::schema::Hostname>")]
|
||||||
|
hostname: Option<String>,
|
||||||
|
|
||||||
|
/// SMTP transport: Port to connect to. Default is 25 for plain, 465 for TLS
|
||||||
|
/// and 587 for StartTLS
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
#[schemars(range(min = 1, max = 65535))]
|
||||||
|
port: Option<NonZeroU16>,
|
||||||
|
|
||||||
|
/// SMTP transport: Username for use to authenticate when connecting to the
|
||||||
|
/// SMTP server
|
||||||
|
///
|
||||||
|
/// Must be set if the `password` field is set
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
username: Option<String>,
|
||||||
|
|
||||||
|
/// SMTP transport: Password for use to authenticate when connecting to the
|
||||||
|
/// SMTP server
|
||||||
|
///
|
||||||
|
/// Must be set if the `username` field is set
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
password: Option<String>,
|
||||||
|
|
||||||
|
/// Sendmail transport: Command to use to send emails
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
#[schemars(default = "default_sendmail_command")]
|
||||||
|
command: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmailConfig {
|
||||||
|
/// What backend should be used when sending emails
|
||||||
|
#[must_use]
|
||||||
|
pub fn transport(&self) -> EmailTransportKind {
|
||||||
|
self.transport
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Connection mode to the relay
|
||||||
|
#[must_use]
|
||||||
|
pub fn mode(&self) -> Option<EmailSmtpMode> {
|
||||||
|
self.mode
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hostname to connect to
|
||||||
|
#[must_use]
|
||||||
|
pub fn hostname(&self) -> Option<&str> {
|
||||||
|
self.hostname.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Port to connect to
|
||||||
|
#[must_use]
|
||||||
|
pub fn port(&self) -> Option<NonZeroU16> {
|
||||||
|
self.port
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Username for use to authenticate when connecting to the SMTP server
|
||||||
|
#[must_use]
|
||||||
|
pub fn username(&self) -> Option<&str> {
|
||||||
|
self.username.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Password for use to authenticate when connecting to the SMTP server
|
||||||
|
#[must_use]
|
||||||
|
pub fn password(&self) -> Option<&str> {
|
||||||
|
self.password.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Command to use to send emails
|
||||||
|
#[must_use]
|
||||||
|
pub fn command(&self) -> Option<&str> {
|
||||||
|
self.command.as_deref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for EmailConfig {
|
impl Default for EmailConfig {
|
||||||
@@ -121,7 +170,13 @@ impl Default for EmailConfig {
|
|||||||
Self {
|
Self {
|
||||||
from: default_email(),
|
from: default_email(),
|
||||||
reply_to: default_email(),
|
reply_to: default_email(),
|
||||||
transport: EmailTransportConfig::Blackhole,
|
transport: EmailTransportKind::Blackhole,
|
||||||
|
mode: None,
|
||||||
|
hostname: None,
|
||||||
|
port: None,
|
||||||
|
username: None,
|
||||||
|
password: None,
|
||||||
|
command: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,6 +192,98 @@ impl ConfigurationSection for EmailConfig {
|
|||||||
Ok(Self::default())
|
Ok(Self::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate(&self, figment: &figment::Figment) -> Result<(), figment::error::Error> {
|
||||||
|
let metadata = figment.find_metadata(Self::PATH.unwrap());
|
||||||
|
|
||||||
|
let error_on_field = |mut error: figment::error::Error, field: &'static str| {
|
||||||
|
error.metadata = metadata.cloned();
|
||||||
|
error.profile = Some(figment::Profile::Default);
|
||||||
|
error.path = vec![Self::PATH.unwrap().to_owned(), field.to_owned()];
|
||||||
|
error
|
||||||
|
};
|
||||||
|
|
||||||
|
let missing_field = |field: &'static str| {
|
||||||
|
error_on_field(figment::error::Error::missing_field(field), field)
|
||||||
|
};
|
||||||
|
|
||||||
|
let unexpected_field = |field: &'static str, expected_fields: &'static [&'static str]| {
|
||||||
|
error_on_field(
|
||||||
|
figment::error::Error::unknown_field(field, expected_fields),
|
||||||
|
field,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
match self.transport {
|
||||||
|
EmailTransportKind::Blackhole => {}
|
||||||
|
|
||||||
|
EmailTransportKind::Smtp => {
|
||||||
|
match (self.username.is_some(), self.password.is_some()) {
|
||||||
|
(true, true) | (false, false) => {}
|
||||||
|
(true, false) => {
|
||||||
|
return Err(missing_field("password"));
|
||||||
|
}
|
||||||
|
(false, true) => {
|
||||||
|
return Err(missing_field("username"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.mode.is_none() {
|
||||||
|
return Err(missing_field("mode"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.hostname.is_none() {
|
||||||
|
return Err(missing_field("hostname"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.command.is_some() {
|
||||||
|
return Err(unexpected_field(
|
||||||
|
"command",
|
||||||
|
&[
|
||||||
|
"from",
|
||||||
|
"reply_to",
|
||||||
|
"transport",
|
||||||
|
"mode",
|
||||||
|
"hostname",
|
||||||
|
"port",
|
||||||
|
"username",
|
||||||
|
"password",
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EmailTransportKind::Sendmail => {
|
||||||
|
let expected_fields = &["from", "reply_to", "transport", "command"];
|
||||||
|
|
||||||
|
if self.command.is_none() {
|
||||||
|
return Err(missing_field("command"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.mode.is_some() {
|
||||||
|
return Err(unexpected_field("mode", expected_fields));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.hostname.is_some() {
|
||||||
|
return Err(unexpected_field("hostname", expected_fields));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.port.is_some() {
|
||||||
|
return Err(unexpected_field("port", expected_fields));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.username.is_some() {
|
||||||
|
return Err(unexpected_field("username", expected_fields));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.password.is_some() {
|
||||||
|
return Err(unexpected_field("password", expected_fields));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn test() -> Self {
|
fn test() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
@@ -35,7 +35,7 @@ pub use self::{
|
|||||||
branding::BrandingConfig,
|
branding::BrandingConfig,
|
||||||
clients::{ClientAuthMethodConfig, ClientConfig, ClientsConfig},
|
clients::{ClientAuthMethodConfig, ClientConfig, ClientsConfig},
|
||||||
database::DatabaseConfig,
|
database::DatabaseConfig,
|
||||||
email::{EmailConfig, EmailSmtpMode, EmailTransportConfig},
|
email::{EmailConfig, EmailSmtpMode, EmailTransportKind},
|
||||||
experimental::ExperimentalConfig,
|
experimental::ExperimentalConfig,
|
||||||
http::{
|
http::{
|
||||||
BindConfig as HttpBindConfig, HttpConfig, ListenerConfig as HttpListenerConfig,
|
BindConfig as HttpBindConfig, HttpConfig, ListenerConfig as HttpListenerConfig,
|
||||||
|
@@ -92,10 +92,13 @@ impl Transport {
|
|||||||
|
|
||||||
/// Construct a Sendmail transport
|
/// Construct a Sendmail transport
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn sendmail(command: impl Into<OsString>) -> Self {
|
pub fn sendmail(command: Option<impl Into<OsString>>) -> Self {
|
||||||
Self::new(TransportInner::Sendmail(
|
let transport = if let Some(command) = command {
|
||||||
AsyncSendmailTransport::new_with_command(command),
|
AsyncSendmailTransport::new_with_command(command)
|
||||||
))
|
} else {
|
||||||
|
AsyncSendmailTransport::new()
|
||||||
|
};
|
||||||
|
Self::new(TransportInner::Sendmail(transport))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1348,106 +1348,9 @@
|
|||||||
"EmailConfig": {
|
"EmailConfig": {
|
||||||
"description": "Configuration related to sending emails",
|
"description": "Configuration related to sending emails",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"oneOf": [
|
|
||||||
{
|
|
||||||
"description": "Don't send emails anywhere",
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
"required": [
|
||||||
"transport"
|
"transport"
|
||||||
],
|
],
|
||||||
"properties": {
|
|
||||||
"transport": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"blackhole"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Send emails via an SMTP relay",
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"hostname",
|
|
||||||
"mode",
|
|
||||||
"transport"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"transport": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"smtp"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"mode": {
|
|
||||||
"description": "Connection mode to the relay",
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/EmailSmtpMode"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"hostname": {
|
|
||||||
"description": "Hostname to connect to",
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/Hostname"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"port": {
|
|
||||||
"description": "Port to connect to. Default is 25 for plain, 465 for TLS and 587 for StartTLS",
|
|
||||||
"type": "integer",
|
|
||||||
"format": "uint16",
|
|
||||||
"minimum": 1.0
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"description": "Username for use to authenticate when connecting to the SMTP server",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"description": "Password for use to authenticate when connecting to the SMTP server",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Send emails by calling sendmail",
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"transport"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"transport": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"sendmail"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"command": {
|
|
||||||
"description": "Command to execute",
|
|
||||||
"default": "sendmail",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Send emails via the AWS SESv2 API",
|
|
||||||
"deprecated": true,
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"transport"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"transport": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"aws_ses"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"from": {
|
"from": {
|
||||||
"description": "Email address to use as From when sending emails",
|
"description": "Email address to use as From when sending emails",
|
||||||
@@ -1460,9 +1363,79 @@
|
|||||||
"default": "\"Authentication Service\" <root@localhost>",
|
"default": "\"Authentication Service\" <root@localhost>",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "email"
|
"format": "email"
|
||||||
|
},
|
||||||
|
"transport": {
|
||||||
|
"description": "What backend should be used when sending emails",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/EmailTransportKind"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mode": {
|
||||||
|
"description": "SMTP transport: Connection mode to the relay",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/EmailSmtpMode"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hostname": {
|
||||||
|
"description": "SMTP transport: Hostname to connect to",
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/Hostname"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"description": "SMTP transport: Port to connect to. Default is 25 for plain, 465 for TLS and 587 for StartTLS",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint16",
|
||||||
|
"maximum": 65535.0,
|
||||||
|
"minimum": 1.0
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"description": "SMTP transport: Username for use to authenticate when connecting to the SMTP server\n\nMust be set if the `password` field is set",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"description": "SMTP transport: Password for use to authenticate when connecting to the SMTP server\n\nMust be set if the `username` field is set",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"command": {
|
||||||
|
"description": "Sendmail transport: Command to use to send emails",
|
||||||
|
"default": "sendmail",
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"EmailTransportKind": {
|
||||||
|
"description": "What backend should be used when sending emails",
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"description": "Don't send emails anywhere",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"blackhole"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Send emails via an SMTP relay",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"smtp"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Send emails by calling sendmail",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"sendmail"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"EmailSmtpMode": {
|
"EmailSmtpMode": {
|
||||||
"description": "Encryption mode to use",
|
"description": "Encryption mode to use",
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
|
Reference in New Issue
Block a user