mirror of
https://github.com/stalwartlabs/mail-server.git
synced 2024-12-25 09:13:12 +08:00
Add enterprise cargo feature + Allow copying SEL licensed code for testing/development purposes (closes #602 closes #601)
This commit is contained in:
parent
e2fc705ad7
commit
38ff4b9ea0
19 changed files with 82 additions and 46 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -132,7 +132,7 @@ jobs:
|
|||
mkdir -p "${root}/target/${target}/release" && cd "$_"
|
||||
|
||||
if [ "${USE_FOUNDATIONDB:-0}" = 1 ]; then
|
||||
build -p mail-server --no-default-features --features "foundationdb elastic s3 redis"
|
||||
build -p mail-server --no-default-features --features "foundationdb elastic s3 redis enterprise"
|
||||
artifact stalwart-mail stalwart-mail-foundationdb
|
||||
fi
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Stalwart Enterprise License 1.0 (SELv1) Agreement
|
||||
=================================================
|
||||
|
||||
Last Update: June 26, 2024
|
||||
Last Update: July 8, 2024
|
||||
|
||||
PLEASE CAREFULLY READ THIS STALWART ENTERPRISE LICENSE AGREEMENT ("AGREEMENT"). THIS AGREEMENT CONSTITUTES A LEGALLY BINDING AGREEMENT BETWEEN YOU AND STALWART LABS LTD AND GOVERNS YOUR USE OF THE SOFTWARE (DEFINED BELOW). IF YOU DO NOT AGREE WITH THIS AGREEMENT, YOU MAY NOT USE THE SOFTWARE. IF YOU ARE USING THE SOFTWARE ON BEHALF OF A LEGAL ENTITY, YOU REPRESENT AND WARRANT THAT YOU HAVE AUTHORITY TO AGREE TO THIS AGREEMENT ON BEHALF OF SUCH ENTITY. IF YOU DO NOT HAVE SUCH AUTHORITY, DO NOT USE THE SOFTWARE IN ANY MANNER.
|
||||
|
||||
|
@ -10,9 +10,11 @@ This Agreement is entered into by and between Stalwart Labs Ltd and you, or the
|
|||
1. DEFINITIONS
|
||||
|
||||
1.1. "Software" refers to the Stalwart Mail Server Enterprise Edition software, including all its versions, updates, modifications, accompanying documentation, and related materials.
|
||||
1.2. "Licensor" refers to Stalwart Labs Ltd, the entity providing the Software.
|
||||
1.3. "Licensee" refers to the individual or entity installing, accessing, or using the Software.
|
||||
1.4. "License Key" refers to the unique code provided by Licensor upon purchasing a subscription which activates the full features of the Software.
|
||||
1.2. "Subscription" refers to the paid access to the Software provided by Licensor to Licensee.
|
||||
1.3. "Licensor" refers to Stalwart Labs Ltd, the entity providing the Software.
|
||||
1.4. "Licensee" refers to the individual or entity installing, accessing, or using the Software with a valid Subscription.
|
||||
1.5. "License Key" refers to the unique code provided by Licensor upon purchasing a Subscription which activates the full features of the Software.
|
||||
1.6. "Source Code" refers to the human-readable version of the Software's code, as opposed to the compiled machine-readable version.
|
||||
|
||||
2. GRANT OF LICENSE
|
||||
|
||||
|
@ -20,21 +22,23 @@ This Agreement is entered into by and between Stalwart Labs Ltd and you, or the
|
|||
2.2. The use of the Software is conditioned upon Licensee maintaining an active and valid paid subscription with Licensor. The paid subscription covers all versions of the Software and all updates and modifications.
|
||||
2.3. This license grants Licensee the right to use the Software for both personal and commercial purposes. However, Licensee is expressly prohibited from reselling, leasing, sublicensing, or otherwise redistributing the Software itself.
|
||||
2.4. This license is further governed by the terms and conditions set forth in any licensing agreements separately executed between Licensor and Licensee. In the event of any conflict between the terms of this Agreement and the terms of a signed licensing agreement, the terms of the signed licensing agreement shall control.
|
||||
2.5. You are not granted any other rights beyond what is expressly stated herein.
|
||||
|
||||
3. LICENSE KEYS
|
||||
|
||||
3.1. The Software shall not be used without a valid License Key issued by Licensor.
|
||||
3.1. Distribution or sharing of License Keys to third parties, not associated with Licensee, is strictly prohibited.
|
||||
3.2. License Keys are bound to the subscription period. Should your subscription expire, all License Keys will become invalid after 15 days from the subscription expiration date.
|
||||
3.3. Any instance of the Software using such an expired key will revert to the Community Edition functionality after the aforementioned 15-day period.
|
||||
3.2. Licensee is required to use valid License Keys issued by Licensor to run the Software, including any modified versions. Any attempts to bypass the License Key requirement is a violation of this Agreement.
|
||||
3.3. Distribution or sharing of License Keys to third parties, not associated with Licensee, is strictly prohibited.
|
||||
3.4. License Keys are bound to the subscription period. Should your subscription expire, all License Keys will become invalid after 15 days from the subscription expiration date.
|
||||
3.5. Any instance of the Software using such an expired key will revert to the Community Edition functionality after the aforementioned 15-day period.
|
||||
|
||||
4. SOURCE CODE USAGE
|
||||
|
||||
4.1. Licensee is permitted to view, copy, and modify the Software's source code, as made available by Licensor, solely for Licensee's internal business use and in compliance with this Agreement's terms.
|
||||
4.2. Any modifications to the source code do not grant Licensee any ownership rights to the original Software or any modifications. All rights, title, and interest to the Software and its source code remain exclusively with Licensor.
|
||||
4.3. Licensee is strictly prohibited from altering, removing, or in any way tampering with the license key validation system within the Software. Any such unauthorized modifications will be considered a material breach of this Agreement and may result in legal action.
|
||||
4.4. Licensee is required to use valid License Keys issued by Licensor to run the Software, including any modified versions. Any attempts to bypass the License Key requirement is a violation of this Agreement.
|
||||
4.5. Notwithstanding the availability of the Software's source code for review and limited modification, the Software and its source code are not open source and remain proprietary to Licensor. The provision of access to the source code does not confer any rights typically associated with open source software, including but not limited to the right to freely distribute, sublicense, or create derivative works for public distribution. All rights not expressly granted herein are reserved by Licensor.
|
||||
4.1. Licensee is permitted to view, copy, and modify the Software's Source Code, as made available by Licensor, solely for Licensee's internal business use and in compliance with this Agreement's terms.
|
||||
4.2. Any modifications to the Source Code do not grant Licensee any ownership rights to the original Software or any modifications. All rights, title, and interest to the Software and its Source Code remain exclusively with Licensor.
|
||||
4.3. Licensee is strictly prohibited from altering, removing, or in any way tampering with the License Key validation system within the Software. Any such unauthorized modifications will be considered a material breach of this Agreement and may result in legal action.
|
||||
4.3. Notwithstanding the availability of the Software's Source Code for review and limited modification, the Software and its Source Code are not open source and remain proprietary to Licensor. The provision of access to the Source Code does not confer any rights typically associated with open source software, including but not limited to the right to freely sublicense, or create derivative works for public distribution. All rights not expressly granted herein are reserved by Licensor.
|
||||
4.4. Notwithstanding the foregoing, you may copy the Source Code for development and testing purposes, without requiring a Subscription.
|
||||
|
||||
5. INTELLECTUAL PROPERTY RIGHTS
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ nlp = { path = "../nlp" }
|
|||
store = { path = "../store" }
|
||||
directory = { path = "../directory" }
|
||||
jmap_proto = { path = "../jmap-proto" }
|
||||
se_licensing = { path = "../se-licensing" }
|
||||
se_licensing = { path = "../se-licensing", optional = true }
|
||||
sieve-rs = { version = "0.5" }
|
||||
mail-parser = { version = "0.9", features = ["full_encoding", "ludicrous_mode"] }
|
||||
mail-auth = { version = "0.4" }
|
||||
|
@ -67,3 +67,4 @@ tracing-journald = "0.3"
|
|||
|
||||
[features]
|
||||
test_mode = []
|
||||
enterprise = ["se_licensing"]
|
||||
|
|
|
@ -4,20 +4,25 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use std::sync::Arc;
|
||||
|
||||
use arc_swap::ArcSwap;
|
||||
use directory::{Directories, Directory};
|
||||
use jmap_proto::types::collection::Collection;
|
||||
use se_licensing::license::LicenseValidator;
|
||||
use store::{BitmapKey, BlobBackend, BlobStore, FtsStore, LookupStore, Store, Stores};
|
||||
use store::{BlobBackend, BlobStore, FtsStore, LookupStore, Store, Stores};
|
||||
use utils::config::Config;
|
||||
|
||||
use crate::{
|
||||
expr::*, listener::tls::TlsManager, manager::config::ConfigManager, webhooks::Webhooks, Core,
|
||||
Enterprise, Network,
|
||||
Network,
|
||||
};
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
use crate::Enterprise;
|
||||
#[cfg(feature = "enterprise")]
|
||||
use jmap_proto::types::collection::Collection;
|
||||
#[cfg(feature = "enterprise")]
|
||||
use se_licensing::license::LicenseValidator;
|
||||
|
||||
use self::{
|
||||
imap::ImapConfig, jmap::settings::JmapConfig, scripts::Scripting, smtp::SmtpConfig,
|
||||
storage::Storage,
|
||||
|
@ -122,6 +127,7 @@ impl Core {
|
|||
// SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
let enterprise = match config.value("enterprise.license-key").map(|key| {
|
||||
LicenseValidator::new().try_parse(key).and_then(|key| {
|
||||
key.into_validated_key(config.value("lookup.default.hostname").unwrap_or_default())
|
||||
|
@ -129,7 +135,10 @@ impl Core {
|
|||
}) {
|
||||
Some(Ok(license)) => {
|
||||
match data
|
||||
.get_bitmap(BitmapKey::document_ids(u32::MAX, Collection::Principal))
|
||||
.get_bitmap(store::BitmapKey::document_ids(
|
||||
u32::MAX,
|
||||
Collection::Principal,
|
||||
))
|
||||
.await
|
||||
{
|
||||
Ok(Some(bitmap)) if bitmap.len() > license.accounts as u64 => {
|
||||
|
@ -152,7 +161,7 @@ impl Core {
|
|||
_ => Some(Enterprise {
|
||||
license,
|
||||
undelete_period: config
|
||||
.property_or_default::<Option<Duration>>(
|
||||
.property_or_default::<Option<std::time::Duration>>(
|
||||
"enterprise.undelete-period",
|
||||
"false",
|
||||
)
|
||||
|
@ -206,6 +215,7 @@ impl Core {
|
|||
blobs: stores.blob_stores,
|
||||
ftss: stores.fts_stores,
|
||||
},
|
||||
#[cfg(feature = "enterprise")]
|
||||
enterprise,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::{borrow::Cow, net::IpAddr, sync::Arc, time::Duration};
|
||||
use std::{borrow::Cow, net::IpAddr, sync::Arc};
|
||||
|
||||
use arc_swap::ArcSwap;
|
||||
use config::{
|
||||
|
@ -35,6 +35,7 @@ use opentelemetry_sdk::{
|
|||
Resource,
|
||||
};
|
||||
use opentelemetry_semantic_conventions::resource::{SERVICE_NAME, SERVICE_VERSION};
|
||||
#[cfg(feature = "enterprise")]
|
||||
use se_licensing::license::LicenseKey;
|
||||
use sieve::Sieve;
|
||||
use store::LookupStore;
|
||||
|
@ -71,6 +72,7 @@ pub struct Core {
|
|||
pub jmap: JmapConfig,
|
||||
pub imap: ImapConfig,
|
||||
pub web_hooks: Webhooks,
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub enterprise: Option<Enterprise>,
|
||||
}
|
||||
|
||||
|
@ -85,10 +87,11 @@ pub struct Network {
|
|||
// SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
#[derive(Clone)]
|
||||
pub struct Enterprise {
|
||||
pub license: LicenseKey,
|
||||
pub undelete_period: Option<Duration>,
|
||||
pub undelete_period: Option<std::time::Duration>,
|
||||
}
|
||||
|
||||
// SPDX-SnippetEnd
|
||||
|
|
|
@ -11,7 +11,7 @@ jmap_proto = { path = "../jmap-proto" }
|
|||
smtp = { path = "../smtp" }
|
||||
utils = { path = "../utils" }
|
||||
common = { path = "../common" }
|
||||
se_common = { path = "../se-common" }
|
||||
se_common = { path = "../se-common", optional = true }
|
||||
directory = { path = "../directory" }
|
||||
smtp-proto = { version = "0.1" }
|
||||
mail-parser = { version = "0.9", features = ["full_encoding", "serde_support", "ludicrous_mode"] }
|
||||
|
@ -61,3 +61,4 @@ quick-xml = "0.35"
|
|||
|
||||
[features]
|
||||
test_mode = []
|
||||
enterprise = ["se_common"]
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
* SPDX-License-Identifier: LicenseRef-SEL
|
||||
*
|
||||
* This file is subject to the Stalwart Enterprise License Agreement (SEL) and
|
||||
* is not open source software. It must not be modified or distributed without
|
||||
* explicit permission from Stalwart Labs Ltd.
|
||||
* Unauthorized use, modification, or distribution is strictly prohibited.
|
||||
* is NOT open source software.
|
||||
*
|
||||
*/
|
||||
|
||||
use std::str::FromStr;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
pub mod dkim;
|
||||
pub mod domain;
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod enterprise;
|
||||
pub mod log;
|
||||
pub mod principal;
|
||||
|
@ -24,6 +25,8 @@ use serde::Serialize;
|
|||
|
||||
use super::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse};
|
||||
use crate::{auth::AccessToken, JMAP};
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
use se_common::EnterpriseCore;
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -95,6 +98,7 @@ impl JMAP {
|
|||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
"pro" if is_superuser => {
|
||||
// WARNING: TAMPERING WITH THIS FUNCTION IS STRICTLY PROHIBITED
|
||||
// Any attempt to modify, bypass, or disable this license validation mechanism
|
||||
|
|
|
@ -23,6 +23,8 @@ use crate::{
|
|||
auth::{oauth::OAuthStatus, AccessToken},
|
||||
JMAP,
|
||||
};
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
use se_common::EnterpriseCore;
|
||||
|
||||
use super::{
|
||||
|
@ -90,11 +92,16 @@ impl JMAP {
|
|||
return err.into_http_response();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "enterprise"))]
|
||||
let is_enterprise = false;
|
||||
#[cfg(feature = "enterprise")]
|
||||
let is_enterprise = self.core.is_enterprise_edition();
|
||||
|
||||
json!({
|
||||
"data": {
|
||||
"code": client_code,
|
||||
"is_admin": access_token.is_super_user(),
|
||||
"is_enterprise": self.core.is_enterprise_edition(),
|
||||
"is_enterprise": is_enterprise,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ use jmap_proto::{
|
|||
type_state::DataType,
|
||||
},
|
||||
};
|
||||
#[cfg(feature = "enterprise")]
|
||||
use se_common::undelete::Undelete;
|
||||
use store::{
|
||||
ahash::AHashMap,
|
||||
|
@ -516,6 +517,7 @@ impl JMAP {
|
|||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
// Hold blob for undeletion
|
||||
#[cfg(feature = "enterprise")]
|
||||
self.core.hold_undelete(
|
||||
&mut batch,
|
||||
Collection::Email.into(),
|
||||
|
|
|
@ -49,6 +49,7 @@ enum ActionClass {
|
|||
Account,
|
||||
Store(usize),
|
||||
Acme(String),
|
||||
#[cfg(feature = "enterprise")]
|
||||
ReloadLicense,
|
||||
}
|
||||
|
||||
|
@ -113,6 +114,7 @@ pub fn spawn_housekeeper(core: JmapInstance, mut rx: mpsc::Receiver<Event>) {
|
|||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
|
||||
// Enterprise Edition license management
|
||||
#[cfg(feature = "enterprise")]
|
||||
if let Some(enterprise) = &core_.enterprise {
|
||||
queue.schedule(
|
||||
Instant::now() + enterprise.license.expires_in(),
|
||||
|
@ -347,6 +349,7 @@ pub fn spawn_housekeeper(core: JmapInstance, mut rx: mpsc::Receiver<Event>) {
|
|||
// SPDX-SnippetBegin
|
||||
// SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
|
||||
// SPDX-License-Identifier: LicenseRef-SEL
|
||||
#[cfg(feature = "enterprise")]
|
||||
ActionClass::ReloadLicense => {
|
||||
match core_.reload().await {
|
||||
Ok(result) => {
|
||||
|
|
|
@ -26,7 +26,7 @@ managesieve = { path = "../managesieve" }
|
|||
common = { path = "../common" }
|
||||
directory = { path = "../directory" }
|
||||
utils = { path = "../utils" }
|
||||
se_common = { path = "../se-common" }
|
||||
se_common = { path = "../se-common", optional = true }
|
||||
tokio = { version = "1.23", features = ["full"] }
|
||||
tracing = "0.1"
|
||||
|
||||
|
@ -34,8 +34,8 @@ tracing = "0.1"
|
|||
jemallocator = "0.5.0"
|
||||
|
||||
[features]
|
||||
default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis"]
|
||||
#default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "foundationdb"]
|
||||
default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "enterprise"]
|
||||
#default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "foundationdb", "enterprise"]
|
||||
sqlite = ["store/sqlite"]
|
||||
foundationdb = ["store/foundation"]
|
||||
postgres = ["store/postgres"]
|
||||
|
@ -44,3 +44,4 @@ rocks = ["store/rocks"]
|
|||
elastic = ["store/elastic"]
|
||||
s3 = ["store/s3"]
|
||||
redis = ["store/redis"]
|
||||
enterprise = ["se_common", "se_common/enterprise", "jmap/enterprise", "common/enterprise"]
|
||||
|
|
|
@ -14,6 +14,7 @@ use imap::core::{ImapSessionManager, IMAP};
|
|||
use jmap::{api::JmapSessionManager, services::gossip::spawn::GossiperBuilder, JMAP};
|
||||
use managesieve::core::ManageSieveSessionManager;
|
||||
use pop3::Pop3SessionManager;
|
||||
#[cfg(feature = "enterprise")]
|
||||
use se_common::EnterpriseCore;
|
||||
use smtp::core::{SmtpSessionManager, SMTP};
|
||||
use tokio::sync::mpsc;
|
||||
|
@ -56,6 +57,7 @@ async fn main() -> std::io::Result<()> {
|
|||
config.log_warnings(init.guards.is_none());
|
||||
|
||||
// Log licensing information
|
||||
#[cfg(feature = "enterprise")]
|
||||
core.load().as_ref().log_license_details();
|
||||
|
||||
// Spawn servers
|
||||
|
|
|
@ -14,3 +14,4 @@ serde = { version = "1.0", features = ["derive"]}
|
|||
|
||||
[features]
|
||||
test_mode = []
|
||||
enterprise = ["common/enterprise"]
|
||||
|
|
|
@ -4,21 +4,22 @@
|
|||
* SPDX-License-Identifier: LicenseRef-SEL
|
||||
*
|
||||
* This file is subject to the Stalwart Enterprise License Agreement (SEL) and
|
||||
* is not open source software. It must not be modified or distributed without
|
||||
* explicit permission from Stalwart Labs Ltd.
|
||||
* Unauthorized use, modification, or distribution is strictly prohibited.
|
||||
* is NOT open source software.
|
||||
*
|
||||
*/
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub mod undelete;
|
||||
use common::Core;
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
pub trait EnterpriseCore {
|
||||
fn is_enterprise_edition(&self) -> bool;
|
||||
fn log_license_details(&self);
|
||||
fn licensed_accounts(&self) -> u32;
|
||||
}
|
||||
|
||||
impl EnterpriseCore for Core {
|
||||
#[cfg(feature = "enterprise")]
|
||||
impl EnterpriseCore for common::Core {
|
||||
// WARNING: TAMPERING WITH THIS FUNCTION IS STRICTLY PROHIBITED
|
||||
// Any attempt to modify, bypass, or disable this license validation mechanism
|
||||
// constitutes a severe violation of the Stalwart Enterprise License Agreement.
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
* SPDX-License-Identifier: LicenseRef-SEL
|
||||
*
|
||||
* This file is subject to the Stalwart Enterprise License Agreement (SEL) and
|
||||
* is not open source software. It must not be modified or distributed without
|
||||
* explicit permission from Stalwart Labs Ltd.
|
||||
* Unauthorized use, modification, or distribution is strictly prohibited.
|
||||
* is NOT open source software.
|
||||
*
|
||||
*/
|
||||
|
||||
use std::future::Future;
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
* SPDX-License-Identifier: LicenseRef-SEL
|
||||
*
|
||||
* This file is subject to the Stalwart Enterprise License Agreement (SEL) and
|
||||
* is not open source software. It must not be modified or distributed without
|
||||
* explicit permission from Stalwart Labs Ltd.
|
||||
* Unauthorized use, modification, or distribution is strictly prohibited.
|
||||
* is NOT open source software.
|
||||
*
|
||||
*/
|
||||
|
||||
pub mod license;
|
||||
|
|
|
@ -4,9 +4,8 @@
|
|||
* SPDX-License-Identifier: LicenseRef-SEL
|
||||
*
|
||||
* This file is subject to the Stalwart Enterprise License Agreement (SEL) and
|
||||
* is not open source software. It must not be modified or distributed without
|
||||
* explicit permission from Stalwart Labs Ltd.
|
||||
* Unauthorized use, modification, or distribution is strictly prohibited.
|
||||
* is NOT open source software.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
|
@ -38,7 +38,7 @@ impl Status<(), Error> {
|
|||
mail_send::Error::Io(_)
|
||||
| mail_send::Error::Tls(_)
|
||||
| mail_send::Error::Base64(_)
|
||||
| mail_send::Error::UnparsableReply
|
||||
| mail_send::Error::UnparseableReply
|
||||
| mail_send::Error::AuthenticationFailed(_)
|
||||
| mail_send::Error::MissingCredentials
|
||||
| mail_send::Error::MissingMailFrom
|
||||
|
|
Loading…
Reference in a new issue