Compare commits

..

10 Commits

Author SHA1 Message Date
FreddleSpl0it
06f308a934 [Web] Sync User enabled/disabled status from IDP 2026-02-24 13:25:47 +01:00
renovate[bot]
404e2f0190 Update actions/stale action to v10.2.0 (#7062) 2026-02-18 08:10:48 +01:00
milkmaker
885ba2510e Translations update from Weblate (#7055)
* [Web] Updated lang.cs-cz.json

Co-authored-by: Filip Hajny <filip@hajny.net>
Co-authored-by: milkmaker <milkmaker@mailcow.de>

* [Web] Updated lang.ru-ru.json

Co-authored-by: Habetdin <15926758+Habetdin@users.noreply.github.com>

---------

Co-authored-by: Filip Hajny <filip@hajny.net>
Co-authored-by: Habetdin <15926758+Habetdin@users.noreply.github.com>
2026-02-09 01:52:35 +01:00
milkmaker
0428f5c9bd update postscreen_access.cidr (#7042) 2026-02-01 22:45:03 +01:00
milkmaker
a70c23065c Translations update from Weblate (#7040)
* [Web] Updated lang.vi-vn.json

Co-authored-by: Phu D. Nguyen <sillycat@duck.com>

* [Web] Updated lang.zh-tw.json

Co-authored-by: Proton Chang <protonmo@gmail.com>

* [Web] Updated lang.si-si.json

Co-authored-by: Matjaž Tekavec <matjaz@moj-svet.si>

---------

Co-authored-by: Phu D. Nguyen <sillycat@duck.com>
Co-authored-by: Proton Chang <protonmo@gmail.com>
Co-authored-by: Matjaž Tekavec <matjaz@moj-svet.si>
2026-02-01 22:44:52 +01:00
FreddleSpl0it
caaa4a414d [Web] Fix datatables search after PR #7022 2026-01-29 10:26:44 +01:00
FreddleSpl0it
c3d841340c [Dovecot][PHP][SOGo] Update Images 2026-01-28 11:28:36 +01:00
FreddleSpl0it
b8cd00111f Merge pull request #7007 from moregeek/feat/allow_preset_passwords
feat: allow preset of passwords via environment vars
2026-01-28 10:18:56 +01:00
FreddleSpl0it
81cda80651 Merge pull request #7021 from mailcow/feat/restrict-alias-sending
[Postfix] Configurable send permissions for alias addresses
2026-01-28 10:03:02 +01:00
Stefan Morgenthaler
c485968e7f feat: allow preset of passwords via environment vars
Signed-off-by: Stefan Morgenthaler <dev@morgenthaler.at>
2026-01-14 11:42:15 +01:00
17 changed files with 176 additions and 57 deletions

View File

@@ -14,7 +14,7 @@ jobs:
pull-requests: write
steps:
- name: Mark/Close Stale Issues and Pull Requests 🗑️
uses: actions/stale@v10.1.1
uses: actions/stale@v10.2.0
with:
repo-token: ${{ secrets.STALE_ACTION_PAT }}
days-before-stale: 60

View File

@@ -155,6 +155,11 @@ while (true) {
continue;
}
// Determine if account is enabled in Keycloak
$keycloak_account_active = isset($user['enabled']) ? intval($user['enabled']) : 1;
$status = ($keycloak_account_active == 1) ? "enabled" : "disabled";
logMsg("info", "User " . $user['email'] . " is {$status} in Keycloak");
// try get mailbox user
$stmt = $pdo->prepare("SELECT
mailbox.*,
@@ -172,6 +177,12 @@ while (true) {
$_SESSION['access_all_exception'] = '1';
if (!$row && intval($iam_settings['import_users']) == 1){
// Skip disabled users during import if sync_disabled_users is enabled
if (intval($iam_settings['sync_disabled_users']) == 1 && $keycloak_account_active == 0) {
logMsg("info", "Skipping import of disabled user " . $user['email']);
continue;
}
if ($mapper_key === false){
if (!empty($iam_settings['default_template'])) {
$mbox_template = $iam_settings['default_template'];
@@ -202,13 +213,26 @@ while (true) {
continue;
}
$mbox_template = $iam_settings['templates'][$mapper_key];
// mailbox user does exist, sync attribtues...
logMsg("info", "Syncing attributes for user " . $user['email']);
mailbox('edit', 'mailbox_from_template', array(
// Prepare update data with active status
$update_data = array(
'username' => $user['email'],
'name' => $user['firstName'] . " " . $user['lastName'],
'template' => $mbox_template
));
);
// Add active status if sync_disabled_users is enabled
if (intval($iam_settings['sync_disabled_users']) == 1) {
if ($row['active'] != $keycloak_account_active) {
$update_data['active'] = $keycloak_account_active;
$status_change = ($keycloak_account_active == 1) ? "enabled" : "disabled";
logMsg("info", "Changing active status for user " . $user['email'] . " to {$status_change}");
}
}
// mailbox user does exist, sync attributes...
logMsg("info", "Syncing attributes for user " . $user['email']);
mailbox('edit', 'mailbox_from_template', $update_data);
} else {
// skip mailbox user
logMsg("info", "Skipping user " . $user['email']);

View File

@@ -118,7 +118,7 @@ if (!empty($iam_settings['filter'])) {
}
$response = $ldap_query->where($iam_settings['username_field'], "*")
->where($iam_settings['attribute_field'], "*")
->select([$iam_settings['username_field'], $iam_settings['attribute_field'], 'displayname'])
->select([$iam_settings['username_field'], $iam_settings['attribute_field'], 'displayname', 'userAccountControl', 'pwdAccountLockedTime'])
->paginate($max);
// Process the users
@@ -138,6 +138,41 @@ foreach ($response as $user) {
$user_template = $user[$iam_settings['attribute_field']][0];
$mapper_key = array_search($user_template, $iam_settings['mappers']);
// Determine if account is disabled in LDAP (multi-provider support)
$ldap_account_active = 1; // Default to active
$has_disabled_attr = false;
$disabled_check_method = "none";
// Try Active Directory userAccountControl first
if (isset($user['useraccountcontrol'][0])) {
$has_disabled_attr = true;
$disabled_check_method = "AD-userAccountControl";
$uac = intval($user['useraccountcontrol'][0]);
// UAC flag 0x0002 indicates ACCOUNTDISABLE
// If bit is set, account is disabled
$ldap_account_active = ($uac & 0x0002) ? 0 : 1;
$uac_status = ($ldap_account_active == 1) ? "enabled" : "disabled";
logMsg("info", "User " . $user[$iam_settings['username_field']][0] . " is {$uac_status} (AD UAC: {$uac})");
}
// Try OpenLDAP/389DS/FreeIPA pwdAccountLockedTime
elseif (isset($user['pwdaccountlockedtime'])) {
$has_disabled_attr = true;
$disabled_check_method = "OpenLDAP-pwdAccountLockedTime";
// If pwdAccountLockedTime attribute exists and has a value, account is locked/disabled
$ldap_account_active = (!empty($user['pwdaccountlockedtime'][0])) ? 0 : 1;
$status = ($ldap_account_active == 1) ? "enabled" : "disabled";
logMsg("info", "User " . $user[$iam_settings['username_field']][0] . " is {$status} (OpenLDAP/389DS)");
}
else {
// No disabled attribute found - this is normal for some LDAP implementations
// We'll skip disabled state sync for this user
logMsg("debug", "User " . $user[$iam_settings['username_field']][0] . " - no disabled attribute found (userAccountControl or pwdAccountLockedTime), skipping status sync");
}
if (empty($user[$iam_settings['username_field']][0])){
logMsg("warning", "Skipping user " . $user['displayname'][0] . " due to empty LDAP ". $iam_settings['username_field'] . " property.");
continue;
@@ -145,6 +180,12 @@ foreach ($response as $user) {
$_SESSION['access_all_exception'] = '1';
if (!$row && intval($iam_settings['import_users']) == 1){
// Skip disabled users during import if sync_disabled_users is enabled
if (intval($iam_settings['sync_disabled_users']) == 1 && $has_disabled_attr && $ldap_account_active == 0) {
logMsg("info", "Skipping import of disabled user " . $user[$iam_settings['username_field']][0] . " (method: {$disabled_check_method})");
continue;
}
if ($mapper_key === false){
if (!empty($iam_settings['default_template'])) {
$mbox_template = $iam_settings['default_template'];
@@ -174,13 +215,26 @@ foreach ($response as $user) {
continue;
}
$mbox_template = $iam_settings['templates'][$mapper_key];
// mailbox user does exist, sync attribtues...
logMsg("info", "Syncing attributes for user " . $user[$iam_settings['username_field']][0]);
mailbox('edit', 'mailbox_from_template', array(
// Prepare update data with active status
$update_data = array(
'username' => $user[$iam_settings['username_field']][0],
'name' => $user['displayname'][0],
'template' => $mbox_template
));
);
// Add active status if sync_disabled_users is enabled and a disabled attribute was found
if (intval($iam_settings['sync_disabled_users']) == 1 && $has_disabled_attr) {
if ($row['active'] != $ldap_account_active) {
$update_data['active'] = $ldap_account_active;
$status_change = ($ldap_account_active == 1) ? "enabled" : "disabled";
logMsg("info", "Changing active status for user " . $user[$iam_settings['username_field']][0] . " to {$status_change} (method: {$disabled_check_method})");
}
}
// mailbox user does exist, sync attributes...
logMsg("info", "Syncing attributes for user " . $user[$iam_settings['username_field']][0]);
mailbox('edit', 'mailbox_from_template', $update_data);
} else {
// skip mailbox user
logMsg("info", "Skipping user " . $user[$iam_settings['username_field']][0]);

View File

@@ -1,6 +1,6 @@
# Whitelist generated by Postwhite v3.4 on Thu Jan 1 00:24:01 UTC 2026
# Whitelist generated by Postwhite v3.4 on Sun Feb 1 00:29:33 UTC 2026
# https://github.com/stevejenkins/postwhite/
# 2105 total rules
# 2102 total rules
2a00:1450:4000::/36 permit
2a01:111:f400::/48 permit
2a01:111:f403:2800::/53 permit
@@ -54,8 +54,8 @@
8.36.116.0/24 permit
8.39.144.0/24 permit
12.130.86.238 permit
13.107.213.38 permit
13.107.246.38 permit
13.107.213.51 permit
13.107.246.51 permit
13.108.16.0/20 permit
13.110.208.0/21 permit
13.110.209.0/24 permit
@@ -2088,11 +2088,6 @@
2001:748:400:3301::3 permit
2001:748:400:3301::4 permit
2404:6800:4000::/36 permit
2603:1010:3:3::5b permit
2603:1020:201:10::10f permit
2603:1030:20e:3::23c permit
2603:1030:b:3::152 permit
2603:1030:c02:8::14 permit
2607:f8b0:4000::/36 permit
2620:109:c003:104::/64 permit
2620:109:c003:104::215 permit
@@ -2105,6 +2100,8 @@
2620:10d:c09c:400::8:1 permit
2620:119:50c0:207::/64 permit
2620:119:50c0:207::215 permit
2620:1ec:46::51 permit
2620:1ec:bdf::51 permit
2800:3f0:4000::/36 permit
49.12.4.251 permit # checks.mailcow.email
2a01:4f8:c17:7906::10 permit # checks.mailcow.email

View File

@@ -2383,6 +2383,7 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
case "use_tls":
case "login_provisioning":
case "ignore_ssl_errors":
case "sync_disabled_users":
$settings[$row["key"]] = boolval($row["value"]);
break;
default:
@@ -2462,13 +2463,14 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
$_data['login_provisioning'] = isset($_data['login_provisioning']) ? boolval($_data['login_provisioning']) : false;
switch ($_data['authsource']) {
case "keycloak":
$_data['server_url'] = (!empty($_data['server_url'])) ? rtrim($_data['server_url'], '/') : null;
$_data['mailpassword_flow'] = isset($_data['mailpassword_flow']) ? intval($_data['mailpassword_flow']) : 0;
$_data['periodic_sync'] = isset($_data['periodic_sync']) ? intval($_data['periodic_sync']) : 0;
$_data['import_users'] = isset($_data['import_users']) ? intval($_data['import_users']) : 0;
$_data['sync_interval'] = (!empty($_data['sync_interval'])) ? intval($_data['sync_interval']) : 15;
$_data['sync_interval'] = $_data['sync_interval'] < 1 ? 1 : $_data['sync_interval'];
$required_settings = array('authsource', 'server_url', 'realm', 'client_id', 'client_secret', 'redirect_url', 'version', 'mailpassword_flow', 'periodic_sync', 'import_users', 'sync_interval', 'ignore_ssl_error', 'login_provisioning');
$_data['server_url'] = (!empty($_data['server_url'])) ? rtrim($_data['server_url'], '/') : null;
$_data['mailpassword_flow'] = isset($_data['mailpassword_flow']) ? intval($_data['mailpassword_flow']) : 0;
$_data['periodic_sync'] = isset($_data['periodic_sync']) ? intval($_data['periodic_sync']) : 0;
$_data['import_users'] = isset($_data['import_users']) ? intval($_data['import_users']) : 0;
$_data['sync_disabled_users'] = isset($_data['sync_disabled_users']) ? intval($_data['sync_disabled_users']) : 0;
$_data['sync_interval'] = (!empty($_data['sync_interval'])) ? intval($_data['sync_interval']) : 15;
$_data['sync_interval'] = $_data['sync_interval'] < 1 ? 1 : $_data['sync_interval'];
$required_settings = array('authsource', 'server_url', 'realm', 'client_id', 'client_secret', 'redirect_url', 'version', 'mailpassword_flow', 'periodic_sync', 'import_users', 'sync_disabled_users', 'sync_interval', 'ignore_ssl_error', 'login_provisioning');
break;
case "generic-oidc":
$_data['authorize_url'] = (!empty($_data['authorize_url'])) ? $_data['authorize_url'] : null;
@@ -2478,18 +2480,19 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
$required_settings = array('authsource', 'authorize_url', 'token_url', 'client_id', 'client_secret', 'redirect_url', 'userinfo_url', 'client_scopes', 'ignore_ssl_error', 'login_provisioning');
break;
case "ldap":
$_data['host'] = (!empty($_data['host'])) ? str_replace(" ", "", $_data['host']) : "";
$_data['port'] = (!empty($_data['port'])) ? intval($_data['port']) : 389;
$_data['username_field'] = (!empty($_data['username_field'])) ? strtolower($_data['username_field']) : "mail";
$_data['attribute_field'] = (!empty($_data['attribute_field'])) ? strtolower($_data['attribute_field']) : "";
$_data['filter'] = (!empty($_data['filter'])) ? $_data['filter'] : "";
$_data['periodic_sync'] = isset($_data['periodic_sync']) ? intval($_data['periodic_sync']) : 0;
$_data['import_users'] = isset($_data['import_users']) ? intval($_data['import_users']) : 0;
$_data['use_ssl'] = isset($_data['use_ssl']) ? boolval($_data['use_ssl']) : false;
$_data['use_tls'] = isset($_data['use_tls']) && !$_data['use_ssl'] ? boolval($_data['use_tls']) : false;
$_data['sync_interval'] = (!empty($_data['sync_interval'])) ? intval($_data['sync_interval']) : 15;
$_data['sync_interval'] = $_data['sync_interval'] < 1 ? 1 : $_data['sync_interval'];
$required_settings = array('authsource', 'host', 'port', 'basedn', 'username_field', 'filter', 'attribute_field', 'binddn', 'bindpass', 'periodic_sync', 'import_users', 'sync_interval', 'use_ssl', 'use_tls', 'ignore_ssl_error', 'login_provisioning');
$_data['host'] = (!empty($_data['host'])) ? str_replace(" ", "", $_data['host']) : "";
$_data['port'] = (!empty($_data['port'])) ? intval($_data['port']) : 389;
$_data['username_field'] = (!empty($_data['username_field'])) ? strtolower($_data['username_field']) : "mail";
$_data['attribute_field'] = (!empty($_data['attribute_field'])) ? strtolower($_data['attribute_field']) : "";
$_data['filter'] = (!empty($_data['filter'])) ? $_data['filter'] : "";
$_data['periodic_sync'] = isset($_data['periodic_sync']) ? intval($_data['periodic_sync']) : 0;
$_data['import_users'] = isset($_data['import_users']) ? intval($_data['import_users']) : 0;
$_data['sync_disabled_users'] = isset($_data['sync_disabled_users']) ? intval($_data['sync_disabled_users']) : 0;
$_data['use_ssl'] = isset($_data['use_ssl']) ? boolval($_data['use_ssl']) : false;
$_data['use_tls'] = isset($_data['use_tls']) && !$_data['use_ssl'] ? boolval($_data['use_tls']) : false;
$_data['sync_interval'] = (!empty($_data['sync_interval'])) ? intval($_data['sync_interval']) : 15;
$_data['sync_interval'] = $_data['sync_interval'] < 1 ? 1 : $_data['sync_interval'];
$required_settings = array('authsource', 'host', 'port', 'basedn', 'username_field', 'filter', 'attribute_field', 'binddn', 'bindpass', 'periodic_sync', 'import_users', 'sync_disabled_users', 'sync_interval', 'use_ssl', 'use_tls', 'ignore_ssl_error', 'login_provisioning');
break;
}

View File

@@ -3691,6 +3691,11 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
}
}
// Override active status if explicitly provided (IDP sync takes priority over template)
if (isset($_data['active'])) {
$mailbox_attributes['active'] = $_data['active'];
}
$mailbox_attributes['quota'] = intval($mailbox_attributes['quota'] / 1048576);
$result = mailbox('edit', 'mailbox', $mailbox_attributes);
if ($result === false) return $result;

View File

@@ -1007,9 +1007,9 @@ if (isset($_GET['query'])) {
['db' => 'last_pw_change', 'dt' => 5, 'dummy' => true, 'order_subquery' => "JSON_EXTRACT(attributes, '$.passwd_update')"],
['db' => 'in_use', 'dt' => 6, 'dummy' => true, 'order_subquery' => "(SELECT SUM(bytes) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`) / `m`.`quota`"],
['db' => 'name', 'dt' => 7],
['db' => 'messages', 'dt' => 18, 'dummy' => true, 'order_subquery' => "SELECT SUM(messages) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`"],
['db' => 'tags', 'dt' => 20, 'dummy' => true, 'search' => ['join' => 'LEFT JOIN `tags_mailbox` AS `tm` ON `tm`.`username` = `m`.`username`', 'where_column' => '`tm`.`tag_name`']],
['db' => 'active', 'dt' => 21],
['db' => 'messages', 'dt' => 20, 'dummy' => true, 'order_subquery' => "SELECT SUM(messages) FROM `quota2` WHERE `quota2`.`username` = `m`.`username`"],
['db' => 'tags', 'dt' => 23, 'dummy' => true, 'search' => ['join' => 'LEFT JOIN `tags_mailbox` AS `tm` ON `tm`.`username` = `m`.`username`', 'where_column' => '`tm`.`tag_name`']],
['db' => 'active', 'dt' => 24],
];
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/lib/ssp.class.php';

View File

@@ -111,7 +111,8 @@
"tags": "Štítky",
"dry": "Simulovat synchronizaci",
"internal": "Interní",
"internal_info": "Interní aliasy jsou přístupné jen z vlastních domén nebo jejich aliasů."
"internal_info": "Interní aliasy jsou přístupné jen z vlastních domén nebo jejich aliasů.",
"sender_allowed": "Povolit jako alias pro odesílání"
},
"admin": {
"access": "Přístupy",
@@ -304,7 +305,7 @@
"rspamd_com_settings": "Název nastavení se vygeneruje automaticky, viz ukázky nastavení níže. Více informací viz <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd dokumentace</a>",
"rspamd_global_filters": "Mapa globálních filtrů",
"rspamd_global_filters_agree": "Budu opatrný!",
"rspamd_global_filters_info": "Mapa globálních filtrů obsahuje různé seznamy povolených a zakázaných serverů",
"rspamd_global_filters_info": "Mapa globálních filtrů obsahuje různé seznamy povolených a zakázaných serverů.",
"rspamd_global_filters_regex": "Názvy stačí k vysvětlení. Položky musejí obsahovat jen platné regulární výrazy ve tvaru \"/vyraz/parametry\" (e.g. <code>/.+@domena\\.tld/i</code>).<br>\n Každý výraz bude podroben základní kontrole, přesto je možné Rspamd 'rozbít', nebude-li syntax zcela korektní.<br>\n Rspamd se pokusí po každé změně načíst mapu znovu. V případě potíží <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">restartujte Rspamd</a>, aby se konfigurace načetla explicitně.",
"rspamd_settings_map": "Nastavení Rspamd",
"sal_level": "Úroveň 'Moo'",
@@ -780,7 +781,9 @@
"mta_sts_max_age_info": "Doba v sekundách, po niž poštovní servery mohou toho pravidlo držet v mezipaměti bez nutnosti obnovení.",
"mta_sts_mx": "Server MX",
"mta_sts_mx_info": "Dovoluje odesílání jen výslovně vypsaným poštovním serverům; odesílající server kontroluje, že server MX určený v DNS odpovídá pravidlu, a povolí doručení jen s platným certifikátem TLS (chrání přes útokem typu MITM).",
"mta_sts_mx_notice": "Lze zadat více serverů MX (oddělte čárkou)."
"mta_sts_mx_notice": "Lze zadat více serverů MX (oddělte čárkou).",
"sender_allowed": "Povolit jako alias pro odesílání",
"sender_allowed_info": "Není-li povoleno, lze alias použít jen pro příjem pošty. Lze také obejít v Sender ACL a nastavit konkrétní schránky, jež tento alias mohou používat"
},
"fido2": {
"confirm": "Potvrdit",

View File

@@ -234,6 +234,8 @@
"iam_mapping": "Attribut Mapping",
"iam_bindpass": "Bind Passwort",
"iam_periodic_full_sync": "Vollsynchronisation",
"iam_sync_disabled_users": "Deaktivierte Benutzer synchronisieren",
"iam_sync_disabled_users_info": "Mailcow-Benutzer automatisch deaktivieren, wenn sie in LDAP/Keycloak deaktiviert sind, und wieder aktivieren, wenn sie reaktiviert werden. Unterstützt Active Directory (userAccountControl), OpenLDAP, 389 Directory Server und FreeIPA (pwdAccountLockedTime).",
"iam_port": "Port",
"iam_realm": "Realm",
"iam_redirect_url": "Redirect Url",

View File

@@ -241,6 +241,8 @@
"iam_mapping": "Attribute Mapping",
"iam_bindpass": "Bind Password",
"iam_periodic_full_sync": "Periodic Full Sync",
"iam_sync_disabled_users": "Sync user disabled status",
"iam_sync_disabled_users_info": "Automatically disable mailcow users when they are disabled in LDAP/Keycloak, and re-enable them when they are re-enabled. Supports Active Directory (userAccountControl), OpenLDAP, 389 Directory Server, and FreeIPA (pwdAccountLockedTime).",
"iam_port": "Port",
"iam_realm": "Realm",
"iam_redirect_url": "Redirect Url",

View File

@@ -111,7 +111,8 @@
"validate": "Проверить",
"validation_success": "Проверка прошла успешно",
"internal": "Внутренний",
"internal_info": "Внутренние псевдонимы доступны только из самого домена или доменов-псевдонимов."
"internal_info": "Внутренние псевдонимы доступны только из самого домена или доменов-псевдонимов.",
"sender_allowed": "Разрешить отправку с этим псевдонимом"
},
"admin": {
"access": "Настройки доступа",
@@ -781,7 +782,9 @@
"mta_sts_max_age_info": "Время в секундах, в течение которого принимающие почтовые серверы могут кэшировать эту политику перед повторной загрузкой.",
"mta_sts_mx": "Сервер MX",
"mta_sts_mx_info": "Разрешает отправку только на явно указанные имена хостов почтовых серверов; отправляющий MTA проверяет, соответствует ли DNS-имя MX-хоста списку политик, и разрешает доставку только с подлинным TLS-сертификатом (защита от MITM).",
"mta_sts_mx_notice": "Можно указать несколько MX-серверов (через запятую)."
"mta_sts_mx_notice": "Можно указать несколько MX-серверов (через запятую).",
"sender_allowed": "Разрешить отправку с этим псевдонимом",
"sender_allowed_info": "Если отключено, этот псевдоним может только принимать почту. Используйте ACL отправителя, чтобы переопределить и предоставить определенным почтовым ящикам разрешение на отправку."
},
"fido2": {
"confirm": "Подтвердить",

View File

@@ -111,7 +111,8 @@
"timeout2": "Časovna omejitev za povezavo do lokalnega gostitelja",
"dry": "Simuliraj sinhronizacijo",
"internal": "Notranje",
"internal_info": "Notranji vzdevki so dostopni samo iz lastne domene ali vzdevkov domen."
"internal_info": "Notranji vzdevki so dostopni samo iz lastne domene ali vzdevkov domen.",
"sender_allowed": "Dovoli pošiljanje kot ta vzdevek"
},
"admin": {
"access": "Dostop",
@@ -780,7 +781,9 @@
"mta_sts_mx_info": "Omogoča pošiljanje samo na izrecno navedena imena gostiteljskih strežnikov poštnih strežnikov; pošiljajoči MTA preveri, ali se ime gostitelja DNS MX ujema s seznamom pravilnikov, in dovoljuje dostavo le z veljavnim potrdilom TLS (zaščita pred MITM).",
"mta_sts_mx_notice": "Določiti je mogoče več strežnikov MX (ločenih z vejicami).",
"internal": "Notranje",
"internal_info": "Notranji vzdevki so dostopni samo iz lastne domene ali vzdevkov domen."
"internal_info": "Notranji vzdevki so dostopni samo iz lastne domene ali vzdevkov domen.",
"sender_allowed": "Dovoli pošiljanje kot ta vzdevek",
"sender_allowed_info": "Če je onemogočeno, lahko ta vzdevek samo prejema pošto. Za preglasitev in dodelitev dovoljenja za pošiljanje določenim poštnim predalom uporabite seznam za nadzor dostopa pošiljatelja."
},
"footer": {
"restart_container_info": "<b>Pomembno:</b> Eleganten ponovni zagon lahko traja nekaj časa, zato počakajte, da se konča.",

View File

@@ -111,7 +111,8 @@
"timeout2": "Thời gian chờ kết nối đến máy chủ cục bộ",
"username": "Tên người dùng",
"validate": "Xác thực",
"validation_success": "Xác thực thành công"
"validation_success": "Xác thực thành công",
"sender_allowed": "Cho phép gửi dưới bí danh này"
},
"admin": {
"access": "Truy cập",

View File

@@ -24,7 +24,7 @@
"sogo_access": "管理 SOGo 存取權",
"sogo_profile_reset": "重設 SOGo 個人資料",
"spam_alias": "臨時別名",
"spam_policy": "名單/名單",
"spam_policy": "封鎖名單/允許名單",
"spam_score": "垃圾郵件分數",
"syncjobs": "同步任務",
"tls_policy": "TLS 規則",
@@ -1180,7 +1180,7 @@
"no_last_login": "沒有最後 UI 登入訊息",
"no_record": "沒有紀錄",
"open_logs": "開啟日誌",
"open_webmail_sso": "网络邮件",
"open_webmail_sso": "網頁信箱",
"password": "密碼",
"password_now": "目前密碼 (確認更改)",
"password_repeat": "密碼 (再次輸入)",

View File

@@ -249,6 +249,17 @@
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
<label class="control-label">{{ lang.admin.iam_sync_disabled_users }}</label>
</div>
<div class="col-12 col-md-9">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="sync_disabled_users" value="1" {% if iam_settings.sync_disabled_users == 1 %}checked{% endif %}>
<label class="form-check-label text-muted small">{{ lang.admin.iam_sync_disabled_users_info }}</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
<label class="control-label">{{ lang.admin.iam_sync_interval }}</label>
@@ -696,6 +707,17 @@
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
<label class="control-label">{{ lang.admin.iam_sync_disabled_users }}</label>
</div>
<div class="col-12 col-md-9">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" name="sync_disabled_users" value="1" {% if iam_settings.sync_disabled_users == 1 %}checked{% endif %}>
<label class="form-check-label text-muted small">{{ lang.admin.iam_sync_disabled_users_info }}</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-md-3 d-flex align-items-center justify-content-md-end">
<label class="control-label">{{ lang.admin.iam_sync_interval }}</label>

View File

@@ -117,7 +117,7 @@ services:
- rspamd
php-fpm-mailcow:
image: ghcr.io/mailcow/phpfpm:8.2.29
image: ghcr.io/mailcow/phpfpm:8.2.29-1
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
depends_on:
- redis-mailcow
@@ -200,7 +200,7 @@ services:
- phpfpm
sogo-mailcow:
image: ghcr.io/mailcow/sogo:5.12.4
image: ghcr.io/mailcow/sogo:5.12.4-1
environment:
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
@@ -252,7 +252,7 @@ services:
- sogo
dovecot-mailcow:
image: ghcr.io/mailcow/dovecot:2.3.21.1
image: ghcr.io/mailcow/dovecot:2.3.21.1-1
depends_on:
- mysql-mailcow
- netfilter-mailcow

View File

@@ -186,13 +186,13 @@ DBNAME=mailcow
DBUSER=mailcow
# Please use long, random alphanumeric strings (A-Za-z0-9)
DBPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
DBROOT=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
DBPASS=${MAILCOW_DBPASS:-$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)}
DBROOT=${MAILCOW_DBROOT:-$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)}
# ------------------------------
# REDIS configuration
# ------------------------------
REDISPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
REDISPASS=${MAILCOW_REDISPASS:-$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)}
# ------------------------------
# HTTP/S Bindings