mirror of
https://github.com/stalwartlabs/mail-server.git
synced 2024-09-20 07:16:18 +08:00
parent
4164598ac2
commit
82f7311a4d
|
@ -119,7 +119,7 @@ All documentation is available at [stalw.art/docs/get-started](https://stalw.art
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
If you are having problems running Stalwart Mail Server, you found a bug or just have a question,
|
If you are having problems running Stalwart Mail Server, you found a bug or just have a question,
|
||||||
do not hesitate to reach us on [Github Discussions](https://github.com/stalwartlabs/mail-server/discussions),
|
do not hesitate to reach us on [GitHub Discussions](https://github.com/stalwartlabs/mail-server/discussions),
|
||||||
[Reddit](https://www.reddit.com/r/stalwartlabs), [Discord](https://discord.gg/aVQr3jF8jd) or [Matrix](https://matrix.to/#/#stalwart:matrix.org).
|
[Reddit](https://www.reddit.com/r/stalwartlabs), [Discord](https://discord.gg/aVQr3jF8jd) or [Matrix](https://matrix.to/#/#stalwart:matrix.org).
|
||||||
Additionally you may purchase a subscription to obtain priority support from Stalwart Labs Ltd.
|
Additionally you may purchase a subscription to obtain priority support from Stalwart Labs Ltd.
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ use utils::{config::Config, map::vec_map::VecMap};
|
||||||
use super::settings::JmapConfig;
|
use super::settings::JmapConfig;
|
||||||
|
|
||||||
impl JmapConfig {
|
impl JmapConfig {
|
||||||
pub fn add_capabilites(&mut self, config: &mut Config) {
|
pub fn add_capabilities(&mut self, config: &mut Config) {
|
||||||
// Add core capabilities
|
// Add core capabilities
|
||||||
self.capabilities.session.append(
|
self.capabilities.session.append(
|
||||||
Capability::Core,
|
Capability::Core,
|
||||||
|
|
|
@ -436,7 +436,7 @@ impl JmapConfig {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add capabilities
|
// Add capabilities
|
||||||
jmap.add_capabilites(config);
|
jmap.add_capabilities(config);
|
||||||
jmap
|
jmap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ pub struct Rcpt {
|
||||||
// Limits
|
// Limits
|
||||||
pub max_recipients: IfBlock,
|
pub max_recipients: IfBlock,
|
||||||
|
|
||||||
// Catch-all and sub-adressing
|
// Catch-all and sub-addressing
|
||||||
pub catch_all: AddressMapping,
|
pub catch_all: AddressMapping,
|
||||||
pub subaddressing: AddressMapping,
|
pub subaddressing: AddressMapping,
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ impl Capability {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all_capabilities(is_authenticated: bool, is_tls: bool) -> Vec<Capability> {
|
pub fn all_capabilities(is_authenticated: bool, is_tls: bool) -> Vec<Capability> {
|
||||||
let mut capabilties = vec![
|
let mut capabilities = vec![
|
||||||
Capability::IMAP4rev2,
|
Capability::IMAP4rev2,
|
||||||
Capability::IMAP4rev1,
|
Capability::IMAP4rev1,
|
||||||
Capability::Enable,
|
Capability::Enable,
|
||||||
|
@ -107,7 +107,7 @@ impl Capability {
|
||||||
];
|
];
|
||||||
|
|
||||||
if is_authenticated {
|
if is_authenticated {
|
||||||
capabilties.extend([
|
capabilities.extend([
|
||||||
Capability::Idle,
|
Capability::Idle,
|
||||||
Capability::Namespace,
|
Capability::Namespace,
|
||||||
Capability::Children,
|
Capability::Children,
|
||||||
|
@ -135,16 +135,16 @@ impl Capability {
|
||||||
Capability::Preview,
|
Capability::Preview,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
capabilties.extend([
|
capabilities.extend([
|
||||||
Capability::Auth(Mechanism::OAuthBearer),
|
Capability::Auth(Mechanism::OAuthBearer),
|
||||||
Capability::Auth(Mechanism::Plain),
|
Capability::Auth(Mechanism::Plain),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if !is_tls {
|
if !is_tls {
|
||||||
capabilties.push(Capability::StartTLS);
|
capabilities.push(Capability::StartTLS);
|
||||||
}
|
}
|
||||||
|
|
||||||
capabilties
|
capabilities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -767,7 +767,7 @@ impl DeliveryAttempt {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Say EHLO
|
// Say EHLO
|
||||||
let capabilties = match say_helo(&mut smtp_client, ¶ms).await {
|
let capabilities = match say_helo(&mut smtp_client, ¶ms).await {
|
||||||
Ok(capabilities) => capabilities,
|
Ok(capabilities) => capabilities,
|
||||||
Err(status) => {
|
Err(status) => {
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
|
@ -794,7 +794,7 @@ impl DeliveryAttempt {
|
||||||
smtp_client,
|
smtp_client,
|
||||||
tls_connector,
|
tls_connector,
|
||||||
envelope.mx,
|
envelope.mx,
|
||||||
&capabilties,
|
&capabilities,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,7 +38,7 @@ impl Status<(), Error> {
|
||||||
mail_send::Error::Io(_)
|
mail_send::Error::Io(_)
|
||||||
| mail_send::Error::Tls(_)
|
| mail_send::Error::Tls(_)
|
||||||
| mail_send::Error::Base64(_)
|
| mail_send::Error::Base64(_)
|
||||||
| mail_send::Error::UnparseableReply
|
| mail_send::Error::UnparsableReply
|
||||||
| mail_send::Error::AuthenticationFailed(_)
|
| mail_send::Error::AuthenticationFailed(_)
|
||||||
| mail_send::Error::MissingCredentials
|
| mail_send::Error::MissingCredentials
|
||||||
| mail_send::Error::MissingMailFrom
|
| mail_send::Error::MissingMailFrom
|
||||||
|
|
|
@ -258,7 +258,7 @@ impl Message {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Handle LMTP responses
|
// Handle LMTP responses
|
||||||
match read_lmtp_data_respone(
|
match read_lmtp_data_response(
|
||||||
&mut smtp_client,
|
&mut smtp_client,
|
||||||
params.hostname,
|
params.hostname,
|
||||||
accepted_rcpts.len(),
|
accepted_rcpts.len(),
|
||||||
|
@ -481,7 +481,7 @@ pub async fn read_smtp_data_response<T: AsyncRead + AsyncWrite + Unpin>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_lmtp_data_respone<T: AsyncRead + AsyncWrite + Unpin>(
|
pub async fn read_lmtp_data_response<T: AsyncRead + AsyncWrite + Unpin>(
|
||||||
smtp_client: &mut SmtpClient<T>,
|
smtp_client: &mut SmtpClient<T>,
|
||||||
hostname: &str,
|
hostname: &str,
|
||||||
num_responses: usize,
|
num_responses: usize,
|
||||||
|
|
|
@ -240,7 +240,7 @@ impl<T: SessionStream> Session<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send agregate reports
|
// Send aggregate reports
|
||||||
let interval = self
|
let interval = self
|
||||||
.core
|
.core
|
||||||
.core
|
.core
|
||||||
|
|
|
@ -196,7 +196,7 @@ impl SMTP {
|
||||||
|
|
||||||
pub async fn schedule_report(&self, report: impl Into<Event>) {
|
pub async fn schedule_report(&self, report: impl Into<Event>) {
|
||||||
if self.inner.report_tx.send(report.into()).await.is_err() {
|
if self.inner.report_tx.send(report.into()).await.is_err() {
|
||||||
tracing::warn!(contex = "report", "Channel send failed.");
|
tracing::warn!(context = "report", "Channel send failed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -611,7 +611,7 @@ if eval "!is_empty(rto_raw)" {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
let "t.REPLYTO_UNPARSEABLE" "1";
|
let "t.REPLYTO_UNPARSABLE" "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
if eval "is_ascii(header.reply-to) && contains(rto_raw, '=?') && contains(rto_raw, '?=')" {
|
if eval "is_ascii(header.reply-to) && contains(rto_raw, '=?') && contains(rto_raw, '?=')" {
|
||||||
|
@ -2793,7 +2793,7 @@ spam-scores = {"ABUSE_SURBL" = "5.0",
|
||||||
"REPLYTO_EQ_TO_ADDR" = "5.0",
|
"REPLYTO_EQ_TO_ADDR" = "5.0",
|
||||||
"REPLYTO_EXCESS_BASE64" = "1.5",
|
"REPLYTO_EXCESS_BASE64" = "1.5",
|
||||||
"REPLYTO_EXCESS_QP" = "1.2",
|
"REPLYTO_EXCESS_QP" = "1.2",
|
||||||
"REPLYTO_UNPARSEABLE" = "1.0",
|
"REPLYTO_UNPARSABLE" = "1.0",
|
||||||
"RWL_MAILSPIKE_EXCELLENT" = "-0.4",
|
"RWL_MAILSPIKE_EXCELLENT" = "-0.4",
|
||||||
"RWL_MAILSPIKE_GOOD" = "-0.1",
|
"RWL_MAILSPIKE_GOOD" = "-0.1",
|
||||||
"RWL_MAILSPIKE_NEUTRAL" = "0.0",
|
"RWL_MAILSPIKE_NEUTRAL" = "0.0",
|
||||||
|
|
|
@ -270,7 +270,7 @@ spam-scores = {"ABUSE_SURBL" = "5.0",
|
||||||
"REPLYTO_EQ_TO_ADDR" = "5.0",
|
"REPLYTO_EQ_TO_ADDR" = "5.0",
|
||||||
"REPLYTO_EXCESS_BASE64" = "1.5",
|
"REPLYTO_EXCESS_BASE64" = "1.5",
|
||||||
"REPLYTO_EXCESS_QP" = "1.2",
|
"REPLYTO_EXCESS_QP" = "1.2",
|
||||||
"REPLYTO_UNPARSEABLE" = "1.0",
|
"REPLYTO_UNPARSABLE" = "1.0",
|
||||||
"RWL_MAILSPIKE_EXCELLENT" = "-0.4",
|
"RWL_MAILSPIKE_EXCELLENT" = "-0.4",
|
||||||
"RWL_MAILSPIKE_GOOD" = "-0.1",
|
"RWL_MAILSPIKE_GOOD" = "-0.1",
|
||||||
"RWL_MAILSPIKE_NEUTRAL" = "0.0",
|
"RWL_MAILSPIKE_NEUTRAL" = "0.0",
|
||||||
|
|
|
@ -59,7 +59,7 @@ if eval "!is_empty(rto_raw)" {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
let "t.REPLYTO_UNPARSEABLE" "1";
|
let "t.REPLYTO_UNPARSABLE" "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
if eval "is_ascii(header.reply-to) && contains(rto_raw, '=?') && contains(rto_raw, '?=')" {
|
if eval "is_ascii(header.reply-to) && contains(rto_raw, '=?') && contains(rto_raw, '?=')" {
|
||||||
|
|
|
@ -15,7 +15,7 @@ if specialuse_exists "dingleberry" {
|
||||||
}
|
}
|
||||||
|
|
||||||
if specialuse_exists "archive" {
|
if specialuse_exists "archive" {
|
||||||
error "A non-existant special-use exists.";
|
error "A non-existent special-use exists.";
|
||||||
}
|
}
|
||||||
|
|
||||||
# MailboxId tests
|
# MailboxId tests
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
expect REPLYTO_UNPARSEABLE
|
expect REPLYTO_UNPARSABLE
|
||||||
|
|
||||||
Reply-to: hello
|
Reply-to: hello
|
||||||
|
|
||||||
|
|
|
@ -180,7 +180,7 @@ pub async fn test(params: &mut JMAPTest) {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// John shoud have ReadItems access to Inbox
|
// John should have ReadItems access to Inbox
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
john_client
|
john_client
|
||||||
.set_default_account_id(&jane_id.to_string())
|
.set_default_account_id(&jane_id.to_string())
|
||||||
|
|
|
@ -498,7 +498,7 @@ impl SmtpConnection {
|
||||||
|
|
||||||
pub trait AssertResult: Sized {
|
pub trait AssertResult: Sized {
|
||||||
fn assert_contains(self, text: &str) -> Self;
|
fn assert_contains(self, text: &str) -> Self;
|
||||||
fn assert_count(self, text: &str, occurences: usize) -> Self;
|
fn assert_count(self, text: &str, occurrences: usize) -> Self;
|
||||||
fn assert_equals(self, text: &str) -> Self;
|
fn assert_equals(self, text: &str) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,12 +512,12 @@ impl AssertResult for Vec<String> {
|
||||||
panic!("Expected response to contain {:?}, got {:?}", text, self);
|
panic!("Expected response to contain {:?}, got {:?}", text, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_count(self, text: &str, occurences: usize) -> Self {
|
fn assert_count(self, text: &str, occurrences: usize) -> Self {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
self.iter().filter(|l| l.contains(text)).count(),
|
self.iter().filter(|l| l.contains(text)).count(),
|
||||||
occurences,
|
occurrences,
|
||||||
"Expected {} occurrences of {:?}, found {}.",
|
"Expected {} occurrences of {:?}, found {}.",
|
||||||
occurences,
|
occurrences,
|
||||||
text,
|
text,
|
||||||
self.iter().filter(|l| l.contains(text)).count()
|
self.iter().filter(|l| l.contains(text)).count()
|
||||||
);
|
);
|
||||||
|
|
|
@ -290,7 +290,7 @@ async fn dmarc() {
|
||||||
.await;
|
.await;
|
||||||
qr.assert_no_events();
|
qr.assert_no_events();
|
||||||
|
|
||||||
// Messagess passing DMARC should be accepted
|
// Messages passing DMARC should be accepted
|
||||||
session
|
session
|
||||||
.send_message(
|
.send_message(
|
||||||
"bill@example.com",
|
"bill@example.com",
|
||||||
|
|
|
@ -303,7 +303,7 @@ async fn mail() {
|
||||||
assert_eq!(session.data.future_release, 10);
|
assert_eq!(session.data.future_release, 10);
|
||||||
session.rset().await;
|
session.rset().await;
|
||||||
|
|
||||||
// Test FUTURERELEASE extension with invalud HOLDUNTIL value
|
// Test FUTURERELEASE extension with invalid HOLDUNTIL value
|
||||||
session
|
session
|
||||||
.ingest(format!("MAIL FROM:<jane@foobar.org> HOLDUNTIL={}\r\n", now + 99999).as_bytes())
|
.ingest(format!("MAIL FROM:<jane@foobar.org> HOLDUNTIL={}\r\n", now + 99999).as_bytes())
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -220,7 +220,7 @@ async fn lookup_sql() {
|
||||||
// External domain
|
// External domain
|
||||||
session.rcpt_to("user@otherdomain.org", "550 5.1.2").await;
|
session.rcpt_to("user@otherdomain.org", "550 5.1.2").await;
|
||||||
|
|
||||||
// Non-existant user
|
// Non-existent user
|
||||||
session.rcpt_to("jack@foobar.org", "550 5.1.2").await;
|
session.rcpt_to("jack@foobar.org", "550 5.1.2").await;
|
||||||
|
|
||||||
// Valid users
|
// Valid users
|
||||||
|
|
Loading…
Reference in a new issue