Rebrand to INBUXA: product name, protocol greetings, sign-in page, calendar templates, logos, README

One branding module (types::brand!) supplies the name to every protocol
greeting, the HTTP realm, the startup banner, Received headers, the
user agent, the IMAP ID response and calendar PRODIDs. The sign-in and
calendar pages take ihasmail's palette and font and the INBUXA logo, and
calendar emails embed the INBUXA lockup. Default calendar and address book
names follow. Protocol identifiers (urn:stalwart:jmap, vnd.stalwart Sieve
extensions) and upstream copyright notices are unchanged.
This commit is contained in:
2026-09-18 10:52:34 -07:00
parent 6e73d284d8
commit 89665decfa
70 changed files with 616 additions and 442 deletions
@@ -90,7 +90,7 @@ impl Scripting {
.with_protected_headers(untrusted.protected_headers)
.with_vacation_default_subject(untrusted.default_subject)
.with_vacation_subject_prefix(untrusted.default_subject_prefix)
.with_env_variable("name", "Stalwart Server")
.with_env_variable("name", types::brand_server!())
.with_env_variable("version", VERSION_PUBLIC)
.with_env_variable("location", "MS")
.with_env_variable("phase", "during");
+1 -1
View File
@@ -190,7 +190,7 @@ impl Network {
}),
info: Info {
provider: Provider {
name: "Stalwart".into(),
name: types::brand!().into(),
..Default::default()
},
..Default::default()
+10 -59
View File
@@ -78,9 +78,9 @@ pub use psl;
pub static VERSION_PRIVATE: &str = env!("CARGO_PKG_VERSION");
pub static VERSION_PUBLIC: &str = "1.0.0";
pub static USER_AGENT: &str = "Stalwart/1.0.0";
pub static DAEMON_NAME: &str = concat!("Stalwart v", env!("CARGO_PKG_VERSION"),);
pub static PROD_ID: &str = "-//Stalwart Labs LLC//Stalwart Server//EN";
pub static USER_AGENT: &str = concat!(types::brand!(), "/1.0.0");
pub static DAEMON_NAME: &str = concat!(types::brand!(), " v", env!("CARGO_PKG_VERSION"),);
pub static PROD_ID: &str = types::brand_prodid!();
/*
@@ -415,59 +415,10 @@ pub struct ThrottleKeyHasher {
#[derive(Clone, Default)]
pub struct ThrottleKeyHasherBuilder {}
pub const DEFAULT_LOGO_BASE64: &str = "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\r\n\
AElFTkSuQmCC";
/// The logo embedded in calendar emails when no custom logo is set: INBUXA's
/// compact lockup at 380x80, twice its 180-pixel display width. Base64 with
/// CRLF line breaks, ready for a base64 MIME part.
pub const DEFAULT_LOGO_BASE64: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../resources/branding/email-logo.png.b64"
));
+2 -1
View File
@@ -38,7 +38,8 @@ pub struct IpcReceivers {
}
const HELP: &str = concat!(
"Stalwart Server v",
types::brand_server!(),
" v",
env!("CARGO_PKG_VERSION"),
r#"
+2 -1
View File
@@ -12,7 +12,8 @@ use store::write::{AnyClass, AnyKey, BatchBuilder, ValueClass};
use store::{Deserialize, IterateParams, SUBSPACE_INDEXES, SUBSPACE_REGISTRY_IDX, Store};
const HELP: &str = concat!(
"Stalwart Server v",
types::brand_server!(),
" v",
env!("CARGO_PKG_VERSION"),
r#" Data Store CLI
+2 -2
View File
@@ -52,9 +52,9 @@ impl Core {
if !conflicts.is_empty() {
eprintln!(
"Cannot import: the target database already contains data in the key ranges being \
imported. This usually means Stalwart was started before the import ran, which \
imported. This usually means the server was started before the import ran, which \
can create duplicate entries. Import into a fresh, empty database and do not \
start Stalwart before importing. Conflicting dumps:"
start the server before importing. Conflicting dumps:"
);
for path in conflicts {
eprintln!(" {}", path.display());
+1 -1
View File
@@ -38,7 +38,7 @@ impl OpenIdDirectory {
pub async fn new(config: OidcConfig) -> Result<Self, OidcError> {
let http = utils::http::http_client_builder(false)
.user_agent("Stalwart/1.0")
.user_agent("INBUXA/1.0") // types::brand!(); this crate does not depend on types
.timeout(Duration::from_secs(30))
.build()
.map_err(|e| OidcError::Network(format!("HTTP client build failed: {e}")))?;
+1 -1
View File
@@ -110,7 +110,7 @@ impl EncryptMessage for Message<'_> {
outer_message.extend_from_slice(
concat!(
"\"\r\n\r\n",
"OpenPGP/MIME message (Automatically encrypted by Stalwart)\r\n\r\n",
concat!("OpenPGP/MIME message (Automatically encrypted by ", types::brand!(), ")\r\n\r\n"),
"--"
)
.as_bytes(),
+1 -1
View File
@@ -779,7 +779,7 @@ impl SieveScriptIngest for Server {
fn write_received_header(buf: &mut Vec<u8>, hostname: &str, id: u64) {
buf.extend_from_slice(b"Received: from localhost (localhost [127.0.0.1])\r\n\tby ");
buf.extend_from_slice(hostname.as_bytes());
buf.extend_from_slice(b" (Stalwart SMTP) with LMTP id ");
buf.extend_from_slice(concat!(" (", types::brand!(), " SMTP) with LMTP id ").as_bytes());
buf.extend_from_slice(format!("{id:X}").as_bytes());
buf.extend_from_slice(b";\r\n\t");
buf.extend_from_slice(Date::now().to_rfc822().as_bytes());
+2 -2
View File
@@ -267,10 +267,10 @@ pub fn accept_language(req: &HttpRequest) -> &str {
}
const BEARER_CHALLENGE: &str = concat!(
"Bearer realm=\"Stalwart Server\", ",
concat!("Bearer realm=\"", types::brand_server!(), "\", "),
"resource_metadata=\"/.well-known/oauth-protected-resource\""
);
const BASIC_CHALLENGE: &str = "Basic realm=\"Stalwart Server\"";
const BASIC_CHALLENGE: &str = concat!("Basic realm=\"", types::brand_server!(), "\"");
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AuthChallenge {
+1 -1
View File
@@ -13,7 +13,7 @@ use imap_proto::{ResponseCode, StatusResponse, protocol::capability::Capability}
pub mod core;
pub mod op;
static SERVER_GREETING: &str = "Stalwart IMAP4rev2 at your service.";
static SERVER_GREETING: &str = concat!(types::brand!(), " IMAP4rev2 at your service.");
pub(crate) static GREETING_WITH_TLS: LazyLock<Vec<u8>> =
LazyLock::new(|| build_greeting(true, true));
+5 -2
View File
@@ -68,8 +68,11 @@ impl<T: SessionStream> Session<T> {
.with_tag(request.tag)
.serialize(
concat!(
"* ID (\"name\" \"Stalwart\" \"version\" \"1.0.0\" \"vendor\" \"Stalwart Labs LLC\" ",
"\"support-url\" \"https://stalw.art\")\r\n"
"* ID (\"name\" \"",
types::brand!(),
"\" \"version\" \"1.0.0\" \"vendor\" \"",
types::brand!(),
"\")\r\n"
)
.as_bytes()
.to_vec(),
+1 -1
View File
@@ -15,7 +15,7 @@ impl<T: SessionStream> Session<T> {
let op_start = Instant::now();
let mut response =
StatusResponse::bye("Stalwart IMAP4rev2 bids you farewell.".to_string()).into_bytes();
StatusResponse::bye(concat!(types::brand!(), " IMAP4rev2 bids you farewell.").to_string()).into_bytes();
trc::event!(
Imap(trc::ImapEvent::Logout),
+1 -1
View File
@@ -407,7 +407,7 @@ impl Session {
impl Default for SieveSessionCapabilities {
fn default() -> Self {
Self {
implementation: "Stalwart v1.0.0",
implementation: concat!(types::brand!(), " v1.0.0"),
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "stalwart"
description = "Stalwart Mail and Collaboration Server"
description = "INBUXA Mail and Collaboration Server, a fork of Stalwart"
authors = [ "Stalwart Labs LLC <[email protected]>"]
repository = "https://github.com/stalwartlabs/stalwart"
homepage = "https://stalw.art"
+1 -1
View File
@@ -9,7 +9,7 @@
pub mod core;
pub mod op;
static SERVER_GREETING: &str = "Stalwart ManageSieve at your service.";
static SERVER_GREETING: &str = concat!(types::brand!(), " ManageSieve at your service.");
#[cfg(test)]
mod tests {
+1 -1
View File
@@ -14,7 +14,7 @@ impl<T: SessionStream> Session<T> {
let op_start = Instant::now();
let mut response = Vec::with_capacity(128);
response.extend_from_slice(b"\"IMPLEMENTATION\" \"Stalwart ManageSieve\"\r\n");
response.extend_from_slice(concat!("\"IMPLEMENTATION\" \"", types::brand!(), " ManageSieve\"\r\n").as_bytes());
response.extend_from_slice(b"\"VERSION\" \"1.0\"\r\n");
if !self.stream.is_tls() {
response.extend_from_slice(b"\"STARTTLS\"\r\n");
+1 -1
View File
@@ -16,6 +16,6 @@ impl<T: AsyncRead + AsyncWrite> Session<T> {
Elapsed = trc::Value::Duration(0)
);
Ok(StatusResponse::ok("Stalwart ManageSieve bids you farewell.").into_bytes())
Ok(StatusResponse::ok(concat!(types::brand!(), " ManageSieve bids you farewell.")).into_bytes())
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ pub mod op;
pub mod protocol;
pub mod session;
static SERVER_GREETING: &str = "+OK Stalwart POP3 at your service.\r\n";
static SERVER_GREETING: &str = concat!("+OK ", types::brand!(), " POP3 at your service.\r\n");
#[derive(Clone)]
pub struct Pop3SessionManager {
+4 -3
View File
@@ -107,7 +107,8 @@ impl<T: SessionStream> Session<T> {
}
if not_deleted.is_empty() {
self.write_ok(format!(
"Stalwart POP3 bids you farewell ({num_deleted} messages deleted)."
concat!(types::brand!(), " POP3 bids you farewell ({} messages deleted)."),
num_deleted
))
.await?;
} else {
@@ -118,11 +119,11 @@ impl<T: SessionStream> Session<T> {
.await?;
}
} else {
self.write_ok("Stalwart POP3 bids you farewell (no messages deleted).")
self.write_ok(concat!(types::brand!(), " POP3 bids you farewell (no messages deleted)."))
.await?;
}
} else {
self.write_ok("Stalwart POP3 bids you farewell.").await?;
self.write_ok(concat!(types::brand!(), " POP3 bids you farewell.")).await?;
}
trc::event!(
+2 -2
View File
@@ -114,7 +114,7 @@ impl<'x, T: Display> Response<'x, T> {
"EXPIRE NEVER",
"UIDL",
"UTF8",
"IMPLEMENTATION Stalwart Server",
concat!("IMPLEMENTATION ", types::brand_server!()),
] {
buf.extend_from_slice(capa.as_bytes());
buf.extend_from_slice(b"\r\n");
@@ -200,7 +200,7 @@ mod tests {
"EXPIRE NEVER\r\n",
"UIDL\r\n",
"UTF8\r\n",
"IMPLEMENTATION Stalwart Server\r\n.\r\n"
concat!("IMPLEMENTATION ", types::brand_server!(), "\r\n.\r\n")
),
),
(
+5 -5
View File
@@ -730,7 +730,7 @@ impl Pickle for AddressBook {
impl Default for AddressBook {
fn default() -> Self {
Self {
default_display_name: Some("Stalwart Address Book".to_string()),
default_display_name: Some("INBUXA Address Book".to_string()),
default_href_name: Some("default".to_string()),
max_v_card_size: 524288u64,
max_address_books: Some(250u64),
@@ -4595,7 +4595,7 @@ impl Pickle for Calendar {
impl Default for Calendar {
fn default() -> Self {
Self {
default_display_name: Some("Stalwart Calendar".to_string()),
default_display_name: Some("INBUXA Calendar".to_string()),
default_href_name: Some("default".to_string()),
max_attendees: 20u64,
max_recurrence_expansions: 3000u64,
@@ -4732,7 +4732,7 @@ impl Default for CalendarAlarm {
allow_external_rcpts: false,
enable: true,
from_email: Default::default(),
from_name: "Stalwart Calendar".to_string(),
from_name: "INBUXA Calendar".to_string(),
min_trigger_interval: Duration::from_millis(3600000),
template: Default::default(),
}
@@ -28308,7 +28308,7 @@ impl MtaStageConnect {
ExpressionContext {
expr: &self.smtp_greeting,
default: Some(Expression {
else_: "system('hostname') + ' Stalwart ESMTP at your service'".to_string(),
else_: "system('hostname') + ' INBUXA ESMTP at your service'".to_string(),
..Default::default()
}),
property: Property::SmtpGreeting,
@@ -28372,7 +28372,7 @@ impl Default for MtaStageConnect {
fn default() -> Self {
Self {
smtp_greeting: Expression {
else_: "system('hostname') + ' Stalwart ESMTP at your service'".to_string(),
else_: "system('hostname') + ' INBUXA ESMTP at your service'".to_string(),
..Default::default()
},
hostname: Expression {
+1 -1
View File
@@ -130,7 +130,7 @@ impl<T: SessionStream> Session<T> {
.await
.filter(|g| !g.is_empty())
.map(|g| format!("220 {}\r\n", g))
.unwrap_or_else(|| "220 Stalwart ESMTP at your service.\r\n".to_string());
.unwrap_or_else(|| concat!("220 ", types::brand!(), " ESMTP at your service.\r\n").to_string());
if self.write(greeting.as_bytes()).await.is_err() {
return false;
+2 -2
View File
@@ -3661,8 +3661,8 @@ impl EventType {
EventType::Security(SecurityEvent::IpAllowExpired) => "IP allow expired",
EventType::Security(SecurityEvent::IpUnauthorized) => "Unauthorized IP address",
EventType::Security(SecurityEvent::Unauthorized) => "Unauthorized access",
EventType::Server(ServerEvent::Startup) => "Starting Stalwart Server",
EventType::Server(ServerEvent::Shutdown) => "Shutting down Stalwart Server",
EventType::Server(ServerEvent::Startup) => "Starting INBUXA Server",
EventType::Server(ServerEvent::Shutdown) => "Shutting down INBUXA Server",
EventType::Server(ServerEvent::StartupError) => "Server startup error",
EventType::Server(ServerEvent::ThreadError) => "Server thread error",
EventType::Server(ServerEvent::Licensing) => "Server licensing event",
+39
View File
@@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: 2026 John Coffey
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
//! The product's name, in one place.
//!
//! Every name the server shows people (protocol greetings, the HTTP sign-in
//! realm, the startup banner, calendar product ids, the name mail clients see
//! during setup) comes from here. That keeps the rebrand to a single file when
//! merging upstream releases, instead of a scattering of string edits.
//!
//! These are macros, not constants, so they can be joined into other string
//! literals at compile time with `concat!`.
/// The product name: `INBUXA`.
#[macro_export]
macro_rules! brand {
() => {
"INBUXA"
};
}
/// The server's full name: `INBUXA Server`.
#[macro_export]
macro_rules! brand_server {
() => {
concat!($crate::brand!(), " Server")
};
}
/// The iCalendar and vCard `PRODID`.
#[macro_export]
macro_rules! brand_prodid {
() => {
concat!("-//", $crate::brand!(), "//", $crate::brand_server!(), "//EN")
};
}
+1
View File
@@ -6,6 +6,7 @@
pub mod acl;
pub mod blob;
pub mod branding;
pub mod blob_hash;
pub mod collection;
pub mod dead_property;