1
0
mirror of https://github.com/mailcow/mailcow-dockerized.git synced 2025-12-15 19:06:03 +00:00

Merge pull request #6718 from mailcow/staging

Update 2025-09
This commit is contained in:
FreddleSpl0it
2025-09-10 11:05:09 +02:00
committed by GitHub
78 changed files with 4811 additions and 1699 deletions

View File

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

View File

@@ -27,7 +27,7 @@ jobs:
- "watchdog-mailcow"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: Setup Docker
run: |
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh

View File

@@ -8,11 +8,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Run the Action
uses: devops-infra/action-pull-request@v0.6.0
uses: devops-infra/action-pull-request@v0.6.1
with:
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}

View File

@@ -13,7 +13,7 @@ jobs:
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up QEMU
uses: docker/setup-qemu-action@v3

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Generate postscreen_access.cidr
run: |

1
.gitignore vendored
View File

@@ -75,3 +75,4 @@ refresh_images.sh
update_diffs/
create_cold_standby.sh
!data/conf/nginx/mailcow_auth.conf
data/conf/postfix/postfix-tlspol

View File

@@ -23,9 +23,6 @@ A big thank you to everyone supporting us on GitHub Sponsors—your contribution
<a href="https://www.maehdros.com/" target=_blank><img
src="https://avatars.githubusercontent.com/u/173894712" height="58"
/></a>
<a href="https://macarne.com/" target=_blank><img
src="https://avatars.githubusercontent.com/u/149550368?s=200&v=4" height="58"
/></a>
### 50$/Month Sponsors
<a href="https://github.com/vnukhr" target=_blank><img

224
_modules/scripts/core.sh Normal file
View File

@@ -0,0 +1,224 @@
#!/usr/bin/env bash
# _modules/scripts/core.sh
# THIS SCRIPT IS DESIGNED TO BE RUNNING BY MAILCOW SCRIPTS ONLY!
# DO NOT, AGAIN, NOT TRY TO RUN THIS SCRIPT STANDALONE!!!!!!
# ANSI color for red errors
RED='\e[31m'
GREEN='\e[32m'
YELLOW='\e[33m'
BLUE='\e[34m'
MAGENTA='\e[35m'
LIGHT_RED='\e[91m'
LIGHT_GREEN='\e[92m'
NC='\e[0m'
caller="${BASH_SOURCE[1]##*/}"
get_installed_tools(){
for bin in openssl curl docker git awk sha1sum grep cut jq; do
if [[ -z $(command -v ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi
done
if grep --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo -e "${LIGHT_RED}BusyBox grep detected, please install gnu grep, \"apk add --no-cache --upgrade grep\"${NC}"; exit 1; fi
# This will also cover sort
if cp --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo -e "${LIGHT_RED}BusyBox cp detected, please install coreutils, \"apk add --no-cache --upgrade coreutils\"${NC}"; exit 1; fi
if sed --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo -e "${LIGHT_RED}BusyBox sed detected, please install gnu sed, \"apk add --no-cache --upgrade sed\"${NC}"; exit 1; fi
}
get_docker_version(){
# Check Docker Version (need at least 24.X)
docker_version=$(docker version --format '{{.Server.Version}}' | cut -d '.' -f 1)
}
get_compose_type(){
if docker compose > /dev/null 2>&1; then
if docker compose version --short | grep -e "^2." -e "^v2." > /dev/null 2>&1; then
COMPOSE_VERSION=native
COMPOSE_COMMAND="docker compose"
if [[ "$caller" == "update.sh" ]]; then
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' "$SCRIPT_DIR/mailcow.conf"
fi
echo -e "\e[33mFound Docker Compose Plugin (native).\e[0m"
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
sleep 2
echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
else
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
exit 1
fi
elif docker-compose > /dev/null 2>&1; then
if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
if docker-compose version --short | grep "^2." > /dev/null 2>&1; then
COMPOSE_VERSION=standalone
COMPOSE_COMMAND="docker-compose"
if [[ "$caller" == "update.sh" ]]; then
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' "$SCRIPT_DIR/mailcow.conf"
fi
echo -e "\e[33mFound Docker Compose Standalone.\e[0m"
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
sleep 2
echo -e "\e[33mNotice: For an automatic update of docker-compose please use the update_compose.sh scripts located at the helper-scripts folder.\e[0m"
else
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
echo -e "\e[31mPlease update/install manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
exit 1
fi
fi
else
echo -e "\e[31mCannot find Docker Compose.\e[0m"
echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
exit 1
fi
}
detect_bad_asn() {
echo -e "\e[33mDetecting if your IP is listed on Spamhaus Bad ASN List...\e[0m"
response=$(curl --connect-timeout 15 --max-time 30 -s -o /dev/null -w "%{http_code}" "https://asn-check.mailcow.email")
if [ "$response" -eq 503 ]; then
if [ -z "$SPAMHAUS_DQS_KEY" ]; then
echo -e "\e[33mYour server's public IP uses an AS that is blocked by Spamhaus to use their DNS public blocklists for Postfix.\e[0m"
echo -e "\e[33mmailcow did not detected a value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf!\e[0m"
sleep 2
echo ""
echo -e "\e[33mTo use the Spamhaus DNS Blocklists again, you will need to create a FREE account for their Data Query Service (DQS) at: https://www.spamhaus.com/free-trial/sign-up-for-a-free-data-query-service-account\e[0m"
echo -e "\e[33mOnce done, enter your DQS API key in mailcow.conf and mailcow will do the rest for you!\e[0m"
echo ""
sleep 2
else
echo -e "\e[33mYour server's public IP uses an AS that is blocked by Spamhaus to use their DNS public blocklists for Postfix.\e[0m"
echo -e "\e[32mmailcow detected a Value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf. Postfix will use DQS with the given API key...\e[0m"
fi
elif [ "$response" -eq 200 ]; then
echo -e "\e[33mCheck completed! Your IP is \e[32mclean\e[0m"
elif [ "$response" -eq 429 ]; then
echo -e "\e[33mCheck completed! \e[31mYour IP seems to be rate limited on the ASN Check service... please try again later!\e[0m"
else
echo -e "\e[31mCheck failed! \e[0mMaybe a DNS or Network problem?\e[0m"
fi
}
check_online_status() {
CHECK_ONLINE_DOMAINS=('https://github.com' 'https://hub.docker.com')
for domain in "${CHECK_ONLINE_DOMAINS[@]}"; do
if timeout 6 curl --head --silent --output /dev/null ${domain}; then
return 0
fi
done
return 1
}
prefetch_images() {
[[ -z ${BRANCH} ]] && { echo -e "\e[33m\nUnknown branch...\e[0m"; exit 1; }
git fetch origin #${BRANCH}
while read image; do
RET_C=0
until docker pull "${image}"; do
RET_C=$((RET_C + 1))
echo -e "\e[33m\nError pulling $image, retrying...\e[0m"
[ ${RET_C} -gt 3 ] && { echo -e "\e[31m\nToo many failed retries, exiting\e[0m"; exit 1; }
sleep 1
done
done < <(git show "origin/${BRANCH}:docker-compose.yml" | grep "image:" | awk '{ gsub("image:","", $3); print $2 }')
}
docker_garbage() {
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd )"
IMGS_TO_DELETE=()
declare -A IMAGES_INFO
COMPOSE_IMAGES=($(grep -oP "image: \K(ghcr\.io/)?mailcow.+" "${SCRIPT_DIR}/docker-compose.yml"))
for existing_image in $(docker images --format "{{.ID}}:{{.Repository}}:{{.Tag}}" | grep -E '(mailcow/|ghcr\.io/mailcow/)'); do
ID=$(echo "$existing_image" | cut -d ':' -f 1)
REPOSITORY=$(echo "$existing_image" | cut -d ':' -f 2)
TAG=$(echo "$existing_image" | cut -d ':' -f 3)
if [[ "$REPOSITORY" == "mailcow/backup" || "$REPOSITORY" == "ghcr.io/mailcow/backup" ]]; then
if [[ "$TAG" != "<none>" ]]; then
continue
fi
fi
if [[ " ${COMPOSE_IMAGES[@]} " =~ " ${REPOSITORY}:${TAG} " ]]; then
continue
else
IMGS_TO_DELETE+=("$ID")
IMAGES_INFO["$ID"]="$REPOSITORY:$TAG"
fi
done
if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then
echo "The following unused mailcow images were found:"
for id in "${IMGS_TO_DELETE[@]}"; do
echo " ${IMAGES_INFO[$id]} ($id)"
done
if [ -z "$FORCE" ]; then
read -r -p "Do you want to delete them to free up some space? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
docker rmi ${IMGS_TO_DELETE[*]}
else
echo "OK, skipped."
fi
else
echo "Running in forced mode! Force removing old mailcow images..."
docker rmi ${IMGS_TO_DELETE[*]}
fi
echo -e "\e[32mFurther cleanup...\e[0m"
echo "If you want to cleanup further garbage collected by Docker, please make sure all containers are up and running before cleaning your system by executing \"docker system prune\""
fi
}
in_array() {
local e match="$1"
shift
for e; do [[ "$e" == "$match" ]] && return 0; done
return 1
}
detect_major_update() {
if [ ${BRANCH} == "master" ]; then
# Array with major versions
# Add major versions here
MAJOR_VERSIONS=(
"2025-02"
"2025-03"
"2025-08"
)
current_version=""
if [[ -f "${SCRIPT_DIR}/data/web/inc/app_info.inc.php" ]]; then
current_version=$(grep 'MAILCOW_GIT_VERSION' ${SCRIPT_DIR}/data/web/inc/app_info.inc.php | sed -E 's/.*MAILCOW_GIT_VERSION="([^"]+)".*/\1/')
fi
if [[ -z "$current_version" ]]; then
return 1
fi
release_url="https://github.com/mailcow/mailcow-dockerized/releases/tag"
updates_to_apply=()
for version in "${MAJOR_VERSIONS[@]}"; do
if [[ "$current_version" < "$version" ]]; then
updates_to_apply+=("$version")
fi
done
if [[ ${#updates_to_apply[@]} -gt 0 ]]; then
echo -e "\e[33m\nMAJOR UPDATES to be applied:\e[0m"
for update in "${updates_to_apply[@]}"; do
echo "$update - $release_url/$update"
done
echo -e "\nPlease read the release notes before proceeding."
read -p "Do you want to proceed with the update? [y/n] " response
if [[ "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "Proceeding with the update..."
else
echo "Update canceled. Exiting."
exit 1
fi
fi
fi
}

View File

@@ -0,0 +1,168 @@
#!/usr/bin/env bash
# _modules/scripts/ipv6_controller.sh
# THIS SCRIPT IS DESIGNED TO BE RUNNING BY MAILCOW SCRIPTS ONLY!
# DO NOT, AGAIN, NOT TRY TO RUN THIS SCRIPT STANDALONE!!!!!!
# 1) Check if the host supports IPv6
get_ipv6_support() {
if grep -qs '^1' /proc/sys/net/ipv6/conf/all/disable_ipv6 2>/dev/null \
|| ! ip -6 route show default &>/dev/null; then
DETECTED_IPV6=false
echo -e "${YELLOW}IPv6 not detected on host ${LIGHT_RED}disabling IPv6 support${YELLOW}.${NC}"
else
DETECTED_IPV6=true
echo -e "IPv6 detected on host ${LIGHT_GREEN}leaving IPv6 support enabled${YELLOW}.${NC}"
fi
}
# 2) Ensure Docker daemon.json has (or create) the required IPv6 settings
docker_daemon_edit(){
DOCKER_DAEMON_CONFIG="/etc/docker/daemon.json"
DOCKER_MAJOR=$(docker version --format '{{.Server.Version}}' 2>/dev/null | cut -d. -f1)
MISSING=()
_has_kv() { grep -Eq "\"$1\"\s*:\s*$2" "$DOCKER_DAEMON_CONFIG" 2>/dev/null; }
if [[ -f "$DOCKER_DAEMON_CONFIG" ]]; then
# reject empty or whitespace-only file immediately
if [[ ! -s "$DOCKER_DAEMON_CONFIG" ]] || ! grep -Eq '[{}]' "$DOCKER_DAEMON_CONFIG"; then
echo -e "${RED}ERROR: $DOCKER_DAEMON_CONFIG exists but is empty or contains no JSON braces please initialize it with valid JSON (e.g. {}).${NC}"
exit 1
fi
# Validate JSON if jq is present
if command -v jq &>/dev/null && ! jq empty "$DOCKER_DAEMON_CONFIG" &>/dev/null; then
echo -e "${RED}ERROR: Invalid JSON in $DOCKER_DAEMON_CONFIG please correct manually.${NC}"
exit 1
fi
# Gather missing keys
! _has_kv ipv6 true && MISSING+=("ipv6: true")
! grep -Eq '"fixed-cidr-v6"\s*:\s*".+"' "$DOCKER_DAEMON_CONFIG" \
&& MISSING+=('fixed-cidr-v6: "fd00:dead:beef:c0::/80"')
if [[ -n "$DOCKER_MAJOR" && "$DOCKER_MAJOR" -le 27 ]]; then
_has_kv ipv6 true && ! _has_kv ip6tables true && MISSING+=("ip6tables: true")
! _has_kv experimental true && MISSING+=("experimental: true")
fi
# Fix if needed
if ((${#MISSING[@]}>0)); then
echo -e "${MAGENTA}Your daemon.json is missing: ${YELLOW}${MISSING[*]}${NC}"
if [[ -n "$FORCE" ]]; then
ans=Y
else
read -p "Would you like to update $DOCKER_DAEMON_CONFIG now? [Y/n] " ans
ans=${ans:-Y}
fi
if [[ $ans =~ ^[Yy]$ ]]; then
cp "$DOCKER_DAEMON_CONFIG" "${DOCKER_DAEMON_CONFIG}.bak"
if command -v jq &>/dev/null; then
TMP=$(mktemp)
JQ_FILTER='.ipv6 = true | .["fixed-cidr-v6"] = "fd00:dead:beef:c0::/80"'
[[ "$DOCKER_MAJOR" && "$DOCKER_MAJOR" -lt 27 ]] \
&& JQ_FILTER+=' | .ip6tables = true | .experimental = true'
jq "$JQ_FILTER" "$DOCKER_DAEMON_CONFIG" >"$TMP" && mv "$TMP" "$DOCKER_DAEMON_CONFIG"
echo -e "${LIGHT_GREEN}daemon.json updated. Restarting Docker...${NC}"
(command -v systemctl &>/dev/null && systemctl restart docker) || service docker restart
echo -e "${YELLOW}Docker restarted.${NC}"
else
echo -e "${RED}Please install jq or manually update daemon.json and restart Docker.${NC}"
exit 1
fi
else
echo -e "${YELLOW}User declined Docker update please insert these changes manually:${NC}"
echo "${MISSING[*]}"
exit 1
fi
fi
else
# Create new daemon.json if missing
if [[ -n "$FORCE" ]]; then
ans=Y
else
read -p "$DOCKER_DAEMON_CONFIG not found. Create it with IPv6 settings? [Y/n] " ans
ans=${ans:-Y}
fi
if [[ $ans =~ ^[Yy]$ ]]; then
if [[ -n "$DOCKER_MAJOR" && "$DOCKER_MAJOR" -lt 27 ]]; then
cat > "$DOCKER_DAEMON_CONFIG" <<EOF
{
"ipv6": true,
"fixed-cidr-v6": "fd00:dead:beef:c0::/80",
"ip6tables": true,
"experimental": true
}
EOF
else
cat > "$DOCKER_DAEMON_CONFIG" <<EOF
{
"ipv6": true,
"fixed-cidr-v6": "fd00:dead:beef:c0::/80"
}
EOF
fi
echo -e "${GREEN}Created $DOCKER_DAEMON_CONFIG with IPv6 settings.${NC}"
echo "Restarting Docker..."
(command -v systemctl &>/dev/null && systemctl restart docker) || service docker restart
echo "Docker restarted."
else
echo "User declined to create daemon.json please manually merge the docker daemon with these configs:"
echo "${MISSING[*]}"
exit 1
fi
fi
}
# 3) Main wrapper for generate_config.sh and update.sh
configure_ipv6() {
# detect manual override if mailcow.conf is present
if [[ -n "$MAILCOW_CONF" && -f "$MAILCOW_CONF" ]] && grep -q '^ENABLE_IPV6=' "$MAILCOW_CONF"; then
MANUAL_SETTING=$(grep '^ENABLE_IPV6=' "$MAILCOW_CONF" | cut -d= -f2)
elif [[ -z "$MAILCOW_CONF" ]] && [[ ! -z "${ENABLE_IPV6:-}" ]]; then
MANUAL_SETTING="$ENABLE_IPV6"
else
MANUAL_SETTING=""
fi
get_ipv6_support
# if user manually set it, check for mismatch
if [[ -n "$MANUAL_SETTING" ]]; then
if [[ "$MANUAL_SETTING" == "false" && "$DETECTED_IPV6" == "true" ]]; then
echo -e "${RED}ERROR: You have ENABLE_IPV6=false but your host and Docker support IPv6.${NC}"
echo -e "${RED}This can create an open relay. Please set ENABLE_IPV6=true in your mailcow.conf and re-run.${NC}"
exit 1
elif [[ "$MANUAL_SETTING" == "true" && "$DETECTED_IPV6" == "false" ]]; then
echo -e "${RED}ERROR: You have ENABLE_IPV6=true but your host does not support IPv6.${NC}"
echo -e "${RED}Please disable or fix your host/Docker IPv6 support, or set ENABLE_IPV6=false.${NC}"
exit 1
else
return
fi
fi
# no manual override: proceed to set or export
if [[ "$DETECTED_IPV6" == "true" ]]; then
docker_daemon_edit
else
echo "Skipping Docker IPv6 configuration because host does not support IPv6."
fi
# now write into mailcow.conf or export
if [[ -n "$MAILCOW_CONF" && -f "$MAILCOW_CONF" ]]; then
LINE="ENABLE_IPV6=$DETECTED_IPV6"
if grep -q '^ENABLE_IPV6=' "$MAILCOW_CONF"; then
sed -i "s/^ENABLE_IPV6=.*/$LINE/" "$MAILCOW_CONF"
else
echo "$LINE" >> "$MAILCOW_CONF"
fi
else
export IPV6_BOOL="$DETECTED_IPV6"
fi
echo "IPv6 configuration complete: ENABLE_IPV6=$DETECTED_IPV6"
}

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env bash
# _modules/scripts/migrate_options.sh
# THIS SCRIPT IS DESIGNED TO BE RUNNING BY MAILCOW SCRIPTS ONLY!
# DO NOT, AGAIN, NOT TRY TO RUN THIS SCRIPT STANDALONE!!!!!!
migrate_config_options() {
sed -i --follow-symlinks '$a\' mailcow.conf
KEYS=(
SOLR_HEAP
SKIP_SOLR
SOLR_PORT
FLATCURVE_EXPERIMENTAL
DISABLE_IPv6
ACME_CONTACT
)
for key in "${KEYS[@]}"; do
if grep -q "${key}" mailcow.conf; then
case "${key}" in
SOLR_HEAP)
echo "Removing ${key} in mailcow.conf"
sed -i '/# Solr heap size in MB\b/d' mailcow.conf
sed -i '/# Solr is a prone to run\b/d' mailcow.conf
sed -i '/SOLR_HEAP\b/d' mailcow.conf
;;
SKIP_SOLR)
echo "Removing ${key} in mailcow.conf"
sed -i '/\bSkip Solr on low-memory\b/d' mailcow.conf
sed -i '/\bSolr is disabled by default\b/d' mailcow.conf
sed -i '/\bDisable Solr or\b/d' mailcow.conf
sed -i '/\bSKIP_SOLR\b/d' mailcow.conf
;;
SOLR_PORT)
echo "Removing ${key} in mailcow.conf"
sed -i '/\bSOLR_PORT\b/d' mailcow.conf
;;
FLATCURVE_EXPERIMENTAL)
echo "Removing ${key} in mailcow.conf"
sed -i '/\bFLATCURVE_EXPERIMENTAL\b/d' mailcow.conf
;;
DISABLE_IPv6)
echo "Migrating ${key} to ENABLE_IPv6 in mailcow.conf"
local old=$(grep '^DISABLE_IPv6=' "mailcow.conf" | cut -d'=' -f2)
local new
if [[ "$old" == "y" ]]; then
new="false"
else
new="true"
fi
sed -i '/^DISABLE_IPv6=/d' "mailcow.conf"
echo "ENABLE_IPV6=$new" >> "mailcow.conf"
;;
ACME_CONTACT)
echo "Deleting obsoleted ${key} in mailcow.conf"
sed -i '/^# Lets Encrypt registration contact information/d' mailcow.conf
sed -i '/^# Optional: Leave empty for none/d' mailcow.conf
sed -i '/^# This value is only used on first order!/d' mailcow.conf
sed -i '/^# Setting it at a later point will require the following steps:/d' mailcow.conf
sed -i '/^# https:\/\/docs.mailcow.email\/troubleshooting\/debug-reset_tls\//d' mailcow.conf
sed -i '/^ACME_CONTACT=.*/d' mailcow.conf
sed -i '/^#ACME_CONTACT=.*/d' mailcow.conf
;;
esac
fi
done
solr_volume=$(docker volume ls -qf name=^${COMPOSE_PROJECT_NAME}_solr-vol-1)
if [[ -n $solr_volume ]]; then
echo -e "\e[34mSolr has been replaced within mailcow since 2025-01.\nThe volume $solr_volume is unused.\e[0m"
sleep 1
if [ ! "$FORCE" ]; then
read -r -p "Remove $solr_volume? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo -e "\e[33mRemoving $solr_volume...\e[0m"
docker volume rm $solr_volume || echo -e "\e[31mFailed to remove. Remove it manually!\e[0m"
echo -e "\e[32mSuccessfully removed $solr_volume!\e[0m"
else
echo -e "Not removing $solr_volume. Run \`docker volume rm $solr_volume\` manually if needed."
fi
else
echo -e "\e[33mForce removing $solr_volume...\e[0m"
docker volume rm $solr_volume || echo -e "\e[31mFailed to remove. Remove it manually!\e[0m"
echo -e "\e[32mSuccessfully removed $solr_volume!\e[0m"
fi
fi
# Delete old fts.conf before forced switch to flatcurve to ensure update is working properly
FTS_CONF_PATH="${SCRIPT_DIR}/data/conf/dovecot/conf.d/fts.conf"
if [[ -f "$FTS_CONF_PATH" ]]; then
if grep -q "Autogenerated by mailcow" "$FTS_CONF_PATH"; then
rm -rf $FTS_CONF_PATH
fi
fi
}

View File

@@ -0,0 +1,299 @@
#!/usr/bin/env bash
# _modules/scripts/new_options.sh
# THIS SCRIPT IS DESIGNED TO BE RUNNING BY MAILCOW SCRIPTS ONLY!
# DO NOT, AGAIN, NOT TRY TO RUN THIS SCRIPT STANDALONE!!!!!!
adapt_new_options() {
CONFIG_ARRAY=(
"AUTODISCOVER_SAN"
"SKIP_LETS_ENCRYPT"
"SKIP_SOGO"
"USE_WATCHDOG"
"WATCHDOG_NOTIFY_EMAIL"
"WATCHDOG_NOTIFY_WEBHOOK"
"WATCHDOG_NOTIFY_WEBHOOK_BODY"
"WATCHDOG_NOTIFY_BAN"
"WATCHDOG_NOTIFY_START"
"WATCHDOG_EXTERNAL_CHECKS"
"WATCHDOG_SUBJECT"
"SKIP_CLAMD"
"SKIP_OLEFY"
"SKIP_IP_CHECK"
"ADDITIONAL_SAN"
"DOVEADM_PORT"
"IPV4_NETWORK"
"IPV6_NETWORK"
"LOG_LINES"
"SNAT_TO_SOURCE"
"SNAT6_TO_SOURCE"
"COMPOSE_PROJECT_NAME"
"DOCKER_COMPOSE_VERSION"
"SQL_PORT"
"API_KEY"
"API_KEY_READ_ONLY"
"API_ALLOW_FROM"
"MAILDIR_GC_TIME"
"MAILDIR_SUB"
"ACL_ANYONE"
"FTS_HEAP"
"FTS_PROCS"
"SKIP_FTS"
"ENABLE_SSL_SNI"
"ALLOW_ADMIN_EMAIL_LOGIN"
"SKIP_HTTP_VERIFICATION"
"SOGO_EXPIRE_SESSION"
"REDIS_PORT"
"REDISPASS"
"DOVECOT_MASTER_USER"
"DOVECOT_MASTER_PASS"
"MAILCOW_PASS_SCHEME"
"ADDITIONAL_SERVER_NAMES"
"WATCHDOG_VERBOSE"
"WEBAUTHN_ONLY_TRUSTED_VENDORS"
"SPAMHAUS_DQS_KEY"
"SKIP_UNBOUND_HEALTHCHECK"
"DISABLE_NETFILTER_ISOLATION_RULE"
"HTTP_REDIRECT"
"ENABLE_IPV6"
)
sed -i --follow-symlinks '$a\' mailcow.conf
for option in ${CONFIG_ARRAY[@]}; do
if grep -q "${option}" mailcow.conf; then
continue
fi
echo "Adding new option \"${option}\" to mailcow.conf"
case "${option}" in
AUTODISCOVER_SAN)
echo '# Obtain certificates for autodiscover.* and autoconfig.* domains.' >> mailcow.conf
echo '# This can be useful to switch off in case you are in a scenario where a reverse proxy already handles those.' >> mailcow.conf
echo '# There are mixed scenarios where ports 80,443 are occupied and you do not want to share certs' >> mailcow.conf
echo '# between services. So acme-mailcow obtains for maildomains and all web-things get handled' >> mailcow.conf
echo '# in the reverse proxy.' >> mailcow.conf
echo 'AUTODISCOVER_SAN=y' >> mailcow.conf
;;
DOCKER_COMPOSE_VERSION)
echo "# Used Docker Compose version" >> mailcow.conf
echo "# Switch here between native (compose plugin) and standalone" >> mailcow.conf
echo "# For more informations take a look at the mailcow docs regarding the configuration options." >> mailcow.conf
echo "# Normally this should be untouched but if you decided to use either of those you can switch it manually here." >> mailcow.conf
echo "# Please be aware that at least one of those variants should be installed on your machine or mailcow will fail." >> mailcow.conf
echo "" >> mailcow.conf
echo "DOCKER_COMPOSE_VERSION=${DOCKER_COMPOSE_VERSION}" >> mailcow.conf
;;
DOVEADM_PORT)
echo "DOVEADM_PORT=127.0.0.1:19991" >> mailcow.conf
;;
LOG_LINES)
echo '# Max log lines per service to keep in Redis logs' >> mailcow.conf
echo "LOG_LINES=9999" >> mailcow.conf
;;
IPV4_NETWORK)
echo '# Internal IPv4 /24 subnet, format n.n.n. (expands to n.n.n.0/24)' >> mailcow.conf
echo "IPV4_NETWORK=172.22.1" >> mailcow.conf
;;
IPV6_NETWORK)
echo '# Internal IPv6 subnet in fc00::/7' >> mailcow.conf
echo "IPV6_NETWORK=fd4d:6169:6c63:6f77::/64" >> mailcow.conf
;;
SQL_PORT)
echo '# Bind SQL to 127.0.0.1 on port 13306' >> mailcow.conf
echo "SQL_PORT=127.0.0.1:13306" >> mailcow.conf
;;
API_KEY)
echo '# Create or override API key for web UI' >> mailcow.conf
echo "#API_KEY=" >> mailcow.conf
;;
API_KEY_READ_ONLY)
echo '# Create or override read-only API key for web UI' >> mailcow.conf
echo "#API_KEY_READ_ONLY=" >> mailcow.conf
;;
API_ALLOW_FROM)
echo '# Must be set for API_KEY to be active' >> mailcow.conf
echo '# IPs only, no networks (networks can be set via UI)' >> mailcow.conf
echo "#API_ALLOW_FROM=" >> mailcow.conf
;;
SNAT_TO_SOURCE)
echo '# Use this IPv4 for outgoing connections (SNAT)' >> mailcow.conf
echo "#SNAT_TO_SOURCE=" >> mailcow.conf
;;
SNAT6_TO_SOURCE)
echo '# Use this IPv6 for outgoing connections (SNAT)' >> mailcow.conf
echo "#SNAT6_TO_SOURCE=" >> mailcow.conf
;;
MAILDIR_GC_TIME)
echo '# Garbage collector cleanup' >> mailcow.conf
echo '# Deleted domains and mailboxes are moved to /var/vmail/_garbage/timestamp_sanitizedstring' >> mailcow.conf
echo '# How long should objects remain in the garbage until they are being deleted? (value in minutes)' >> mailcow.conf
echo '# Check interval is hourly' >> mailcow.conf
echo 'MAILDIR_GC_TIME=1440' >> mailcow.conf
;;
ACL_ANYONE)
echo '# Set this to "allow" to enable the anyone pseudo user. Disabled by default.' >> mailcow.conf
echo '# When enabled, ACL can be created, that apply to "All authenticated users"' >> mailcow.conf
echo '# This should probably only be activated on mail hosts, that are used exclusively by one organisation.' >> mailcow.conf
echo '# Otherwise a user might share data with too many other users.' >> mailcow.conf
echo 'ACL_ANYONE=disallow' >> mailcow.conf
;;
FTS_HEAP)
echo '# Dovecot Indexing (FTS) Process maximum heap size in MB, there is no recommendation, please see Dovecot docs.' >> mailcow.conf
echo '# Flatcurve is used as FTS Engine. It is supposed to be pretty efficient in CPU and RAM consumption.' >> mailcow.conf
echo '# Please always monitor your Resource consumption!' >> mailcow.conf
echo "FTS_HEAP=128" >> mailcow.conf
;;
SKIP_FTS)
echo '# Skip FTS (Fulltext Search) for Dovecot on low-memory, low-threaded systems or if you simply want to disable it.' >> mailcow.conf
echo "# Dovecot inside mailcow use Flatcurve as FTS Backend." >> mailcow.conf
echo "SKIP_FTS=y" >> mailcow.conf
;;
FTS_PROCS)
echo '# Controls how many processes the Dovecot indexing process can spawn at max.' >> mailcow.conf
echo '# Too many indexing processes can use a lot of CPU and Disk I/O' >> mailcow.conf
echo '# Please visit: https://doc.dovecot.org/configuration_manual/service_configuration/#indexer-worker for more informations' >> mailcow.conf
echo "FTS_PROCS=1" >> mailcow.conf
;;
ENABLE_SSL_SNI)
echo '# Create seperate certificates for all domains - y/n' >> mailcow.conf
echo '# this will allow adding more than 100 domains, but some email clients will not be able to connect with alternative hostnames' >> mailcow.conf
echo '# see https://wiki.dovecot.org/SSL/SNIClientSupport' >> mailcow.conf
echo "ENABLE_SSL_SNI=n" >> mailcow.conf
;;
SKIP_SOGO)
echo '# Skip SOGo: Will disable SOGo integration and therefore webmail, DAV protocols and ActiveSync support (experimental, unsupported, not fully implemented) - y/n' >> mailcow.conf
echo "SKIP_SOGO=n" >> mailcow.conf
;;
MAILDIR_SUB)
echo '# MAILDIR_SUB defines a path in a users virtual home to keep the maildir in. Leave empty for updated setups.' >> mailcow.conf
echo "#MAILDIR_SUB=Maildir" >> mailcow.conf
echo "MAILDIR_SUB=" >> mailcow.conf
;;
WATCHDOG_NOTIFY_WEBHOOK)
echo '# Send notifications to a webhook URL that receives a POST request with the content type "application/json".' >> mailcow.conf
echo '# You can use this to send notifications to services like Discord, Slack and others.' >> mailcow.conf
echo '#WATCHDOG_NOTIFY_WEBHOOK=https://discord.com/api/webhooks/XXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' >> mailcow.conf
;;
WATCHDOG_NOTIFY_WEBHOOK_BODY)
echo '# JSON body included in the webhook POST request. Needs to be in single quotes.' >> mailcow.conf
echo '# Following variables are available: SUBJECT, BODY' >> mailcow.conf
WEBHOOK_BODY='{"username": "mailcow Watchdog", "content": "**${SUBJECT}**\n${BODY}"}'
echo "#WATCHDOG_NOTIFY_WEBHOOK_BODY='${WEBHOOK_BODY}'" >> mailcow.conf
;;
WATCHDOG_NOTIFY_BAN)
echo '# Notify about banned IP. Includes whois lookup.' >> mailcow.conf
echo "WATCHDOG_NOTIFY_BAN=y" >> mailcow.conf
;;
WATCHDOG_NOTIFY_START)
echo '# Send a notification when the watchdog is started.' >> mailcow.conf
echo "WATCHDOG_NOTIFY_START=y" >> mailcow.conf
;;
WATCHDOG_SUBJECT)
echo '# Subject for watchdog mails. Defaults to "Watchdog ALERT" followed by the error message.' >> mailcow.conf
echo "#WATCHDOG_SUBJECT=" >> mailcow.conf
;;
WATCHDOG_EXTERNAL_CHECKS)
echo '# Checks if mailcow is an open relay. Requires a SAL. More checks will follow.' >> mailcow.conf
echo '# No data is collected. Opt-in and anonymous.' >> mailcow.conf
echo '# Will only work with unmodified mailcow setups.' >> mailcow.conf
echo "WATCHDOG_EXTERNAL_CHECKS=n" >> mailcow.conf
;;
SOGO_EXPIRE_SESSION)
echo '# SOGo session timeout in minutes' >> mailcow.conf
echo "SOGO_EXPIRE_SESSION=480" >> mailcow.conf
;;
REDIS_PORT)
echo "REDIS_PORT=127.0.0.1:7654" >> mailcow.conf
;;
DOVECOT_MASTER_USER)
echo '# DOVECOT_MASTER_USER and _PASS must _both_ be provided. No special chars.' >> mailcow.conf
echo '# Empty by default to auto-generate master user and password on start.' >> mailcow.conf
echo '# User expands to DOVECOT_MASTER_USER@mailcow.local' >> mailcow.conf
echo '# LEAVE EMPTY IF UNSURE' >> mailcow.conf
echo "DOVECOT_MASTER_USER=" >> mailcow.conf
;;
DOVECOT_MASTER_PASS)
echo '# LEAVE EMPTY IF UNSURE' >> mailcow.conf
echo "DOVECOT_MASTER_PASS=" >> mailcow.conf
;;
MAILCOW_PASS_SCHEME)
echo '# Password hash algorithm' >> mailcow.conf
echo '# Only certain password hash algorithm are supported. For a fully list of supported schemes,' >> mailcow.conf
echo '# see https://docs.mailcow.email/models/model-passwd/' >> mailcow.conf
echo "MAILCOW_PASS_SCHEME=BLF-CRYPT" >> mailcow.conf
;;
ADDITIONAL_SERVER_NAMES)
echo '# Additional server names for mailcow UI' >> mailcow.conf
echo '#' >> mailcow.conf
echo '# Specify alternative addresses for the mailcow UI to respond to' >> mailcow.conf
echo '# This is useful when you set mail.* as ADDITIONAL_SAN and want to make sure mail.maildomain.com will always point to the mailcow UI.' >> mailcow.conf
echo '# If the server name does not match a known site, Nginx decides by best-guess and may redirect users to the wrong web root.' >> mailcow.conf
echo '# You can understand this as server_name directive in Nginx.' >> mailcow.conf
echo '# Comma separated list without spaces! Example: ADDITIONAL_SERVER_NAMES=a.b.c,d.e.f' >> mailcow.conf
echo 'ADDITIONAL_SERVER_NAMES=' >> mailcow.conf
;;
WEBAUTHN_ONLY_TRUSTED_VENDORS)
echo "# WebAuthn device manufacturer verification" >> mailcow.conf
echo '# After setting WEBAUTHN_ONLY_TRUSTED_VENDORS=y only devices from trusted manufacturers are allowed' >> mailcow.conf
echo '# root certificates can be placed for validation under mailcow-dockerized/data/web/inc/lib/WebAuthn/rootCertificates' >> mailcow.conf
echo 'WEBAUTHN_ONLY_TRUSTED_VENDORS=n' >> mailcow.conf
;;
SPAMHAUS_DQS_KEY)
echo "# Spamhaus Data Query Service Key" >> mailcow.conf
echo '# Optional: Leave empty for none' >> mailcow.conf
echo '# Enter your key here if you are using a blocked ASN (OVH, AWS, Cloudflare e.g) for the unregistered Spamhaus Blocklist.' >> mailcow.conf
echo '# If empty, it will completely disable Spamhaus blocklists if it detects that you are running on a server using a blocked AS.' >> mailcow.conf
echo '# Otherwise it will work as usual.' >> mailcow.conf
echo 'SPAMHAUS_DQS_KEY=' >> mailcow.conf
;;
WATCHDOG_VERBOSE)
echo '# Enable watchdog verbose logging' >> mailcow.conf
echo 'WATCHDOG_VERBOSE=n' >> mailcow.conf
;;
SKIP_UNBOUND_HEALTHCHECK)
echo '# Skip Unbound (DNS Resolver) Healthchecks (NOT Recommended!) - y/n' >> mailcow.conf
echo 'SKIP_UNBOUND_HEALTHCHECK=n' >> mailcow.conf
;;
DISABLE_NETFILTER_ISOLATION_RULE)
echo '# Prevent netfilter from setting an iptables/nftables rule to isolate the mailcow docker network - y/n' >> mailcow.conf
echo '# CAUTION: Disabling this may expose container ports to other neighbors on the same subnet, even if the ports are bound to localhost' >> mailcow.conf
echo 'DISABLE_NETFILTER_ISOLATION_RULE=n' >> mailcow.conf
;;
HTTP_REDIRECT)
echo '# Redirect HTTP connections to HTTPS - y/n' >> mailcow.conf
echo 'HTTP_REDIRECT=n' >> mailcow.conf
;;
ENABLE_IPV6)
echo '# IPv6 Controller Section' >> mailcow.conf
echo '# This variable controls the usage of IPv6 within mailcow.' >> mailcow.conf
echo '# Can either be true or false | Defaults to true' >> mailcow.conf
echo '# WARNING: MAKE SURE TO PROPERLY CONFIGURE IPv6 ON YOUR HOST FIRST BEFORE ENABLING THIS AS FAULTY CONFIGURATIONS CAN LEAD TO OPEN RELAYS!' >> mailcow.conf
echo '# A COMPLETE DOCKER STACK REBUILD (compose down && compose up -d) IS NEEDED TO APPLY THIS.' >> mailcow.conf
echo ENABLE_IPV6=${IPV6_BOOL} >> mailcow.conf
;;
SKIP_CLAMD)
echo '# Skip ClamAV (clamd-mailcow) anti-virus (Rspamd will auto-detect a missing ClamAV container) - y/n' >> mailcow.conf
echo 'SKIP_CLAMD=n' >> mailcow.conf
;;
SKIP_OLEFY)
echo '# Skip Olefy (olefy-mailcow) anti-virus for Office documents (Rspamd will auto-detect a missing Olefy container) - y/n' >> mailcow.conf
echo 'SKIP_OLEFY=n' >> mailcow.conf
;;
REDISPASS)
echo "REDISPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2>/dev/null | head -c 28)" >> mailcow.conf
;;
*)
echo "${option}=" >> mailcow.conf
;;
esac
done
}

View File

@@ -206,7 +206,7 @@ while true; do
if [[ ${AUTODISCOVER_SAN} == "y" ]]; then
# Fetch certs for autoconfig and autodiscover subdomains
ADDITIONAL_WC_ARR+=('autodiscover' 'autoconfig')
ADDITIONAL_WC_ARR+=('autodiscover' 'autoconfig' 'mta-sts')
fi
if [[ ${SKIP_IP_CHECK} != "y" ]]; then

View File

@@ -8,7 +8,7 @@ fi
# Cleaning up garbage
echo "Cleaning up tmp files..."
rm -rf /var/lib/clamav/clamav-*.tmp
rm -rf /var/lib/clamav/tmp.*
# Prepare whitelist

View File

@@ -3,7 +3,7 @@ FROM alpine:3.21
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$
ARG GOSU_VERSION=1.16
ARG GOSU_VERSION=1.17
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8

View File

@@ -132,8 +132,8 @@ while ($row = $sth->fetchrow_arrayref()) {
"--tmpdir", "/tmp",
"--nofoldersizes",
"--addheader",
($timeout1 gt "0" ? () : ('--timeout1', $timeout1)),
($timeout2 gt "0" ? () : ('--timeout2', $timeout2)),
($timeout1 le "0" ? () : ('--timeout1', $timeout1)),
($timeout2 le "0" ? () : ('--timeout2', $timeout2)),
($exclude eq "" ? () : ("--exclude", $exclude)),
($subfolder2 eq "" ? () : ('--subfolder2', $subfolder2)),
($maxage eq "0" ? () : ('--maxage', $maxage)),

View File

@@ -76,7 +76,7 @@ try:
def notify_rcpt(rcpt, msg_count, quarantine_acl, category):
if category == "add_header": category = "add header"
meta_query = query_mysql('SELECT SHA2(CONCAT(id, qid), 256) AS qhash, id, subject, score, sender, created, action FROM quarantine WHERE notified = 0 AND rcpt = "%s" AND score < %f AND (action = "%s" OR "all" = "%s")' % (rcpt, max_score, category, category))
meta_query = query_mysql('SELECT `qhash`, id, subject, score, sender, created, action FROM quarantine WHERE notified = 0 AND rcpt = "%s" AND score < %f AND (action = "%s" OR "all" = "%s")' % (rcpt, max_score, category, category))
print("%s: %d of %d messages qualify for notification" % (rcpt, len(meta_query), msg_count))
if len(meta_query) == 0:
return

View File

@@ -1,5 +1,7 @@
#!/usr/bin/env python3
DEBUG = False
import re
import os
import sys
@@ -20,10 +22,13 @@ from modules.Logger import Logger
from modules.IPTables import IPTables
from modules.NFTables import NFTables
def logdebug(msg):
if DEBUG:
logger.logInfo("DEBUG: %s" % msg)
# globals
# Globals
WHITELIST = []
BLACKLIST= []
BLACKLIST = []
bans = {}
quit_now = False
exit_code = 0
@@ -33,12 +38,10 @@ r = None
pubsub = None
clear_before_quit = False
def refreshF2boptions():
global f2boptions
global quit_now
global exit_code
f2boptions = {}
if not r.get('F2B_OPTIONS'):
@@ -52,8 +55,9 @@ def refreshF2boptions():
else:
try:
f2boptions = json.loads(r.get('F2B_OPTIONS'))
except ValueError:
logger.logCrit('Error loading F2B options: F2B_OPTIONS is not json')
except ValueError as e:
logger.logCrit(
'Error loading F2B options: F2B_OPTIONS is not json. Exception: %s' % e)
quit_now = True
exit_code = 2
@@ -61,15 +65,15 @@ def refreshF2boptions():
r.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False))
def verifyF2boptions(f2boptions):
verifyF2boption(f2boptions,'ban_time', 1800)
verifyF2boption(f2boptions,'max_ban_time', 10000)
verifyF2boption(f2boptions,'ban_time_increment', True)
verifyF2boption(f2boptions,'max_attempts', 10)
verifyF2boption(f2boptions,'retry_window', 600)
verifyF2boption(f2boptions,'netban_ipv4', 32)
verifyF2boption(f2boptions,'netban_ipv6', 128)
verifyF2boption(f2boptions,'banlist_id', str(uuid.uuid4()))
verifyF2boption(f2boptions,'manage_external', 0)
verifyF2boption(f2boptions, 'ban_time', 1800)
verifyF2boption(f2boptions, 'max_ban_time', 10000)
verifyF2boption(f2boptions, 'ban_time_increment', True)
verifyF2boption(f2boptions, 'max_attempts', 10)
verifyF2boption(f2boptions, 'retry_window', 600)
verifyF2boption(f2boptions, 'netban_ipv4', 32)
verifyF2boption(f2boptions, 'netban_ipv6', 128)
verifyF2boption(f2boptions, 'banlist_id', str(uuid.uuid4()))
verifyF2boption(f2boptions, 'manage_external', 0)
def verifyF2boption(f2boptions, f2boption, f2bdefault):
f2boptions[f2boption] = f2boptions[f2boption] if f2boption in f2boptions and f2boptions[f2boption] is not None else f2bdefault
@@ -111,7 +115,7 @@ def get_ip(address):
def ban(address):
global f2boptions
global lock
logdebug("ban() called with address=%s" % address)
refreshF2boptions()
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
RETRY_WINDOW = int(f2boptions['retry_window'])
@@ -119,31 +123,43 @@ def ban(address):
NETBAN_IPV6 = '/' + str(f2boptions['netban_ipv6'])
ip = get_ip(address)
if not ip: return
if not ip:
logdebug("No valid IP -- skipping ban()")
return
address = str(ip)
self_network = ipaddress.ip_network(address)
with lock:
temp_whitelist = set(WHITELIST)
if temp_whitelist:
for wl_key in temp_whitelist:
wl_net = ipaddress.ip_network(wl_key, False)
if wl_net.overlaps(self_network):
logger.logInfo('Address %s is whitelisted by rule %s' % (self_network, wl_net))
return
logdebug("Checking if %s overlaps with any WHITELIST entries" % self_network)
if temp_whitelist:
for wl_key in temp_whitelist:
wl_net = ipaddress.ip_network(wl_key, False)
logdebug("Checking overlap between %s and %s" % (self_network, wl_net))
if wl_net.overlaps(self_network):
logger.logInfo(
'Address %s is allowlisted by rule %s' % (self_network, wl_net))
return
net = ipaddress.ip_network((address + (NETBAN_IPV4 if type(ip) is ipaddress.IPv4Address else NETBAN_IPV6)), strict=False)
net = ipaddress.ip_network(
(address + (NETBAN_IPV4 if type(ip) is ipaddress.IPv4Address else NETBAN_IPV6)), strict=False)
net = str(net)
logdebug("Ban net: %s" % net)
if not net in bans:
bans[net] = {'attempts': 0, 'last_attempt': 0, 'ban_counter': 0}
logdebug("Initing new ban counter for %s" % net)
current_attempt = time.time()
logdebug("Current attempt ts=%s, previous: %s, retry_window: %s" %
(current_attempt, bans[net]['last_attempt'], RETRY_WINDOW))
if current_attempt - bans[net]['last_attempt'] > RETRY_WINDOW:
bans[net]['attempts'] = 0
logdebug("Ban counter for %s reset as window expired" % net)
bans[net]['attempts'] += 1
bans[net]['last_attempt'] = current_attempt
logdebug("%s attempts now %d" % (net, bans[net]['attempts']))
if bans[net]['attempts'] >= MAX_ATTEMPTS:
cur_time = int(round(time.time()))
@@ -151,34 +167,41 @@ def ban(address):
logger.logCrit('Banning %s for %d minutes' % (net, NET_BAN_TIME / 60 ))
if type(ip) is ipaddress.IPv4Address and int(f2boptions['manage_external']) != 1:
with lock:
logdebug("Calling tables.banIPv4(%s)" % net)
tables.banIPv4(net)
elif int(f2boptions['manage_external']) != 1:
with lock:
logdebug("Calling tables.banIPv6(%s)" % net)
tables.banIPv6(net)
logdebug("Updating F2B_ACTIVE_BANS[%s]=%d" %
(net, cur_time + NET_BAN_TIME))
r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + NET_BAN_TIME)
else:
logger.logWarn('%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net))
logger.logWarn('%d more attempts in the next %d seconds until %s is banned' % (
MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net))
def unban(net):
global lock
logdebug("Calling unban() with net=%s" % net)
if not net in bans:
logger.logInfo('%s is not banned, skipping unban and deleting from queue (if any)' % net)
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
return
logger.logInfo(
'%s is not banned, skipping unban and deleting from queue (if any)' % net)
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
return
logger.logInfo('Unbanning %s' % net)
if type(ipaddress.ip_network(net)) is ipaddress.IPv4Network:
with lock:
logdebug("Calling tables.unbanIPv4(%s)" % net)
tables.unbanIPv4(net)
else:
with lock:
logdebug("Calling tables.unbanIPv6(%s)" % net)
tables.unbanIPv6(net)
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
if net in bans:
logdebug("Unban for %s, setting attempts=0, ban_counter+=1" % net)
bans[net]['attempts'] = 0
bans[net]['ban_counter'] += 1
@@ -204,17 +227,19 @@ def permBan(net, unban=False):
if is_unbanned:
r.hdel('F2B_PERM_BANS', '%s' % net)
logger.logCrit('Removed host/network %s from blacklist' % net)
logger.logCrit('Removed host/network %s from denylist' % net)
elif is_banned:
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
logger.logCrit('Added host/network %s to blacklist' % net)
logger.logCrit('Added host/network %s to denylist' % net)
def clear():
global lock
logger.logInfo('Clearing all bans')
for net in bans.copy():
logdebug("Unbanning net: %s" % net)
unban(net)
with lock:
logdebug("Clearing IPv4/IPv6 table")
tables.clearIPv4Table()
tables.clearIPv6Table()
try:
@@ -275,21 +300,35 @@ def snat6(snat_target):
def autopurge():
global f2boptions
logdebug("autopurge thread started")
while not quit_now:
logdebug("autopurge tick")
time.sleep(10)
refreshF2boptions()
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
QUEUE_UNBAN = r.hgetall('F2B_QUEUE_UNBAN')
logdebug("QUEUE_UNBAN: %s" % QUEUE_UNBAN)
if QUEUE_UNBAN:
for net in QUEUE_UNBAN:
logdebug("Autopurge: unbanning queued net: %s" % net)
unban(str(net))
for net in bans.copy():
if bans[net]['attempts'] >= MAX_ATTEMPTS:
NET_BAN_TIME = calcNetBanTime(bans[net]['ban_counter'])
TIME_SINCE_LAST_ATTEMPT = time.time() - bans[net]['last_attempt']
if TIME_SINCE_LAST_ATTEMPT > NET_BAN_TIME:
unban(net)
# Only check expiry for actively banned IPs:
active_bans = r.hgetall('F2B_ACTIVE_BANS')
now = time.time()
for net_str, expire_str in active_bans.items():
logdebug("Checking ban expiry for (actively banned): %s" % net_str)
# Defensive: always process if timer missing or expired
try:
expire = float(expire_str)
except Exception:
logdebug("Invalid expire time for %s; unbanning" % net_str)
unban(net_str)
continue
time_left = expire - now
logdebug("Time left for %s: %.1f seconds" % (net_str, time_left))
if time_left <= 0:
logdebug("Ban expired for %s" % net_str)
unban(net_str)
def mailcowChainOrder():
global lock
@@ -359,7 +398,7 @@ def whitelistUpdate():
with lock:
if Counter(new_whitelist) != Counter(WHITELIST):
WHITELIST = new_whitelist
logger.logInfo('Whitelist was changed, it has %s entries' % len(WHITELIST))
logger.logInfo('Allowlist was changed, it has %s entries' % len(WHITELIST))
time.sleep(60.0 - ((time.time() - start_time) % 60.0))
def blacklistUpdate():
@@ -375,7 +414,7 @@ def blacklistUpdate():
addban = set(new_blacklist).difference(BLACKLIST)
delban = set(BLACKLIST).difference(new_blacklist)
BLACKLIST = new_blacklist
logger.logInfo('Blacklist was changed, it has %s entries' % len(BLACKLIST))
logger.logInfo('Denylist was changed, it has %s entries' % len(BLACKLIST))
if addban:
for net in addban:
permBan(net=net)
@@ -386,25 +425,25 @@ def blacklistUpdate():
def sigterm_quit(signum, frame):
global clear_before_quit
logdebug("SIGTERM received, setting clear_before_quit to True and exiting")
clear_before_quit = True
sys.exit(exit_code)
def berfore_quit():
def before_quit():
logdebug("before_quit called, clear_before_quit=%s" % clear_before_quit)
if clear_before_quit:
clear()
if pubsub is not None:
pubsub.unsubscribe()
if __name__ == '__main__':
atexit.register(berfore_quit)
logger = Logger()
logdebug("Sys.argv: %s" % sys.argv)
atexit.register(before_quit)
signal.signal(signal.SIGTERM, sigterm_quit)
# init Logger
logger = Logger()
# init backend
backend = sys.argv[1]
logdebug("Backend: %s" % backend)
if backend == "nftables":
logger.logInfo('Using NFTables backend')
tables = NFTables(chain_name, logger)
@@ -412,16 +451,12 @@ if __name__ == '__main__':
logger.logInfo('Using IPTables backend')
tables = IPTables(chain_name, logger)
# In case a previous session was killed without cleanup
clear()
# Reinit MAILCOW chain
# Is called before threads start, no locking
logger.logInfo("Initializing mailcow netfilter chain")
tables.initChainIPv4()
tables.initChainIPv6()
if os.getenv("DISABLE_NETFILTER_ISOLATION_RULE").lower() in ("y", "yes"):
if os.getenv("DISABLE_NETFILTER_ISOLATION_RULE", "").lower() in ("y", "yes"):
logger.logInfo(f"Skipping {chain_name} isolation")
else:
logger.logInfo(f"Setting {chain_name} isolation")
@@ -432,23 +467,28 @@ if __name__ == '__main__':
try:
redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '')
redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '')
logdebug(
"Connecting redis (SLAVEOF_IP:%s, PORT:%s)" % (redis_slaveof_ip, redis_slaveof_port))
if "".__eq__(redis_slaveof_ip):
r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
r = redis.StrictRedis(
host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
else:
r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0, password=os.environ['REDISPASS'])
r = redis.StrictRedis(
host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0, password=os.environ['REDISPASS'])
r.ping()
pubsub = r.pubsub()
except Exception as ex:
print('%s - trying again in 3 seconds' % (ex))
logdebug(
'Redis connection failed: %s - trying again in 3 seconds' % (ex))
time.sleep(3)
else:
break
logger.set_redis(r)
logdebug("Redis connection established, setting up F2B keys")
# rename fail2ban to netfilter
if r.exists('F2B_LOG'):
logdebug("Renaming F2B_LOG to NETFILTER_LOG")
r.rename('F2B_LOG', 'NETFILTER_LOG')
# clear bans in redis
r.delete('F2B_ACTIVE_BANS')
r.delete('F2B_PERM_BANS')
@@ -463,7 +503,7 @@ if __name__ == '__main__':
snat_ip = os.getenv('SNAT_TO_SOURCE')
snat_ipo = ipaddress.ip_address(snat_ip)
if type(snat_ipo) is ipaddress.IPv4Address:
snat4_thread = Thread(target=snat4,args=(snat_ip,))
snat4_thread = Thread(target=snat4, args=(snat_ip,))
snat4_thread.daemon = True
snat4_thread.start()
except ValueError:
@@ -499,4 +539,5 @@ if __name__ == '__main__':
while not quit_now:
time.sleep(0.5)
sys.exit(exit_code)
logdebug("Exiting with code %s" % exit_code)
sys.exit(exit_code)

View File

@@ -10,7 +10,7 @@ def includes_conf(env, template_vars):
server_name_config = f"server_name {template_vars['MAILCOW_HOSTNAME']} autodiscover.* autoconfig.* {' '.join(template_vars['ADDITIONAL_SERVER_NAMES'])};"
listen_plain_config = f"listen {template_vars['HTTP_PORT']};"
listen_ssl_config = f"listen {template_vars['HTTPS_PORT']};"
if not template_vars['DISABLE_IPv6']:
if not template_vars['ENABLE_IPV6']:
listen_plain_config += f"\nlisten [::]:{template_vars['HTTP_PORT']};"
listen_ssl_config += f"\nlisten [::]:{template_vars['HTTPS_PORT']} ssl;"
listen_ssl_config += "\nhttp2 on;"
@@ -58,7 +58,7 @@ def prepare_template_vars():
'SOGOHOST': os.getenv("SOGOHOST", ipv4_network + ".248"),
'RSPAMDHOST': os.getenv("RSPAMDHOST", "rspamd-mailcow"),
'PHPFPMHOST': os.getenv("PHPFPMHOST", "php-fpm-mailcow"),
'DISABLE_IPv6': os.getenv("DISABLE_IPv6", "n").lower() in ("y", "yes"),
'ENABLE_IPV6': os.getenv("ENABLE_IPV6", "true").lower() != "false",
'HTTP_REDIRECT': os.getenv("HTTP_REDIRECT", "n").lower() in ("y", "yes"),
}

View File

@@ -3,15 +3,15 @@ FROM php:8.2-fpm-alpine3.21
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
# renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced extractVersion=^v(?<version>.*)$
ARG APCU_PECL_VERSION=5.1.24
ARG APCU_PECL_VERSION=5.1.26
# renovate: datasource=github-tags depName=Imagick/imagick versioning=semver-coerced extractVersion=(?<version>.*)$
ARG IMAGICK_PECL_VERSION=3.8.0
# renovate: datasource=github-tags depName=php/pecl-mail-mailparse versioning=semver-coerced extractVersion=^v(?<version>.*)$
ARG MAILPARSE_PECL_VERSION=3.1.8
# renovate: datasource=github-tags depName=php-memcached-dev/php-memcached versioning=semver-coerced extractVersion=^v(?<version>.*)$
ARG MEMCACHED_PECL_VERSION=3.2.0
ARG MEMCACHED_PECL_VERSION=3.3.0
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced extractVersion=(?<version>.*)$
ARG REDIS_PECL_VERSION=6.1.0
ARG REDIS_PECL_VERSION=6.2.0
# renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced extractVersion=(?<version>.*)$
ARG COMPOSER_VERSION=2.8.6

View File

@@ -0,0 +1,50 @@
FROM golang:1.25-bookworm AS builder
WORKDIR /src
ENV CGO_ENABLED=0 \
GO111MODULE=on \
NOOPT=1 \
VERSION=1.8.14
RUN git clone --branch v${VERSION} https://github.com/Zuplu/postfix-tlspol && \
cd /src/postfix-tlspol && \
scripts/build.sh build-only
FROM debian:bookworm-slim
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ENV LC_ALL=C
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
dirmngr \
dnsutils \
iputils-ping \
sudo \
supervisor \
redis-tools \
syslog-ng \
syslog-ng-core \
syslog-ng-mod-redis \
tzdata \
&& rm -rf /var/lib/apt/lists/* \
&& touch /etc/default/locale
COPY supervisord.conf /etc/supervisor/supervisord.conf
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
COPY postfix-tlspol.sh /opt/postfix-tlspol.sh
COPY stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
COPY docker-entrypoint.sh /docker-entrypoint.sh
COPY --from=builder /src/postfix-tlspol/build/postfix-tlspol /usr/local/bin/postfix-tlspol
RUN chmod +x /opt/postfix-tlspol.sh \
/usr/local/sbin/stop-supervisor.sh \
/docker-entrypoint.sh
RUN rm -rf /tmp/* /var/tmp/*
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"]

View File

@@ -0,0 +1,7 @@
#!/bin/bash
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
fi
exec "$@"

View File

@@ -0,0 +1,52 @@
#!/bin/bash
LOGLVL=info
if [ ${DEV_MODE} != "n" ]; then
echo -e "\e[31mEnabling debug mode\e[0m"
set -x
LOGLVL=debug
fi
[[ ! -d /etc/postfix-tlspol ]] && mkdir -p /etc/postfix-tlspol
[[ ! -d /var/lib/postfix-tlspol ]] && mkdir -p /var/lib/postfix-tlspol
until dig +short mailcow.email > /dev/null; do
echo "Waiting for DNS..."
sleep 1
done
# Do not attempt to write to slave
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
else
export REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
fi
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
echo "Waiting for Redis..."
sleep 2
done
echo "Waiting for Postfix..."
until ping postfix -c1 > /dev/null; do
sleep 1
done
echo "Postfix OK"
cat <<EOF > /etc/postfix-tlspol/config.yaml
server:
address: 0.0.0.0:8642
log-level: ${LOGLVL}
prefetch: true
cache-file: /var/lib/postfix-tlspol/cache.db
dns:
# must support DNSSEC
address: 127.0.0.11:53
EOF
/usr/local/bin/postfix-tlspol -config /etc/postfix-tlspol/config.yaml

View File

@@ -0,0 +1,8 @@
#!/bin/bash
printf "READY\n";
while read line; do
echo "Processing Event: $line" >&2;
kill -3 $(cat "/var/run/supervisord.pid")
done < /dev/stdin

View File

@@ -0,0 +1,25 @@
[supervisord]
pidfile=/var/run/supervisord.pid
nodaemon=true
user=root
[program:syslog-ng]
command=/usr/sbin/syslog-ng --foreground --no-caps
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autostart=true
[program:postfix-tlspol]
startsecs=10
autorestart=true
command=/opt/postfix-tlspol.sh
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[eventlistener:processes]
command=/usr/local/sbin/stop-supervisor.sh
events=PROCESS_STATE_STOPPED, PROCESS_STATE_EXITED, PROCESS_STATE_FATAL

View File

@@ -0,0 +1,45 @@
@version: 3.38
@include "scl.conf"
options {
chain_hostnames(off);
flush_lines(0);
use_dns(no);
dns_cache(no);
use_fqdn(no);
owner("root"); group("adm"); perm(0640);
stats_freq(0);
bad_hostname("^gconfd$");
};
source s_src {
unix-stream("/dev/log");
internal();
};
destination d_stdout { pipe("/dev/stdout"); };
destination d_redis_ui_log {
redis(
host("`REDIS_SLAVEOF_IP`")
persist-name("redis1")
port(`REDIS_SLAVEOF_PORT`)
auth("`REDISPASS`")
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
filter f_mail { facility(mail); };
# start
# overriding warnings are still displayed when the entrypoint runs its initial check
# warnings logged by postfix-mailcow to syslog are hidden to reduce repeating msgs
# Some other warnings are ignored
filter f_ignore {
not match("overriding earlier entry" value("MESSAGE"));
not match("TLS SNI from checks.mailcow.email" value("MESSAGE"));
not match("no SASL support" value("MESSAGE"));
not facility (local0, local1, local2, local3, local4, local5, local6, local7);
};
# end
log {
source(s_src);
filter(f_ignore);
destination(d_stdout);
filter(f_mail);
destination(d_redis_ui_log);
};

View File

@@ -0,0 +1,45 @@
@version: 3.38
@include "scl.conf"
options {
chain_hostnames(off);
flush_lines(0);
use_dns(no);
dns_cache(no);
use_fqdn(no);
owner("root"); group("adm"); perm(0640);
stats_freq(0);
bad_hostname("^gconfd$");
};
source s_src {
unix-stream("/dev/log");
internal();
};
destination d_stdout { pipe("/dev/stdout"); };
destination d_redis_ui_log {
redis(
host("redis-mailcow")
persist-name("redis1")
port(6379)
auth("`REDISPASS`")
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
);
};
filter f_mail { facility(mail); };
# start
# overriding warnings are still displayed when the entrypoint runs its initial check
# warnings logged by postfix-mailcow to syslog are hidden to reduce repeating msgs
# Some other warnings are ignored
filter f_ignore {
not match("overriding earlier entry" value("MESSAGE"));
not match("TLS SNI from checks.mailcow.email" value("MESSAGE"));
not match("no SASL support" value("MESSAGE"));
not facility (local0, local1, local2, local3, local4, local5, local6, local7);
};
# end
log {
source(s_src);
filter(f_ignore);
destination(d_stdout);
filter(f_mail);
destination(d_redis_ui_log);
};

View File

@@ -1,9 +1,9 @@
FROM debian:bookworm-slim
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ENV LC_ALL C
ENV LC_ALL=C
RUN dpkg-divert --local --rename --add /sbin/initctl \
&& ln -sf /bin/true /sbin/initctl \

View File

@@ -524,4 +524,4 @@ if [[ $? != 0 ]]; then
else
postfix -c /opt/postfix/conf start
sleep 126144000
fi
fi

View File

@@ -2,7 +2,7 @@ FROM debian:bookworm-slim
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ARG RSPAMD_VER=rspamd_3.11.1-1~ab0b44951
ARG RSPAMD_VER=rspamd_3.12.1-1~6dbfca2fa
ARG CODENAME=bookworm
ENV LC_ALL=C

View File

@@ -86,7 +86,8 @@ if [[ "${SKIP_OLEFY}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
rm /etc/rspamd/local.d/external_services.conf
fi
else
cat <<EOF > /etc/rspamd/local.d/external_services.conf
if [[ ! -f /etc/rspamd/local.d/external_services.conf ]]; then
cat <<EOF > /etc/rspamd/local.d/external_services.conf
oletools {
# default olefy settings
servers = "olefy:10055";
@@ -100,6 +101,7 @@ oletools {
retransmits = 1;
}
EOF
fi
fi
# Provide additional lua modules

View File

@@ -16,7 +16,6 @@ RUN apk add --update \
fcgi \
openssl \
nagios-plugins-mysql \
nagios-plugins-dns \
nagios-plugins-disk \
bind-tools \
redis \
@@ -32,9 +31,11 @@ RUN apk add --update \
tzdata \
whois \
&& curl https://raw.githubusercontent.com/mludvig/smtp-cli/v3.10/smtp-cli -o /smtp-cli \
&& chmod +x smtp-cli
&& chmod +x smtp-cli \
&& mkdir /usr/lib/mailcow
COPY watchdog.sh /watchdog.sh
COPY check_mysql_slavestatus.sh /usr/lib/nagios/plugins/check_mysql_slavestatus.sh
COPY check_dns.sh /usr/lib/mailcow/check_dns.sh
CMD ["/watchdog.sh"]

View File

@@ -0,0 +1,39 @@
#!/bin/sh
while getopts "H:s:" opt; do
case "$opt" in
H) HOST="$OPTARG" ;;
s) SERVER="$OPTARG" ;;
*) echo "Usage: $0 -H host -s server"; exit 3 ;;
esac
done
if [ -z "$SERVER" ]; then
echo "No DNS Server provided"
exit 3
fi
if [ -z "$HOST" ]; then
echo "No host to test provided"
exit 3
fi
# run dig and measure the time it takes to run
START_TIME=$(date +%s%3N)
dig_output=$(dig +short +timeout=2 +tries=1 "$HOST" @"$SERVER" 2>/dev/null)
dig_rc=$?
dig_output_ips=$(echo "$dig_output" | grep -E '^[0-9.]+$' | sort | paste -sd ',' -)
END_TIME=$(date +%s%3N)
ELAPSED_TIME=$((END_TIME - START_TIME))
# validate and perform nagios like output and exit codes
if [ $dig_rc -ne 0 ] || [ -z "$dig_output" ]; then
echo "Domain $HOST was not found by the server"
exit 2
elif [ $dig_rc -eq 0 ]; then
echo "DNS OK: $ELAPSED_TIME ms response time. $HOST returns $dig_output_ips"
exit 0
else
echo "Unknown error"
exit 3
fi

View File

@@ -1,5 +1,10 @@
#!/bin/bash
if [ "${DEV_MODE}" != "n" ]; then
echo -e "\e[31mEnabled Debug Mode\e[0m"
set -x
fi
trap "exit" INT TERM
trap "kill 0" EXIT
@@ -297,7 +302,7 @@ unbound_checks() {
touch /tmp/unbound-mailcow; echo "$(tail -50 /tmp/unbound-mailcow)" > /tmp/unbound-mailcow
host_ip=$(get_container_ip unbound-mailcow)
err_c_cur=${err_count}
/usr/lib/nagios/plugins/check_dns -s ${host_ip} -H stackoverflow.com 2>> /tmp/unbound-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
/usr/lib/mailcow/check_dns.sh -s ${host_ip} -H stackoverflow.com 2>> /tmp/unbound-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
DNSSEC=$(dig com +dnssec | egrep 'flags:.+ad')
if [[ -z ${DNSSEC} ]]; then
echo "DNSSEC failure" 2>> /tmp/unbound-mailcow 1>&2
@@ -445,6 +450,31 @@ postfix_checks() {
return 1
}
postfix-tlspol_checks() {
err_count=0
diff_c=0
THRESHOLD=${POSTFIX_TLSPOL_THRESHOLD}
# Reduce error count by 2 after restarting an unhealthy container
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
while [ ${err_count} -lt ${THRESHOLD} ]; do
touch /tmp/postfix-tlspol-mailcow; echo "$(tail -50 /tmp/postfix-tlspol-mailcow)" > /tmp/postfix-tlspol-mailcow
host_ip=$(get_container_ip postfix-tlspol-mailcow)
err_c_cur=${err_count}
/usr/lib/nagios/plugins/check_tcp -4 -H ${host_ip} -p 8642 2>> /tmp/postfix-tlspol-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
progress "Postfix TLS Policy companion" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
if [[ $? == 10 ]]; then
diff_c=0
sleep 1
else
diff_c=0
sleep $(( ( RANDOM % 60 ) + 20 ))
fi
done
return 1
}
clamd_checks() {
err_count=0
diff_c=0
@@ -922,6 +952,18 @@ PID=$!
echo "Spawned mailq_checks with PID ${PID}"
BACKGROUND_TASKS+=(${PID})
(
while true; do
if ! postfix-tlspol_checks; then
log_msg "Postfix TLS Policy hit error limit"
echo postfix-tlspol-mailcow > /tmp/com_pipe
fi
done
) &
PID=$!
echo "Spawned postfix-tlspol_checks with PID ${PID}"
BACKGROUND_TASKS+=(${PID})
(
while true; do
if ! dovecot_checks; then

View File

@@ -86,7 +86,7 @@ if ($result === false){
'remote_addr' => $post['real_rip']
));
if ($result) {
error_log('MAILCOWAUTH: App auth for user ' . $post['username']);
error_log('MAILCOWAUTH: App auth for user ' . $post['username'] . " with service " . $post['service'] . " from IP " . $post['real_rip']);
set_sasl_log($post['username'], $post['real_rip'], $post['service']);
}
}
@@ -94,9 +94,9 @@ if ($result === false){
// Init Identity Provider
$iam_provider = identity_provider('init');
$iam_settings = identity_provider('get');
$result = user_login($post['username'], $post['password'], array('is_internal' => true));
$result = user_login($post['username'], $post['password'], array('is_internal' => true, 'service' => $post['service']));
if ($result) {
error_log('MAILCOWAUTH: User auth for user ' . $post['username']);
error_log('MAILCOWAUTH: User auth for user ' . $post['username'] . " with service " . $post['service'] . " from IP " . $post['real_rip']);
set_sasl_log($post['username'], $post['real_rip'], $post['service']);
}
}
@@ -105,7 +105,7 @@ if ($result) {
http_response_code(200); // OK
$return['success'] = true;
} else {
error_log("MAILCOWAUTH: Login failed for user " . $post['username']);
error_log("MAILCOWAUTH: Login failed for user " . $post['username'] . " with service " . $post['service'] . " from IP " . $post['real_rip']);
http_response_code(401); // Unauthorized
}

View File

@@ -48,13 +48,21 @@ http {
listen {{ HTTP_PORT }} default_server;
listen [::]:{{ HTTP_PORT }} default_server;
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.* {{ ADDITIONAL_SERVER_NAMES | join(' ') }};
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.* mta-sts.* {{ ADDITIONAL_SERVER_NAMES | join(' ') }};
if ( $request_uri ~* "%0A|%0D" ) { return 403; }
location ^~ /.well-known/acme-challenge/ {
allow all;
default_type "text/plain";
}
location ^~ /.well-known/mta-sts.txt {
allow all;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/mta-sts.php;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location / {
return 301 https://$host$uri$is_args$args;
}
@@ -82,7 +90,7 @@ http {
ssl_certificate /etc/ssl/mail/cert.pem;
ssl_certificate_key /etc/ssl/mail/key.pem;
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.*;
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.* mta-sts.*;
include /etc/nginx/includes/sites-default.conf;
}

View File

@@ -76,6 +76,14 @@ location ^~ /.well-known/acme-challenge/ {
allow all;
default_type "text/plain";
}
location ^~ /.well-known/mta-sts.txt {
allow all;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass {{ PHPFPMHOST }}:9002;
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/mta-sts.php;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
rewrite ^/.well-known/caldav$ /SOGo/dav/ permanent;
rewrite ^/.well-known/carddav$ /SOGo/dav/ permanent;

View File

@@ -152,7 +152,7 @@ smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_sasl_passwd_maps_sender_dependent.cf
smtp_sasl_security_options =
smtp_sasl_mechanism_filter = plain, login
smtp_tls_policy_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_tls_policy_override_maps.cf
smtp_tls_policy_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_tls_policy_override_maps.cf socketmap:inet:postfix-tlspol:8642:QUERY
smtp_header_checks = pcre:/opt/postfix/conf/anonymize_headers.pcre
mail_name = Postcow
# local_transport map catches local destinations and prevents routing local dests when the next map would route "*"

View File

@@ -1,13 +1,25 @@
# Whitelist generated by Postwhite v3.4 on Tue Jul 1 00:22:55 UTC 2025
# Whitelist generated by Postwhite v3.4 on Mon Sep 1 00:23:07 UTC 2025
# https://github.com/stevejenkins/postwhite/
# 2105 total rules
# 2165 total rules
2a00:1450:4000::/36 permit
2a01:111:f400::/48 permit
2a01:111:f403::/49 permit
2a01:111:f403:8000::/50 permit
2a01:111:f403:8000::/51 permit
2a01:111:f403::/49 permit
2a01:111:f403:c000::/51 permit
2a01:111:f403:f000::/52 permit
2a01:238:20a:202:5370::1 permit
2a01:238:20a:202:5372::1 permit
2a01:238:20a:202:5373::1 permit
2a01:238:400:101:53::1 permit
2a01:238:400:102:53::1 permit
2a01:238:400:103:53::1 permit
2a01:238:400:301:53::1 permit
2a01:238:400:302:53::1 permit
2a01:238:400:303:53::1 permit
2a01:238:400:470:53::1 permit
2a01:238:400:471:53::1 permit
2a01:238:400:472:53::1 permit
2a01:b747:3000:200::/56 permit
2a01:b747:3001:200::/56 permit
2a01:b747:3002:200::/56 permit
@@ -17,16 +29,17 @@
2a01:b747:3006:200::/56 permit
2a02:a60:0:5::/64 permit
2c0f:fb50:4000::/36 permit
2.207.151.53 permit
2.207.217.30 permit
3.64.237.68 permit
3.65.3.180 permit
3.70.123.177 permit
3.72.182.33 permit
3.74.81.189 permit
3.74.125.228 permit
3.75.33.185 permit
3.93.157.0/24 permit
3.94.40.108 permit
3.121.107.214 permit
3.129.120.190 permit
3.210.190.0/24 permit
3.211.80.218 permit
@@ -42,7 +55,7 @@
8.40.222.0/23 permit
8.40.222.250/31 permit
12.130.86.238 permit
13.107.246.51 permit
13.107.246.40 permit
13.110.208.0/21 permit
13.110.209.0/24 permit
13.110.216.0/22 permit
@@ -64,6 +77,8 @@
18.97.2.64/26 permit
18.156.89.250 permit
18.156.205.64 permit
18.157.70.148 permit
18.157.114.255 permit
18.157.243.190 permit
18.158.153.154 permit
18.194.95.56 permit
@@ -75,9 +90,7 @@
18.216.232.154 permit
18.235.27.253 permit
18.236.40.242 permit
18.236.56.161 permit
20.51.6.32/30 permit
20.51.98.61 permit
20.52.52.2 permit
20.52.128.133 permit
20.59.80.4/30 permit
@@ -120,7 +133,6 @@
27.123.206.56/29 permit
27.123.206.76/30 permit
27.123.206.80/28 permit
31.25.48.222 permit
31.47.251.17 permit
31.186.239.0/24 permit
34.2.64.0/22 permit
@@ -154,8 +166,8 @@
34.212.163.75 permit
34.215.104.144 permit
34.218.115.239 permit
34.218.116.3 permit
34.225.212.172 permit
34.241.242.183 permit
35.83.148.184 permit
35.155.198.111 permit
35.158.23.94 permit
@@ -171,6 +183,7 @@
37.218.249.47 permit
37.218.251.62 permit
39.156.163.64/29 permit
40.90.65.81 permit
40.92.0.0/15 permit
40.92.0.0/16 permit
40.107.0.0/16 permit
@@ -178,6 +191,7 @@
40.233.64.216 permit
40.233.83.78 permit
40.233.88.28 permit
43.239.212.33 permit
44.206.138.57 permit
44.210.169.44 permit
44.217.45.156 permit
@@ -188,7 +202,10 @@
44.246.68.102 permit
44.246.77.92 permit
45.14.148.0/22 permit
46.19.170.16 permit
45.143.132.0/24 permit
45.143.133.0/24 permit
45.143.134.0/24 permit
45.143.135.0/24 permit
46.226.48.0/21 permit
46.228.36.37 permit
46.228.36.38/31 permit
@@ -254,8 +271,12 @@
50.56.130.221 permit
50.56.130.222 permit
50.112.246.219 permit
51.77.79.158 permit
51.83.17.38 permit
51.89.119.103 permit
52.1.14.157 permit
52.5.230.59 permit
52.6.74.205 permit
52.12.53.23 permit
52.13.214.179 permit
52.26.1.71 permit
@@ -303,6 +324,8 @@
52.234.172.96/28 permit
52.235.253.128 permit
52.236.28.240/28 permit
54.36.149.183 permit
54.38.221.122 permit
54.90.148.255 permit
54.165.19.38 permit
54.174.52.0/24 permit
@@ -323,13 +346,13 @@
54.255.61.23 permit
56.124.6.228 permit
57.103.64.0/18 permit
57.129.93.249 permit
62.13.128.0/24 permit
62.13.129.128/25 permit
62.13.136.0/21 permit
62.13.144.0/21 permit
62.13.152.0/21 permit
62.17.146.128/26 permit
62.179.121.0/24 permit
62.201.172.0/27 permit
62.201.172.32/27 permit
62.253.227.114 permit
@@ -352,6 +375,7 @@
64.127.115.252 permit
64.132.88.0/23 permit
64.132.92.0/24 permit
64.181.194.190 permit
64.207.219.7 permit
64.207.219.8 permit
64.207.219.9 permit
@@ -408,7 +432,6 @@
65.154.166.0/24 permit
65.212.180.36 permit
66.102.0.0/20 permit
66.102.0.0/21 permit
66.119.150.192/26 permit
66.163.184.0/24 permit
66.163.185.0/24 permit
@@ -643,6 +666,11 @@
77.238.189.142 permit
77.238.189.146/31 permit
77.238.189.148/30 permit
79.135.106.0/24 permit
79.135.107.0/24 permit
81.169.146.243 permit
81.169.146.245 permit
81.169.146.246 permit
81.223.46.0/27 permit
82.165.159.2 permit
82.165.159.3 permit
@@ -658,10 +686,15 @@
82.165.159.45 permit
82.165.159.130 permit
82.165.159.131 permit
84.116.6.0/23 permit
84.116.36.0/24 permit
84.116.50.0/23 permit
85.158.136.0/21 permit
85.215.255.39 permit
85.215.255.40 permit
85.215.255.41 permit
85.215.255.45 permit
85.215.255.46 permit
85.215.255.47 permit
85.215.255.48 permit
85.215.255.49 permit
86.61.88.25 permit
87.238.80.0/21 permit
87.248.103.12 permit
@@ -701,12 +734,13 @@
87.248.117.205 permit
87.253.232.0/21 permit
89.22.108.0/24 permit
91.198.2.0/24 permit
91.211.240.0/22 permit
94.169.2.0/23 permit
94.236.119.0/26 permit
94.245.112.0/27 permit
94.245.112.10/31 permit
95.131.104.0/21 permit
95.217.114.154 permit
96.43.144.0/20 permit
96.43.144.64/28 permit
96.43.144.64/31 permit
@@ -1344,9 +1378,9 @@
108.174.6.215 permit
108.175.18.45 permit
108.175.30.45 permit
108.177.8.0/21 permit
108.177.96.0/19 permit
108.177.96.0/20 permit
108.179.144.0/20 permit
109.224.244.0/24 permit
109.237.142.0/24 permit
111.221.23.128/25 permit
111.221.26.0/27 permit
@@ -1429,6 +1463,8 @@
132.226.26.225 permit
132.226.49.32 permit
132.226.56.24 permit
134.128.64.0/19 permit
134.128.96.0/19 permit
134.170.27.8 permit
134.170.113.0/26 permit
134.170.141.64/26 permit
@@ -1508,7 +1544,6 @@
148.105.0.0/16 permit
148.105.8.0/21 permit
149.72.0.0/16 permit
149.72.223.204 permit
149.72.248.236 permit
149.97.173.180 permit
150.230.98.160 permit
@@ -1618,17 +1653,20 @@
168.245.127.231 permit
169.148.129.0/24 permit
169.148.131.0/24 permit
169.148.138.0/24 permit
169.148.142.10 permit
169.148.144.0/25 permit
169.148.144.10 permit
169.148.146.0/23 permit
169.148.175.3 permit
169.148.188.0/24 permit
169.148.188.182 permit
170.10.128.0/24 permit
170.10.129.0/24 permit
170.10.132.56/29 permit
170.10.132.64/29 permit
170.10.133.0/24 permit
172.217.0.0/19 permit
172.217.0.0/20 permit
172.217.32.0/20 permit
172.217.128.0/19 permit
172.217.160.0/20 permit
@@ -1662,9 +1700,14 @@
182.50.78.64/28 permit
183.240.219.64/29 permit
185.4.120.0/22 permit
185.11.253.128/27 permit
185.11.255.0/24 permit
185.12.80.0/22 permit
185.28.196.0/22 permit
185.58.84.93 permit
185.70.40.0/24 permit
185.70.41.0/24 permit
185.70.43.0/24 permit
185.80.93.204 permit
185.80.93.227 permit
185.80.95.31 permit
@@ -1672,6 +1715,8 @@
185.138.56.128/25 permit
185.189.236.0/22 permit
185.211.120.0/22 permit
185.233.188.0/23 permit
185.233.190.0/23 permit
185.250.236.0/22 permit
185.250.239.148 permit
185.250.239.168 permit
@@ -1724,6 +1769,7 @@
188.125.85.234/31 permit
188.125.85.236/31 permit
188.125.85.238 permit
188.165.51.139 permit
188.172.128.0/20 permit
192.0.64.0/18 permit
192.18.139.154 permit
@@ -1746,7 +1792,12 @@
193.109.254.0/23 permit
193.122.128.100 permit
193.123.56.63 permit
193.142.157.0/24 permit
193.142.157.191 permit
193.142.157.198 permit
194.19.134.0/25 permit
194.25.134.16/28 permit
194.25.134.80/28 permit
194.64.234.129 permit
194.97.196.0/24 permit
194.97.196.3 permit
@@ -1865,6 +1916,8 @@
204.92.114.187 permit
204.92.114.203 permit
204.92.114.204/31 permit
204.141.32.0/23 permit
204.141.42.0/23 permit
204.216.164.202 permit
204.220.160.0/21 permit
204.220.168.0/21 permit
@@ -1944,8 +1997,6 @@
208.71.42.212/31 permit
208.71.42.214 permit
208.72.249.240/29 permit
208.74.204.5 permit
208.74.204.9 permit
208.75.120.0/22 permit
208.76.62.0/24 permit
208.76.63.0/24 permit
@@ -2009,6 +2060,8 @@
212.227.15.4 permit
212.227.15.5 permit
212.227.15.6 permit
212.227.15.7 permit
212.227.15.8 permit
212.227.15.14 permit
212.227.15.15 permit
212.227.15.18 permit
@@ -2025,21 +2078,36 @@
212.227.15.53 permit
212.227.15.54 permit
212.227.15.55 permit
212.227.17.1 permit
212.227.17.2 permit
212.227.17.7 permit
212.227.17.11 permit
212.227.17.12 permit
212.227.17.16 permit
212.227.17.17 permit
212.227.17.18 permit
212.227.17.19 permit
212.227.17.20 permit
212.227.17.21 permit
212.227.17.22 permit
212.227.17.26 permit
212.227.17.27 permit
212.227.17.28 permit
212.227.17.29 permit
212.227.126.206 permit
212.227.126.207 permit
212.227.126.208 permit
212.227.126.209 permit
212.227.126.220 permit
212.227.126.221 permit
212.227.126.222 permit
212.227.126.223 permit
212.227.126.224 permit
212.227.126.225 permit
212.227.126.226 permit
212.227.126.227 permit
213.46.255.0/24 permit
213.95.19.64/27 permit
213.95.135.4 permit
213.199.128.139 permit
213.199.128.145 permit
213.199.138.181 permit
@@ -2141,16 +2209,17 @@
2607:13c0:0002:0000:0000:0000:0000:1000/116 permit
2607:13c0:0004:0000:0000:0000:0000:0000/116 permit
2607:f8b0:4000::/36 permit
2620:109:c003:104::/64 permit
2620:109:c003:104::215 permit
2620:109:c006:104::/64 permit
2620:109:c003:104::/64 permit
2620:109:c006:104::215 permit
2620:109:c006:104::/64 permit
2620:109:c00d:104::/64 permit
2620:10d:c090:400::8:1 permit
2620:10d:c091:400::8:1 permit
2620:10d:c09b:400::8:1 permit
2620:10d:c09c:400::8:1 permit
2620:119:50c0:207::/64 permit
2620:119:50c0:207::215 permit
2620:119:50c0:207::/64 permit
2800:3f0:4000::/36 permit
194.25.134.0/24 permit # t-online.de
49.12.4.251 permit # checks.mailcow.email
2a01:4f8:c17:7906::10 permit # checks.mailcow.email

View File

@@ -56,7 +56,7 @@ function normalize_email($email) {
$email = explode('@', $email);
$email[0] = str_replace('.', '', $email[0]);
$email = implode('@', $email);
}
}
$gm_alt = "@googlemail.com";
if (substr_compare($email, $gm_alt, -strlen($gm_alt)) == 0) {
$email = explode('@', $email);
@@ -114,7 +114,7 @@ function ucl_rcpts($object, $type) {
$rcpt[] = str_replace('/', '\/', $row['address']);
}
// Aliases by alias domains
$stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias` FROM `mailbox`
$stmt = $pdo->prepare("SELECT CONCAT(`local_part`, '@', `alias_domain`.`alias_domain`) AS `alias` FROM `mailbox`
LEFT OUTER JOIN `alias_domain` ON `mailbox`.`domain` = `alias_domain`.`target_domain`
WHERE `mailbox`.`username` = :object");
$stmt->execute(array(
@@ -184,7 +184,7 @@ while ($row = array_shift($rows)) {
rcpt = <?=json_encode($rcpt, JSON_UNESCAPED_SLASHES);?>;
<?php
}
$stmt = $pdo->prepare("SELECT `option`, `value` FROM `filterconf`
$stmt = $pdo->prepare("SELECT `option`, `value` FROM `filterconf`
WHERE (`option` = 'highspamlevel' OR `option` = 'lowspamlevel')
AND `object`= :object");
$stmt->execute(array(':object' => $row['object']));
@@ -468,4 +468,36 @@ while ($row = array_shift($rows)) {
<?php
}
?>
<?php
// Start internal aliases
$stmt = $pdo->query("SELECT `id`, `address`, `domain` FROM `alias` WHERE `active` = '1' AND `internal` = '1'");
$aliases = $stmt->fetchAll(PDO::FETCH_ASSOC);
while ($alias = array_shift($aliases)) {
// build allowed_domains regex and add target domain and alias domains
$stmt = $pdo->prepare("SELECT `alias_domain` FROM `alias_domain` WHERE `active` = '1' AND `target_domain` = :target_domain");
$stmt->execute(array(':target_domain' => $alias['domain']));
$allowed_domains = $stmt->fetchAll(PDO::FETCH_ASSOC);
$allowed_domains = array_map(function($item) {
return str_replace('.', '\.', $item['alias_domain']);
}, $allowed_domains);
$allowed_domains[] = str_replace('.', '\.', $alias['domain']);
$allowed_domains = implode('|', $allowed_domains);
?>
internal_alias_<?=$alias['id'];?> {
priority = 10;
rcpt = "<?=$alias['address'];?>";
from = "/^((?!.*@(<?=$allowed_domains;?>)).)*$/";
apply "default" {
MAILCOW_INTERNAL_ALIAS = 9999.0;
}
symbols [
"MAILCOW_INTERNAL_ALIAS"
]
}
<?php
}
?>
}

View File

@@ -102,7 +102,7 @@ rspamd_config:register_symbol({
local rcpt_split = rspamd_str_split(rcpt['addr'], '@')
if #rcpt_split == 2 then
if rcpt_split[1] == 'postmaster' then
task:set_pre_result('accept', 'whitelisting postmaster smtp rcpt')
task:set_pre_result('accept', 'whitelisting postmaster smtp rcpt', 'postmaster')
return
end
end
@@ -167,7 +167,7 @@ rspamd_config:register_symbol({
for k,v in pairs(data) do
if (v and v ~= userdata and v == '1') then
rspamd_logger.infox(rspamd_config, "found ip in keep_spam map, setting pre-result")
task:set_pre_result('accept', 'ip matched with forward hosts')
task:set_pre_result('accept', 'ip matched with forward hosts', 'keep_spam')
end
end
end
@@ -454,12 +454,18 @@ rspamd_config:register_symbol({
local redis_params = rspamd_parse_redis_server('dyn_rl')
local rspamd_logger = require "rspamd_logger"
local envfrom = task:get_from(1)
local envrcpt = task:get_recipients(1) or {}
local uname = task:get_user()
if not envfrom or not uname then
return false
end
local uname = uname:lower()
if #envrcpt == 1 and envrcpt[1].addr:lower() == uname then
return false
end
local env_from_domain = envfrom[1].domain:lower() -- get smtp from domain in lower case
local function redis_cb_user(err, data)
@@ -544,13 +550,13 @@ rspamd_config:register_symbol({
-- determine newline type
local function newline(task)
local t = task:get_newlines_type()
if t == 'cr' then
return '\r'
elseif t == 'lf' then
return '\n'
end
return '\r\n'
end
-- retrieve footer
@@ -558,7 +564,7 @@ rspamd_config:register_symbol({
if err or type(data) ~= 'string' then
rspamd_logger.infox(rspamd_config, "domain wide footer request for user %s returned invalid or empty data (\"%s\") or error (\"%s\")", uname, data, err)
else
-- parse json string
local footer = cjson.decode(data)
if not footer then
@@ -607,26 +613,30 @@ rspamd_config:register_symbol({
if footer.plain and footer.plain ~= "" then
footer.plain = lua_util.jinja_template(footer.plain, replacements, true)
end
-- add footer
local out = {}
local rewrite = lua_mime.add_text_footer(task, footer.html, footer.plain) or {}
local seen_cte
local newline_s = newline(task)
local function rewrite_ct_cb(name, hdr)
if rewrite.need_rewrite_ct then
if name:lower() == 'content-type' then
local nct = string.format('%s: %s/%s; charset=utf-8',
'Content-Type', rewrite.new_ct.type, rewrite.new_ct.subtype)
-- include boundary if present
local boundary_part = rewrite.new_ct.boundary and
string.format('; boundary="%s"', rewrite.new_ct.boundary) or ''
local nct = string.format('%s: %s/%s; charset=utf-8%s',
'Content-Type', rewrite.new_ct.type, rewrite.new_ct.subtype, boundary_part)
out[#out + 1] = nct
-- update Content-Type header
-- update Content-Type header (include boundary if present)
task:set_milter_reply({
remove_headers = {['Content-Type'] = 0},
})
task:set_milter_reply({
add_headers = {['Content-Type'] = string.format('%s/%s; charset=utf-8', rewrite.new_ct.type, rewrite.new_ct.subtype)}
add_headers = {['Content-Type'] = string.format('%s/%s; charset=utf-8%s',
rewrite.new_ct.type, rewrite.new_ct.subtype, boundary_part)}
})
return
elseif name:lower() == 'content-transfer-encoding' then
@@ -645,16 +655,16 @@ rspamd_config:register_symbol({
end
out[#out + 1] = hdr.raw:gsub('\r?\n?$', '')
end
task:headers_foreach(rewrite_ct_cb, {full = true})
if not seen_cte and rewrite.need_rewrite_ct then
out[#out + 1] = string.format('%s: %s', 'Content-Transfer-Encoding', 'quoted-printable')
end
-- End of headers
out[#out + 1] = newline_s
if rewrite.out then
for _,o in ipairs(rewrite.out) do
out[#out + 1] = o

View File

@@ -236,6 +236,9 @@ foreach ($rcpt_final_mailboxes as $rcpt_final) {
':action' => $action,
':fuzzy_hashes' => $fuzzy
));
$lastId = $pdo->lastInsertId();
$stmt_update = $pdo->prepare("UPDATE `quarantine` SET `qhash` = SHA2(CONCAT(`id`, `qid`), 256) WHERE `id` = :id");
$stmt_update->execute(array(':id' => $lastId));
$stmt = $pdo->prepare('DELETE FROM `quarantine` WHERE `rcpt` = :rcpt AND `id` NOT IN (
SELECT `id`
FROM (

View File

@@ -48,6 +48,12 @@ if (isset($_SESSION['mailcow_cc_role'])) {
$rl = ratelimit('get', 'domain', $domain);
$rlyhosts = relayhost('get');
$domain_footer = mailbox('get', 'domain_wide_footer', $domain);
$mta_sts = mailbox('get', 'mta_sts', $domain);
if (count($mta_sts) == 0) {
$mta_sts = false;
} elseif (isset($mta_sts['mx'])) {
$mta_sts['mx'] = implode(',', $mta_sts['mx']);
}
$template = 'edit/domain.twig';
$template_data = [
'acl' => $_SESSION['acl'],
@@ -58,6 +64,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
'dkim' => dkim('details', $domain),
'domain_details' => $result,
'domain_footer' => $domain_footer,
'mta_sts' => $mta_sts,
'mailboxes' => mailbox('get', 'mailboxes', $_GET["domain"]),
'aliases' => mailbox('get', 'aliases', $_GET["domain"], 'address'),
'alias_domains' => mailbox('get', 'alias_domains', $_GET["domain"])
@@ -125,6 +132,7 @@ if (isset($_SESSION['mailcow_cc_role'])) {
'mailbox' => $mailbox,
'rl' => $rl,
'pushover_data' => $pushover_data,
'get_tagging_options' => mailbox('get', 'delimiter_action', $mailbox),
'quarantine_notification' => $quarantine_notification,
'quarantine_category' => $quarantine_category,
'get_tls_policy' => $get_tls_policy,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -71,6 +71,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
// Init records array
$spf_link = '<a href="http://www.open-spf.org/SPF_Record_Syntax/" target="_blank">SPF Record Syntax</a><br />';
$dmarc_link = '<a href="https://www.kitterman.com/dmarc/assistant.html" target="_blank">DMARC Assistant</a>';
$mtasts_report_link = '<a href="https://mxtoolbox.com/dmarc/smtp-tls/how-to-setup-smtp-tls-reports" target="_blank">TLS Report Record Syntax</a>';
$records = array();
@@ -128,6 +129,27 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
);
}
$mta_sts = mailbox('get', 'mta_sts', $domain);
if (count($mta_sts) > 0 && $mta_sts['active'] == 1) {
if (!in_array($domain, $alias_domains)) {
$records[] = array(
'mta-sts.' . $domain,
'CNAME',
$mailcow_hostname
);
}
$records[] = array(
'_mta-sts.' . $domain,
'TXT',
"v={$mta_sts['version']};id={$mta_sts['id']};",
);
$records[] = array(
'_smtp._tls.' . $domain,
'TXT',
$mtasts_report_link,
);
}
$records[] = array(
$domain,
'TXT',
@@ -341,15 +363,25 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
}
foreach ($currents as &$current) {
if ($current['type'] == "TXT" &&
stripos(strtolower($current['txt']), 'v=sts') === 0) {
if (strtolower($current[$data_field[$current['type']]]) == strtolower($record[2])) {
$state = state_good;
}
else {
$state = state_nomatch;
}
$state .= '<br />' . $current[$data_field[$current['type']]];
}
if ($current['type'] == 'TXT' &&
stripos($current['txt'], 'v=dmarc') === 0 &&
$record[2] == $dmarc_link) {
stripos($current['txt'], 'v=dmarc') === 0 &&
$record[2] == $dmarc_link) {
$current['txt'] = str_replace(' ', '', $current['txt']);
$state = $current[$data_field[$current['type']]] . state_optional;
}
elseif ($current['type'] == 'TXT' &&
stripos($current['txt'], 'v=spf') === 0 &&
$record[2] == $spf_link) {
stripos($current['txt'], 'v=spf') === 0 &&
$record[2] == $spf_link) {
$state = state_nomatch;
$rslt = get_spf_allowed_hosts($record[0], true);
if (in_array($ip, $rslt) && in_array(expand_ipv6($ip6), $rslt)) {
@@ -358,8 +390,8 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
$state .= '<br />' . $current[$data_field[$current['type']]] . state_optional;
}
elseif ($current['type'] == 'TXT' &&
stripos($current['txt'], 'v=dkim') === 0 &&
stripos($record[2], 'v=dkim') === 0) {
stripos($current['txt'], 'v=dkim') === 0 &&
stripos($record[2], 'v=dkim') === 0) {
preg_match('/v=DKIM1;.*k=rsa;.*p=([^;]*).*/i', $current[$data_field[$current['type']]], $dkim_matches_current);
preg_match('/v=DKIM1;.*k=rsa;.*p=([^;]*).*/i', $record[2], $dkim_matches_good);
if ($dkim_matches_current[1] == $dkim_matches_good[1]) {
@@ -367,7 +399,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
}
}
elseif ($current['type'] != 'TXT' &&
isset($data_field[$current['type']]) && $state != state_good) {
isset($data_field[$current['type']]) && $state != state_good) {
$state = state_nomatch;
if ($current[$data_field[$current['type']]] == $record[2]) {
$state = state_good;

View File

@@ -26,23 +26,25 @@ if (is_array($alertbox_log_parser)) {
// map tfa details for twig
$pending_tfa_authmechs = [];
foreach($_SESSION['pending_tfa_methods'] as $authdata){
$pending_tfa_authmechs[$authdata['authmech']] = false;
}
if (isset($pending_tfa_authmechs['webauthn'])) {
$pending_tfa_authmechs['webauthn'] = true;
}
if (!isset($pending_tfa_authmechs['webauthn'])
&& isset($pending_tfa_authmechs['yubi_otp'])) {
$pending_tfa_authmechs['yubi_otp'] = true;
}
if (!isset($pending_tfa_authmechs['webauthn'])
&& !isset($pending_tfa_authmechs['yubi_otp'])
&& isset($pending_tfa_authmechs['totp'])) {
$pending_tfa_authmechs['totp'] = true;
}
if (isset($pending_tfa_authmechs['u2f'])) {
$pending_tfa_authmechs['u2f'] = true;
if (array_key_exists('pending_tfa_methods', $_SESSION)) {
foreach($_SESSION['pending_tfa_methods'] as $authdata){
$pending_tfa_authmechs[$authdata['authmech']] = false;
}
if (isset($pending_tfa_authmechs['webauthn'])) {
$pending_tfa_authmechs['webauthn'] = true;
}
if (!isset($pending_tfa_authmechs['webauthn'])
&& isset($pending_tfa_authmechs['yubi_otp'])) {
$pending_tfa_authmechs['yubi_otp'] = true;
}
if (!isset($pending_tfa_authmechs['webauthn'])
&& !isset($pending_tfa_authmechs['yubi_otp'])
&& isset($pending_tfa_authmechs['totp'])) {
$pending_tfa_authmechs['totp'] = true;
}
if (isset($pending_tfa_authmechs['u2f'])) {
$pending_tfa_authmechs['u2f'] = true;
}
}
// globals

View File

@@ -193,6 +193,7 @@ function user_login($user, $pass, $extra = null){
global $iam_settings;
$is_internal = $extra['is_internal'];
$service = $extra['service'];
if (!filter_var($user, FILTER_VALIDATE_EMAIL) && !ctype_alnum(str_replace(array('_', '.', '-'), '', $user))) {
if (!$is_internal){
@@ -235,6 +236,14 @@ function user_login($user, $pass, $extra = null){
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!empty($row)) {
// check if user has access to service (imap, smtp, pop3, sieve) if service is set
$row['attributes'] = json_decode($row['attributes'], true);
if (isset($service)) {
$key = strtolower($service) . "_access";
if (isset($row['attributes'][$key]) && $row['attributes'][$key] != '1') {
return false;
}
}
return true;
}
}
@@ -242,7 +251,14 @@ function user_login($user, $pass, $extra = null){
return false;
}
// check if user has access to service (imap, smtp, pop3, sieve) if service is set
$row['attributes'] = json_decode($row['attributes'], true);
if (isset($service)) {
$key = strtolower($service) . "_access";
if (isset($row['attributes'][$key]) && $row['attributes'][$key] != '1') {
return false;
}
}
switch ($row['authsource']) {
case 'keycloak':
// user authsource is keycloak, try using via rest flow

View File

@@ -293,7 +293,7 @@ function customize($_action, $_item, $_data = null) {
}
if (empty($app_links)){
return false;
return [];
}
// convert from old style

View File

@@ -2211,7 +2211,7 @@ function cors($action, $data = null) {
$cors_settings['allowed_origins'] = $allowed_origins[0];
if (in_array('*', $allowed_origins)){
$cors_settings['allowed_origins'] = '*';
} else if (in_array($_SERVER['HTTP_ORIGIN'], $allowed_origins)) {
} else if (array_key_exists('HTTP_ORIGIN', $_SERVER) && in_array($_SERVER['HTTP_ORIGIN'], $allowed_origins)) {
$cors_settings['allowed_origins'] = $_SERVER['HTTP_ORIGIN'];
}
// always allow OPTIONS for preflight request

View File

@@ -684,15 +684,16 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
return true;
break;
case 'alias':
$addresses = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['address']));
$gotos = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['goto']));
$active = intval($_data['active']);
$sogo_visible = intval($_data['sogo_visible']);
$goto_null = intval($_data['goto_null']);
$goto_spam = intval($_data['goto_spam']);
$goto_ham = intval($_data['goto_ham']);
$addresses = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['address']));
$gotos = array_map('trim', preg_split( "/( |,|;|\n)/", $_data['goto']));
$internal = intval($_data['internal']);
$active = intval($_data['active']);
$sogo_visible = intval($_data['sogo_visible']);
$goto_null = intval($_data['goto_null']);
$goto_spam = intval($_data['goto_spam']);
$goto_ham = intval($_data['goto_ham']);
$private_comment = $_data['private_comment'];
$public_comment = $_data['public_comment'];
$public_comment = $_data['public_comment'];
if (strlen($private_comment) > 160 | strlen($public_comment) > 160){
$_SESSION['return'][] = array(
'type' => 'danger',
@@ -842,8 +843,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
);
continue;
}
$stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `public_comment`, `private_comment`, `goto`, `domain`, `sogo_visible`, `active`)
VALUES (:address, :public_comment, :private_comment, :goto, :domain, :sogo_visible, :active)");
$stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `public_comment`, `private_comment`, `goto`, `domain`, `sogo_visible`, `internal`, `active`)
VALUES (:address, :public_comment, :private_comment, :goto, :domain, :sogo_visible, :internal, :active)");
if (!filter_var($address, FILTER_VALIDATE_EMAIL) === true) {
$stmt->execute(array(
':address' => '@'.$domain,
@@ -853,6 +854,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':goto' => $goto,
':domain' => $domain,
':sogo_visible' => $sogo_visible,
':internal' => $internal,
':active' => $active
));
}
@@ -864,6 +866,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':goto' => $goto,
':domain' => $domain,
':sogo_visible' => $sogo_visible,
':internal' => $internal,
':active' => $active
));
}
@@ -1223,6 +1226,14 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$stmt->execute(array(
':username' => $username
));
// save delimiter_action
if (isset($_data['tagged_mail_handler'])) {
mailbox('edit', 'delimiter_action', array(
'username' => $username,
'tagged_mail_handler' => $_data['tagged_mail_handler']
));
}
// save tags
foreach($tags as $index => $tag){
if (empty($tag)) continue;
@@ -1392,6 +1403,80 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
return mailbox('add', 'mailbox', $mailbox_attributes);
break;
case 'mta_sts':
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
$version = strtolower($_data['version']);
$mode = strtolower($_data['mode']);
$mx = explode(",", preg_replace('/\s+/', '', $_data['mx']));
$max_age = intval($_data['max_age']);
$active = (intval($_data['active']) == 1) ? 1 : 0;
$id = date('YmdHis');
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
'msg' => 'access_denied'
);
return false;
}
if (empty($version) || !in_array($version, array('stsv1'))) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
'msg' => array('version_invalid', htmlspecialchars($domain))
);
return false;
}
if (empty($mode) || !in_array($mode, array('enforce', 'testing', 'none'))) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
'msg' => array('mode_invalid', htmlspecialchars($domain))
);
return false;
}
if (empty($max_age) || $max_age < 0 || $max_age > 31536000) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
'msg' => array('max_age_invalid', htmlspecialchars($domain))
);
return false;
}
foreach ($mx as $index => $mx_domain) {
$mx_domain = idn_to_ascii(strtolower(trim($mx_domain)), 0, INTL_IDNA_VARIANT_UTS46);
if (!is_valid_domain_name($mx_domain)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
'msg' => array('mx_invalid', htmlspecialchars($mx_domain))
);
return false;
}
}
try {
$stmt = $pdo->prepare("INSERT INTO `mta_sts` (`id`, `domain`, `version`, `mode`, `mx`, `max_age`, `active`)
VALUES (:id, :domain, :version, :mode, :mx, :max_age, :active)");
$stmt->execute(array(
':id' => $id,
':domain' => $domain,
':version' => $version,
':mode' => $mode,
':mx' => implode(",", $mx),
':max_age' => $max_age,
':active' => $active
));
} catch (PDOException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => $e->getMessage()
);
return false;
}
break;
case 'resource':
$domain = idn_to_ascii(strtolower(trim($_data['domain'])), 0, INTL_IDNA_VARIANT_UTS46);
$description = $_data['description'];
@@ -1613,6 +1698,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$attr = array();
$attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
$attr["tagged_mail_handler"] = (!empty($_data['tagged_mail_handler'])) ? $_data['tagged_mail_handler'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['tagged_mail_handler']);
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
@@ -2398,6 +2484,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
foreach ($ids as $id) {
$is_now = mailbox('get', 'alias_details', $id);
if (!empty($is_now)) {
$internal = (isset($_data['internal'])) ? intval($_data['internal']) : $is_now['internal'];
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
$sogo_visible = (isset($_data['sogo_visible'])) ? intval($_data['sogo_visible']) : $is_now['sogo_visible'];
$goto_null = (isset($_data['goto_null'])) ? intval($_data['goto_null']) : 0;
@@ -2583,6 +2670,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`domain` = :domain,
`goto` = :goto,
`sogo_visible`= :sogo_visible,
`internal`= :internal,
`active`= :active
WHERE `id` = :id");
$stmt->execute(array(
@@ -2592,6 +2680,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
':domain' => $domain,
':goto' => $goto,
':sogo_visible' => $sogo_visible,
':internal' => $internal,
':active' => $active,
':id' => $is_now['id']
));
@@ -3259,6 +3348,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
);
return false;
}
// save delimiter_action
if (isset($_data['tagged_mail_handler'])) {
mailbox('edit', 'delimiter_action', array(
'username' => $username,
'tagged_mail_handler' => $_data['tagged_mail_handler']
));
}
// save tags
foreach($tags as $index => $tag){
if (empty($tag)) continue;
@@ -3604,6 +3700,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$attr = array();
$attr["quota"] = isset($_data['quota']) ? intval($_data['quota']) * 1048576 : 0;
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : $is_now['tags'];
$attr["tagged_mail_handler"] = (!empty($_data['tagged_mail_handler'])) ? $_data['tagged_mail_handler'] : $is_now['tagged_mail_handler'];
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame'];
@@ -3724,6 +3821,125 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
return true;
break;
case 'mta_sts':
if (!is_array($_data['domains'])) {
$domains = array();
$domains[] = $_data['domains'];
}
else {
$domains = $_data['domains'];
}
foreach ($domains as $domain) {
$domain = idn_to_ascii(strtolower(trim($domain)), 0, INTL_IDNA_VARIANT_UTS46);
if (!hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $domain)) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
'msg' => 'access_denied'
);
continue;
}
$is_now = mailbox('get', 'mta_sts', $domain);
if (!empty($is_now)) {
$version = (isset($_data['version'])) ? strtolower($_data['version']) : $is_now['version'];
$active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
$active = ($active == 1) ? 1 : 0;
$mode = (isset($_data['mode'])) ? strtolower($_data['mode']) : $is_now['mode'];
$mx = (isset($_data['mx'])) ? explode(",", preg_replace('/\s+/', '', $_data['mx'])) : $is_now['mx'];
$max_age = (isset($_data['max_age'])) ? intval($_data['max_age']) : $is_now['max_age'];
// Update ID if neccesary
if ($version != strtolower($is_now['version']) ||
$mode != strtolower($is_now['mode']) ||
$mx != $is_now['mx'] ||
$max_age != $is_now['max_age']) {
$id = date('YmdHis');
} else {
$id = $is_now['id'];
}
} else {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
'msg' => 'access_denied'
);
continue;
}
if (empty($version) || !in_array($version, array('stsv1'))) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
'msg' => array('version_invalid', htmlspecialchars($version))
);
continue;
}
if (empty($mode) || !in_array($mode, array('enforce', 'testing', 'none'))) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
'msg' => array('mode_invalid', htmlspecialchars($domain))
);
continue;
}
if (empty($max_age) || $max_age < 0 || $max_age > 31557600) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
'msg' => array('max_age_invalid', htmlspecialchars($domain))
);
continue;
}
foreach ($mx as $index => $mx_domain) {
$mx_domain = idn_to_ascii(strtolower(trim($mx_domain)), 0, INTL_IDNA_VARIANT_UTS46);
$invalid_mx = false;
if (!is_valid_domain_name($mx_domain)) {
$invalid_mx = $mx_domain;
break;
}
}
if ($invalid_mx) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
'msg' => array('mx_invalid', htmlspecialchars($invalid_mx))
);
continue;
}
try {
$stmt = $pdo->prepare("UPDATE `mta_sts` SET `id` = :id, `version` = :version, `mode` = :mode, `mx` = :mx, `max_age` = :max_age, `active` = :active WHERE `domain` = :domain");
$stmt->execute(array(
':id' => $id,
':domain' => $domain,
':version' => $version,
':mode' => $mode,
':mx' => implode(",", $mx),
':max_age' => $max_age,
':active' => $active
));
} catch (PDOException $e) {
$_SESSION['return'][] = array(
'type' => 'danger',
'log' => array(__FUNCTION__, $_action, $_type, $_data),
'msg' => $e->getMessage()
);
continue;
}
$_SESSION['return'][] = array(
'type' => 'success',
'log' => array(__FUNCTION__, $_action, $_type, $_data, $_attr),
'msg' => array('object_modified', $domain)
);
}
return true;
break;
case 'resource':
if (!is_array($_data['name'])) {
$names = array();
@@ -4490,6 +4706,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
`address`,
`public_comment`,
`private_comment`,
`internal`,
`active`,
`sogo_visible`,
`created`,
@@ -4520,6 +4737,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$aliasdata['goto'] = $row['goto'];
$aliasdata['address'] = $row['address'];
(!filter_var($aliasdata['address'], FILTER_VALIDATE_EMAIL)) ? $aliasdata['is_catch_all'] = 1 : $aliasdata['is_catch_all'] = 0;
$aliasdata['internal'] = $row['internal'];
$aliasdata['active'] = $row['active'];
$aliasdata['active_int'] = $row['active'];
$aliasdata['sogo_visible'] = $row['sogo_visible'];
@@ -5012,6 +5230,20 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
return $rows;
}
break;
case 'mta_sts':
$stmt = $pdo->prepare("SELECT * FROM `mta_sts` WHERE `domain` = :domain");
$stmt->execute(array(
':domain' => $_data,
));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (empty($row)){
return [];
}
$row['mx'] = explode(',', $row['mx']);
$row['version'] = strtoupper(substr($row['version'], 0, 3)) . substr($row['version'], 3);
return $row;
break;
case 'resource_details':
$resourcedata = array();
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
@@ -5397,6 +5629,10 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$stmt->execute(array(
':domain' => $domain,
));
$stmt = $pdo->prepare("DELETE FROM `mta_sts` WHERE `domain` = :domain");
$stmt->execute(array(
':domain' => $domain,
));
$stmt = $pdo->query("DELETE FROM `admin` WHERE `superadmin` = 0 AND `username` NOT IN (SELECT `username`FROM `domain_admins`);");
$stmt = $pdo->query("DELETE FROM `da_acl` WHERE `username` NOT IN (SELECT `username`FROM `domain_admins`);");
try {

View File

@@ -22,7 +22,7 @@ function quarantine($_action, $_data = null) {
return false;
}
$stmt = $pdo->prepare('SELECT `id` FROM `quarantine` LEFT OUTER JOIN `user_acl` ON `user_acl`.`username` = `rcpt`
WHERE SHA2(CONCAT(`id`, `qid`), 256) = :hash
WHERE `qhash` = :hash
AND user_acl.quarantine = 1
AND rcpt IN (SELECT username FROM mailbox)');
$stmt->execute(array(':hash' => $hash));
@@ -65,7 +65,7 @@ function quarantine($_action, $_data = null) {
return false;
}
$stmt = $pdo->prepare('SELECT `id` FROM `quarantine` LEFT OUTER JOIN `user_acl` ON `user_acl`.`username` = `rcpt`
WHERE SHA2(CONCAT(`id`, `qid`), 256) = :hash
WHERE `qhash` = :hash
AND `user_acl`.`quarantine` = 1
AND `username` IN (SELECT `username` FROM `mailbox`)');
$stmt->execute(array(':hash' => $hash));
@@ -833,7 +833,7 @@ function quarantine($_action, $_data = null) {
)));
return false;
}
$stmt = $pdo->prepare('SELECT * FROM `quarantine` WHERE SHA2(CONCAT(`id`, `qid`), 256) = :hash');
$stmt = $pdo->prepare('SELECT * FROM `quarantine` WHERE `qhash` = :hash');
$stmt->execute(array(':hash' => $hash));
return $stmt->fetch(PDO::FETCH_ASSOC);
break;

View File

@@ -4,7 +4,7 @@ function init_db_schema()
try {
global $pdo;
$db_version = "27012025_1555";
$db_version = "19082025_1436";
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@@ -184,6 +184,7 @@ function init_db_schema()
"private_comment" => "TEXT",
"public_comment" => "TEXT",
"sogo_visible" => "TINYINT(1) NOT NULL DEFAULT '1'",
"internal" => "TINYINT(1) NOT NULL DEFAULT '0'",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
@@ -345,10 +346,14 @@ function init_db_schema()
"notified" => "TINYINT(1) NOT NULL DEFAULT '0'",
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
"user" => "VARCHAR(255) NOT NULL DEFAULT 'unknown'",
"qhash" => "VARCHAR(64)",
),
"keys" => array(
"primary" => array(
"" => array("id")
),
"key" => array(
"qhash" => array("qhash")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
@@ -471,6 +476,23 @@ function init_db_schema()
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"mta_sts" => array(
"cols" => array(
"id" => "BIGINT NOT NULL",
"domain" => "VARCHAR(255) NOT NULL",
"version" => "VARCHAR(255) NOT NULL",
"mode" => "VARCHAR(255) NOT NULL",
"mx" => "VARCHAR(255) NOT NULL",
"max_age" => "VARCHAR(255) NOT NULL",
"active" => "TINYINT(1) NOT NULL DEFAULT '1'"
),
"keys" => array(
"primary" => array(
"" => array("domain")
)
),
"attr" => "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC"
),
"user_acl" => array(
"cols" => array(
"username" => "VARCHAR(255) NOT NULL",
@@ -1482,6 +1504,10 @@ function init_db_schema()
'msg' => 'db_init_complete'
);
}
// fill quarantine.qhash
$pdo->query("UPDATE `quarantine` SET `qhash` = SHA2(CONCAT(`id`, `qid`), 256) WHERE ISNULL(`qhash`)");
} catch (PDOException $e) {
if (php_sapi_name() == "cli") {
echo "DB initialization failed: " . print_r($e, true) . PHP_EOL;

View File

@@ -83,6 +83,7 @@ $DEFAULT_LANG = 'en-gb';
// https://en.wikipedia.org/wiki/IETF_language_tag
$AVAILABLE_LANGUAGES = array(
// 'ca-es' => 'Català (Catalan)',
'bg-bg' => 'Български (Bulgarian)',
'cs-cz' => 'Čeština (Czech)',
'da-dk' => 'Danish (Dansk)',
'de-de' => 'Deutsch (German)',
@@ -185,6 +186,12 @@ $MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update'] = false;
// Enable SOGo access - Users will be redirected to SOGo after login (set to false to disable redirect by default)
$MAILBOX_DEFAULT_ATTRIBUTES['sogo_access'] = true;
// How to handle tagged emails
// none - No special handling
// subfolder - Create subfolder under INBOX (e.g. "INBOX/Facebook")
// subject - Add tag to subject (e.g. "[Facebook] Subject")
$MAILBOX_DEFAULT_ATTRIBUTES['tagged_mail_handler'] = "none";
// Send notification when quarantine is not empty (never, hourly, daily, weekly)
$MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification'] = 'hourly';
@@ -237,12 +244,12 @@ $FIDO2_FORMATS = array('apple', 'android-key', 'android-safetynet', 'fido-u2f',
// Set visible Rspamd maps in mailcow UI, do not change unless you know what you are doing
$RSPAMD_MAPS = array(
'regex' => array(
'Header-From: Blacklist' => 'global_mime_from_blacklist.map',
'Header-From: Whitelist' => 'global_mime_from_whitelist.map',
'Envelope Sender Blacklist' => 'global_smtp_from_blacklist.map',
'Envelope Sender Whitelist' => 'global_smtp_from_whitelist.map',
'Recipient Blacklist' => 'global_rcpt_blacklist.map',
'Recipient Whitelist' => 'global_rcpt_whitelist.map',
'Header-From: Denylist' => 'global_mime_from_blacklist.map',
'Header-From: Allowlist' => 'global_mime_from_whitelist.map',
'Envelope Sender Denylist' => 'global_smtp_from_blacklist.map',
'Envelope Sender Allowlist' => 'global_smtp_from_whitelist.map',
'Recipient Denylist' => 'global_rcpt_blacklist.map',
'Recipient Allowlist' => 'global_rcpt_whitelist.map',
'Fishy TLDS (only fired in combination with bad words)' => 'fishy_tlds.map',
'Bad Words (only fired in combination with fishy TLDs)' => 'bad_words.map',
'Bad Words DE (only fired in combination with fishy TLDs)' => 'bad_words_de.map',
@@ -256,57 +263,57 @@ $RSPAMD_MAPS = array(
$IMAPSYNC_OPTIONS = array(
'whitelist' => array(
'abort',
'authmd51',
'authmd52',
'abort',
'authmd51',
'authmd52',
'authmech1',
'authmech2',
'authuser1',
'authuser2',
'debug',
'debugcontent',
'debugcrossduplicates',
'debugflags',
'debugfolders',
'debugimap',
'debugimap1',
'debugimap2',
'debugmemory',
'debugssl',
'authuser1',
'authuser2',
'debug',
'debugcontent',
'debugcrossduplicates',
'debugflags',
'debugfolders',
'debugimap',
'debugimap1',
'debugimap2',
'debugmemory',
'debugssl',
'delete1emptyfolders',
'delete2folders',
'disarmreadreceipts',
'delete2folders',
'disarmreadreceipts',
'domain1',
'domain2',
'domino1',
'domino2',
'domino1',
'domino2',
'dry',
'errorsmax',
'exchange1',
'exchange2',
'exchange1',
'exchange2',
'exitwhenover',
'expunge1',
'f1f2',
'filterbuggyflags',
'f1f2',
'filterbuggyflags',
'folder',
'folderfirst',
'folderlast',
'folderrec',
'gmail1',
'gmail2',
'idatefromheader',
'gmail1',
'gmail2',
'idatefromheader',
'include',
'inet4',
'inet6',
'justconnect',
'justfolders',
'justfoldersizes',
'justlogin',
'keepalive1',
'keepalive2',
'justconnect',
'justfolders',
'justfoldersizes',
'justlogin',
'keepalive1',
'keepalive2',
'log',
'logdir',
'logfile',
'logfile',
'maxbytesafter',
'maxlinelength',
'maxmessagespersecond',
@@ -314,62 +321,62 @@ $IMAPSYNC_OPTIONS = array(
'maxsleep',
'minage',
'minsize',
'noabletosearch',
'noabletosearch1',
'noabletosearch2',
'noexpunge1',
'noexpunge2',
'noabletosearch',
'noabletosearch1',
'noabletosearch2',
'noexpunge1',
'noexpunge2',
'nofoldersizesatend',
'noid',
'nolog',
'nomixfolders',
'noresyncflags',
'nossl1',
'nossl2',
'nosyncacls',
'notls1',
'notls2',
'nouidexpunge2',
'nousecache',
'noid',
'nolog',
'nomixfolders',
'noresyncflags',
'nossl1',
'nossl2',
'nosyncacls',
'notls1',
'notls2',
'nouidexpunge2',
'nousecache',
'oauthaccesstoken1',
'oauthaccesstoken2',
'oauthdirect1',
'oauthdirect2',
'office1',
'office2',
'pidfile',
'pidfilelocking',
'office1',
'office2',
'pidfile',
'pidfilelocking',
'prefix1',
'prefix2',
'proxyauth1',
'proxyauth2',
'resyncflags',
'resynclabels',
'search',
'proxyauth1',
'proxyauth2',
'resyncflags',
'resynclabels',
'search',
'search1',
'search2',
'search2',
'sep1',
'sep2',
'showpasswords',
'skipemptyfolders',
'ssl2',
'ssl2',
'sslargs1',
'sslargs2',
'sslargs2',
'subfolder1',
'subscribe',
'subscribe',
'subscribed',
'syncacls',
'syncduplicates',
'syncinternaldates',
'synclabels',
'tests',
'testslive',
'testslive6',
'tls2',
'truncmess',
'usecache',
'useheader',
'useuid'
'synclabels',
'tests',
'testslive',
'testslive6',
'tls2',
'truncmess',
'usecache',
'useheader',
'useuid'
),
'blacklist' => array(
'skipmess',

View File

@@ -269,6 +269,24 @@ $(document).ready(function() {
function setMailboxTemplateData(template){
$("#addInputQuota").val(template.quota / 1048576);
if (template.tagged_mail_handler === "subfolder"){
$('#tagged_mail_handler_subfolder').prop('checked', true);
$('#tagged_mail_handler_subject').prop('checked', false);
$('#tagged_mail_handler_none').prop('checked', false);
} else if(template.tagged_mail_handler === "subject"){
$('#tagged_mail_handler_subfolder').prop('checked', false);
$('#tagged_mail_handler_subject').prop('checked', true);
$('#tagged_mail_handler_none').prop('checked', false);
} else if(template.tagged_mail_handler === "none"){
$('#tagged_mail_handler_subfolder').prop('checked', false);
$('#tagged_mail_handler_subject').prop('checked', false);
$('#tagged_mail_handler_none').prop('checked', true);
} else {
$('#tagged_mail_handler_subfolder').prop('checked', false);
$('#tagged_mail_handler_subject').prop('checked', false);
$('#tagged_mail_handler_none').prop('checked', true);
}
if (template.quarantine_notification === "never"){
$('#quarantine_notification_never').prop('checked', true);
$('#quarantine_notification_hourly').prop('checked', false);
@@ -1954,6 +1972,15 @@ jQuery(function($){
data: 'private_comment',
defaultContent: ''
},
{
title: lang.internal,
data: 'internal',
defaultContent: '',
responsivePriority: 6,
render: function (data, type) {
return 1==data?'<i class="bi bi-check-lg"><span class="sorting-value">1</span></i>':0==data&&'<i class="bi bi-x-lg"><span class="sorting-value">0</span></i>';
}
},
{
title: lang.active,
data: 'active',

View File

@@ -324,6 +324,9 @@ if (isset($_GET['query'])) {
case "app-passwd":
process_add_return(app_passwd('add', $attr));
break;
case "mta-sts":
process_add_return(mailbox('add', 'mta_sts', $attr));
break;
// return no route found if no case is matched
default:
http_response_code(404);
@@ -2001,6 +2004,9 @@ if (isset($_GET['query'])) {
case "reset-password-notification":
process_edit_return(reset_password('edit_notification', $attr));
break;
case "mta-sts":
process_edit_return(mailbox('edit', 'mta_sts', array_merge(array('domains' => $items), $attr)));
break;
// return no route found if no case is matched
default:
http_response_code(404);

File diff suppressed because it is too large Load Diff

View File

@@ -557,4 +557,4 @@
"week": "Setmana",
"weeks": "Setmanes"
}
}
}

View File

@@ -25,7 +25,7 @@
"sogo_access": "Verwalten des SOGo-Zugriffsrechts erlauben",
"sogo_profile_reset": "SOGo-Profil zurücksetzen",
"spam_alias": "Temporäre E-Mail-Aliasse",
"spam_policy": "Blacklist/Whitelist",
"spam_policy": "Deny/Allowlist",
"spam_score": "Spam-Bewertung",
"syncjobs": "Sync Jobs",
"tls_policy": "Verschlüsselungsrichtlinie",
@@ -71,6 +71,8 @@
"goto_spam": "Nachrichten als <span class=\"text-danger\"><b>Spam</b></span> lernen",
"hostname": "Host",
"inactive": "Inaktiv",
"internal": "Intern",
"internal_info": "Interne Aliasse sind nur von der eigenen Domäne oder Alias-Domänen erreichbar.",
"kind": "Art",
"mailbox_quota_def": "Standard-Quota einer Mailbox",
"mailbox_quota_m": "Max. Speicherplatz pro Mailbox (MiB)",
@@ -147,7 +149,7 @@
"arrival_time": "Ankunftszeit (Serverzeit)",
"authed_user": "Auth. Benutzer",
"ays": "Soll der Vorgang wirklich ausgeführt werden?",
"ban_list_info": "Übersicht ausgesperrter Netzwerke: <b>Netzwerk (verbleibende Bannzeit) - [Aktionen]</b>.<br />IPs, die zum Entsperren eingereiht werden, verlassen die Liste aktiver Banns nach wenigen Sekunden.<br />Rote Labels sind Indikatoren für aktive Blacklist-Einträge.",
"ban_list_info": "Übersicht ausgesperrter Netzwerke: <b>Netzwerk (verbleibende Bannzeit) - [Aktionen]</b>.<br />IPs, die zum Entsperren eingereiht werden, verlassen die Liste aktiver Banns nach wenigen Sekunden.<br />Rote Labels sind Indikatoren für aktive Allowlist-Einträge.",
"change_logo": "Logo ändern",
"configuration": "Konfiguration",
"convert_html_to_text": "Konvertiere HTML zu reinem Text",
@@ -184,9 +186,9 @@
"excludes": "Diese Empfänger ausschließen",
"f2b_ban_time": "Bannzeit in Sekunden",
"f2b_ban_time_increment": "Bannzeit erhöht sich mit jedem Bann",
"f2b_blacklist": "Blacklist für Netzwerke und Hosts",
"f2b_blacklist": "Denyliste für Netzwerke und Hosts",
"f2b_filter": "Regex-Filter",
"f2b_list_info": "Ein Host oder Netzwerk auf der Blacklist wird immer eine Whitelist-Einheit überwiegen. <b>Die Aktualisierung der Liste dauert einige Sekunden.</b>",
"f2b_list_info": "Ein Host oder Netzwerk auf der Denyliste wird immer eine Allowlist-Einheit überwiegen. <b>Die Aktualisierung der Liste dauert einige Sekunden.</b>",
"f2b_manage_external": "Fail2Ban extern verwalten",
"f2b_manage_external_info": "Fail2ban wird die Banlist weiterhin pflegen, jedoch werden keine aktiven Regeln zum blockieren gesetzt. Die unten generierte Banlist, kann verwendet werden, um den Datenverkehr extern zu blockieren.",
"f2b_max_attempts": "Max. Versuche",
@@ -196,10 +198,10 @@
"f2b_parameters": "Fail2ban-Parameter",
"f2b_regex_info": "Berücksichtigte Logs: SOGo, Postfix, Dovecot, PHP-FPM.",
"f2b_retry_window": "Wiederholungen im Zeitraum von (s)",
"f2b_whitelist": "Whitelist für Netzwerke und Hosts",
"f2b_whitelist": "Allowliste für Netzwerke und Hosts",
"filter_table": "Tabelle filtern",
"force_sso_text": "Wenn ein externer OIDC-Provider konfiguriert ist, blendet diese Option die mailcow Loginform aus und zeigt nur den Single Sign-On-Button an.",
"force_sso": "mailcow Login deaktivieren und nur Single Sign-On anzeigen",
"force_sso_text": "Wenn ein externer OIDC-Provider konfiguriert ist, blendet diese Option die mailcow-Loginform aus und zeigt nur den Single-Sign-On-Button an.",
"force_sso": "mailcow-Login deaktivieren und nur Single Sign-On anzeigen",
"forwarding_hosts": "Weiterleitungs-Hosts",
"forwarding_hosts_add_hint": "Sie können entweder IPv4-/IPv6-Adressen, Netzwerke in CIDR-Notation, Hostnamen (die zu IP-Adressen aufgelöst werden), oder Domainnamen (die zu IP-Adressen aufgelöst werden, indem ihr SPF-Record abgefragt wird oder, in dessen Abwesenheit, ihre MX-Records) angeben.",
"forwarding_hosts_hint": "Eingehende Nachrichten werden von den hier gelisteten Hosts bedingungslos akzeptiert. Diese Hosts werden dann nicht mit DNSBLs abgeglichen oder Greylisting unterworfen. Von ihnen empfangener Spam wird nie abgelehnt, optional kann er aber in den Spam-Ordner einsortiert werden. Die übliche Verwendung für diese Funktion ist, um Mailserver anzugeben, auf denen eine Weiterleitung zu Ihrem mailcow-Server eingerichtet wurde.",
@@ -272,6 +274,7 @@
"message": "Nachricht",
"message_size": "Nachrichtengröße",
"nexthop": "Next Hop",
"needs_restart": "benötigt Neustart",
"no": "&#10005;",
"no_active_bans": "Keine aktiven Banns",
"no_new_rows": "Keine weiteren Zeilen vorhanden",
@@ -354,8 +357,8 @@
"rspamd_com_settings": "Ein Name wird automatisch generiert. Beispielinhalte zur Einsicht stehen nachstehend bereit. Siehe auch <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd docs</a>",
"rspamd_global_filters": "Globale Filter-Maps",
"rspamd_global_filters_agree": "Ich werde vorsichtig sein!",
"rspamd_global_filters_info": "Globale Filter-Maps steuern globales White- und Blacklisting dieses Servers.",
"rspamd_global_filters_regex": "Die akzeptierte Form für Einträge sind <b>ausschließlich</b> Regular Expressions.\r\n Trotz rudimentärer Überprüfung der Map, kann es zu fehlerhaften Einträgen kommen, die Rspamd im schlechtesten Fall mit unvorhersehbarer Funktionalität bestraft.<br>\r\n Das korrekte Format lautet \"/pattern/options\" (Beispiel: <code>/.+@domain\\.tld/i</code>).<br>\r\n Der Name der Map beschreibt die jeweilige Funktion.<br>\r\n Rspamd versucht die Maps umgehend aufzulösen. Bei Problemen sollte <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">Rspamd manuell neugestartet werden</a>.<br>Elemente auf Blacklists sind von der Quarantäne ausgeschlossen.",
"rspamd_global_filters_info": "Globale Filter-Maps steuern globales Allow- und Denylisting dieses Servers.",
"rspamd_global_filters_regex": "Die akzeptierte Form für Einträge sind <b>ausschließlich</b> Regular Expressions.\r\n Trotz rudimentärer Überprüfung der Map, kann es zu fehlerhaften Einträgen kommen, die Rspamd im schlechtesten Fall mit unvorhersehbarer Funktionalität bestraft.<br>\r\n Das korrekte Format lautet \"/pattern/options\" (Beispiel: <code>/.+@domain\\.tld/i</code>).<br>\r\n Der Name der Map beschreibt die jeweilige Funktion.<br>\r\n Rspamd versucht die Maps umgehend aufzulösen. Bei Problemen sollte <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">Rspamd manuell neugestartet werden</a>.<br>Elemente auf Denylisten sind von der Quarantäne ausgeschlossen.",
"rspamd_settings_map": "Rspamd-Settings-Map",
"sal_level": "Moo-Level",
"save": "Änderungen speichern",
@@ -407,7 +410,8 @@
"allowed_origins": "Access-Control-Allow-Origin",
"logo_dark_label": "Invertiert für den Darkmode",
"logo_normal_label": "Normal",
"user_link": "Nutzer-Link"
"user_link": "Nutzer-Link",
"filter": "Filter"
},
"danger": {
"access_denied": "Zugriff verweigert oder unvollständige/ungültige Daten",
@@ -481,10 +485,13 @@
"mailboxes_in_use": "Maximale Anzahl an Mailboxen muss größer oder gleich %d sein",
"malformed_username": "Benutzername hat ein falsches Format",
"map_content_empty": "Inhalt darf nicht leer sein",
"max_age_invalid": "Maximales Alter %s ist ungültig",
"max_alias_exceeded": "Anzahl an Alias-Adressen überschritten",
"max_mailbox_exceeded": "Anzahl an Mailboxen überschritten (%d von %d)",
"max_quota_in_use": "Mailbox-Speicherplatzlimit muss größer oder gleich %d MiB sein",
"maxquota_empty": "Max. Speicherplatz pro Mailbox darf nicht 0 sein.",
"mode_invalid": "Modus %s ist ungültig",
"mx_invalid": "MX-Eintrag %s ist ungültig",
"mysql_error": "MySQL-Fehler: %s",
"network_host_invalid": "Netzwerk oder Host ungültig: %s",
"next_hop_interferes": "%s verhindert das Hinzufügen von Next Hop %s",
@@ -544,10 +551,12 @@
"username_invalid": "Benutzername %s kann nicht verwendet werden",
"validity_missing": "Bitte geben Sie eine Gültigkeitsdauer an",
"value_missing": "Bitte alle Felder ausfüllen",
"version_invalid": "Version %s ist ungültig",
"yotp_verification_failed": "Yubico OTP-Verifizierung fehlgeschlagen: %s",
"template_exists": "Vorlage %s existiert bereits",
"template_id_invalid": "Vorlagen-ID %s ungültig",
"template_name_invalid": "Name der Vorlage ungültig"
"template_name_invalid": "Name der Vorlage ungültig",
"required_data_missing": "Die benötigten Daten: %s fehlen"
},
"datatables": {
"collapse_all": "Alle Einklappen",
@@ -683,6 +692,8 @@
"grant_types": "Grant-types",
"hostname": "Servername",
"inactive": "Inaktiv",
"internal": "Intern",
"internal_info": "Interne Aliasse sind nur von der eigenen Domäne oder Alias-Domänen erreichbar.",
"kind": "Art",
"last_modified": "Zuletzt geändert",
"lookup_mx": "Ziel mit MX vergleichen (Regex, etwa <code>.*\\.google\\.com</code>, um alle Ziele mit MX *google.com zu routen)",
@@ -701,6 +712,17 @@
"maxbytespersecond": "Max. Übertragungsrate in Bytes/s (0 für unlimitiert)",
"mbox_rl_info": "Dieses Limit wird auf den SASL Loginnamen angewendet und betrifft daher alle Absenderadressen, die der eingeloggte Benutzer verwendet. Bei Mailbox Ratelimit überwiegt ein Domain-weites Ratelimit.",
"mins_interval": "Intervall (min)",
"mta_sts": "MTA-STS",
"mta_sts_info": "<a href='https://de.wikipedia.org/wiki/STARTTLS#MTA-STS' target='_blank'>MTA-STS</a> ist ein Standard, der den E-Mail-Versand zwischen Mailservern zwingt, TLS mit gültigen Zertifikaten zu verwenden. <br>Er wird verwendet, wenn <a target='_blank' href='https://de.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities'>DANE</a> aufgrund fehlender oder nicht unterstützter DNSSEC nicht möglich ist.<br><b>Hinweis</b>: Wenn die empfangende Domain DANE mit DNSSEC unterstützt, wird DANE <b>immer</b> bevorzugt MTA-STS fungiert nur als Fallback.",
"mta_sts_version": "Version",
"mta_sts_version_info": "Definiert die Version des MTA-STS-Standards derzeit ist nur <code>STSv1</code> gültig.",
"mta_sts_mode": "Modus",
"mta_sts_mode_info": "Es gibt drei Modi zur Auswahl:<ul><li><em>testing</em> Die Richtlinie wird nur überwacht, Verstöße haben keine Auswirkungen.</li><li><em>enforce</em> Die Richtlinie wird strikt durchgesetzt, Verbindungen ohne gültiges TLS werden abgelehnt.</li><li><em>none</em> Die Richtlinie wird veröffentlicht, aber nicht angewendet.</li></ul>",
"mta_sts_max_age": "Maximales Alter",
"mta_sts_max_age_info": "Zeit in Sekunden, die empfangende Mailserver diese Richtlinie zwischenspeichern dürfen, bevor sie erneut abgerufen wird.",
"mta_sts_mx": "MX-Server",
"mta_sts_mx_info": "Erlaubt das Senden nur an explizit aufgeführte Mailserver-Hostnamen; der sendende MTA überprüft, ob der DNS-MX-Hostname mit der Richtlinienliste übereinstimmt, und erlaubt die Zustellung nur mit einem gültigen TLS-Zertifikat (schützt vor MITM).",
"mta_sts_mx_notice": "Es können mehrere MX-Server angegeben werden (durch Kommas getrennt).",
"multiple_bookings": "Mehrfaches Buchen",
"nexthop": "Next Hop",
"none_inherit": "Keine Auswahl / Erben",
@@ -747,7 +769,7 @@
"sogo_visible_info": "Diese Option hat lediglich Einfluss auf Objekte, die in SOGo darstellbar sind (geteilte oder nicht-geteilte Alias-Adressen mit dem Ziel mindestens einer lokalen Mailbox).",
"spam_alias": "Anpassen temporärer Alias-Adressen",
"spam_filter": "Spamfilter",
"spam_policy": "Hinzufügen und Entfernen von Einträgen in White- und Blacklists",
"spam_policy": "Hinzufügen und Entfernen von Einträgen in Allow- und Denylisten",
"spam_score": "Einen benutzerdefiniterten Spam-Score festlegen",
"subfolder2": "Ziel-Ordner<br><small>(leer = kein Unterordner)</small>",
"syncjob": "Sync-Job bearbeiten",
@@ -829,7 +851,8 @@
"password": "Passwort",
"reset_password": "Passwort zurücksetzen",
"request_reset_password": "Passwortänderung anfordern",
"username": "Benutzername"
"username": "Benutzername",
"email": "E-Mail-Adresse"
},
"mailbox": {
"action": "Aktion",
@@ -850,7 +873,7 @@
"add_tls_policy_map": "TLS-Richtlinieneintrag hinzufügen",
"address_rewriting": "Adressumschreibung",
"alias": "Alias",
"alias_domain_alias_hint": "Alias-Adressen werden <b>nicht</b> automatisch auch auf Domain-Alias Adressen angewendet. Eine Alias-Adresse <code>mein-alias@domain</code> bildet demnach <b>nicht</b> die Adresse <code>mein-alias@alias-domain</code> ab.<br>E-Mail-Weiterleitungen an externe Postfächer sollten über Sieve (SOGo Weiterleitung oder im Reiter \"Filter\") angelegt werden. Der Button \"Alias über Alias-Domains expandieren\" erstellt fehlende Alias-Adressen in Alias-Domains.",
"alias_domain_alias_hint": "Alias-Adressen werden <b>nicht</b> automatisch auch auf Domain-Alias Adressen angewendet. Eine Alias-Adresse <code>mein-alias@domain</code> bildet demnach <b>nicht</b> die Adresse <code>mein-alias@alias-domain</code> ab.<br>E-Mail-Weiterleitungen an externe Postfächer sollten über Sieve (SOGo Weiterleitung oder im Reiter Filter) angelegt werden. Der Button Alias über Alias-Domains expandieren erstellt fehlende Alias-Adressen in Alias-Domains.",
"alias_domain_backupmx": "Alias-Domain für Relay-Domain inaktiv",
"aliases": "Aliasse",
"allow_from_smtp": "Nur folgende IPs für <b>SMTP</b> erlauben",
@@ -904,6 +927,7 @@
"in_use": "Prozentualer Gebrauch",
"inactive": "Inaktiv",
"insert_preset": "Beispiel \"%s\" laden",
"internal": "Intern",
"kind": "Art",
"last_mail_login": "Letzter Mail-Login",
"last_modified": "Zuletzt geändert",
@@ -941,7 +965,7 @@
"recipient_map_new": "Neuer Empfänger",
"recipient_map_new_info": "Der neue Empfänger muss eine E-Mail-Adresse oder ein Domainname sein.",
"recipient_map_old": "Original-Empfänger",
"recipient_map_old_info": "Der originale Empfänger muss eine E-Mail-Adresse oder ein Domainname sein.",
"recipient_map_old_info": "Der originäre Empfänger muss eine E-Mail-Adresse oder ein Domainname sein.",
"recipient_maps": "Empfängerumschreibungen",
"relay_all": "Alle Empfänger-Adressen relayen",
"relay_unknown": "Unbekannte Mailboxen relayen",
@@ -1037,7 +1061,7 @@
"notified": "Benachrichtigt",
"qhandler_success": "Aktion wurde an das System übergeben. Sie dürfen dieses Fenster nun schließen.",
"qid": "Rspamd QID",
"qinfo": "Das Quarantänesystem speichert abgelehnte Nachrichten in der Datenbank (dem Sender wird <em>nicht</em> signalisiert, dass seine E-Mail zugestellt wurde) als auch diese, die als Kopie in den Junk-Ordner der jeweiligen Mailbox zugestellt wurden.\r\n <br>\"Als Spam lernen und löschen\" lernt Nachrichten nach bayesscher Statistik als Spam und erstellt Fuzzy Hashes ausgehend von der jeweiligen Nachricht, um ähnliche Inhalte zukünftig zu unterbinden.\r\n <br>Der Prozess des Lernens kann abhängig vom System zeitintensiv sein.<br>Auf Blacklists vorkommende Elemente sind von der Quarantäne ausgeschlossen.",
"qinfo": "Das Quarantänesystem speichert abgelehnte Nachrichten in der Datenbank (dem Sender wird <em>nicht</em> signalisiert, dass seine E-Mail zugestellt wurde) als auch diese, die als Kopie in den Junk-Ordner der jeweiligen Mailbox zugestellt wurden.\r\n <br>\"Als Spam lernen und löschen\" lernt Nachrichten nach bayesscher Statistik als Spam und erstellt Fuzzy Hashes ausgehend von der jeweiligen Nachricht, um ähnliche Inhalte zukünftig zu unterbinden.\r\n <br>Der Prozess des Lernens kann abhängig vom System zeitintensiv sein.<br>Auf Denylisten vorkommende Elemente sind von der Quarantäne ausgeschlossen.",
"qitem": "Quarantäneeintrag",
"quarantine": "Quarantäne",
"quick_actions": "Aktionen",
@@ -1246,7 +1270,7 @@
"delete_ays": "Soll der Löschvorgang wirklich ausgeführt werden?",
"direct_aliases": "Direkte Alias-Adressen",
"direct_aliases_desc": "Nur direkte Alias-Adressen werden für benutzerdefinierte Einstellungen berücksichtigt.",
"direct_protocol_access": "Der Hauptbenutzer hat <b>direkten, externen Zugriff</b> auf folgende Protokolle und Anwendungen. Diese Einstellung wird vom Administrator gesteuert. App-Passwörter können verwendet werden, um individuelle Zugänge für Protokolle und Anwendungen zu erstellen.<br>Der Button \"Webmail\" kann unabhängig der Einstellung immer verwendet werden.",
"direct_protocol_access": "Der Hauptbenutzer hat <b>direkten, externen Zugriff</b> auf folgende Protokolle und Anwendungen. Diese Einstellung wird vom Administrator gesteuert. App-Passwörter können verwendet werden, um individuelle Zugänge für Protokolle und Anwendungen zu erstellen.<br>Der Button Webmail kann unabhängig der Einstellung immer verwendet werden.",
"eas_reset": "ActiveSync-Geräte-Cache zurücksetzen",
"eas_reset_help": "In vielen Fällen kann ein ActiveSync-Profil durch das Zurücksetzen des Caches repariert werden.<br><b>Vorsicht:</b> Alle Elemente werden erneut heruntergeladen!",
"eas_reset_now": "Jetzt zurücksetzen",
@@ -1326,8 +1350,8 @@
"spam_score_reset": "Auf Server-Standard zurücksetzen",
"spamfilter": "Spamfilter",
"spamfilter_behavior": "Bewertung",
"spamfilter_bl": "Blacklist",
"spamfilter_bl_desc": "Für E-Mail-Adressen, die vom Spamfilter <b>immer</b> als Spam erfasst und abgelehnt werden. Die Quarantäne-Funktion ist für diese Nachrichten deaktiviert. Die Verwendung von Wildcards ist gestattet. Ein Filter funktioniert lediglich für direkte nicht-\"Catch All\" Alias-Adressen (Alias-Adressen mit lediglich einer Mailbox als Ziel-Adresse) sowie die Mailbox-Adresse selbst.",
"spamfilter_bl": "Denyliste",
"spamfilter_bl_desc": "Für E-Mail-Adressen, die vom Spamfilter <b>immer</b> als Spam erfasst und abgelehnt werden. Die Quarantäne-Funktion ist für diese Nachrichten <b>deaktiviert</b>. Die Verwendung von Wildcards ist gestattet. Ein Filter funktioniert lediglich für direkte Nicht-Catch-All“-Alias-Adressen (Alias-Adressen mit lediglich einer Mailbox als Ziel-Adresse) sowie die Mailbox-Adresse selbst.",
"spamfilter_default_score": "Standardwert",
"spamfilter_green": "Grün: Die Nachricht ist kein Spam",
"spamfilter_hint": "Der erste Wert beschreibt den \"low spam score\", der zweite Wert den \"high spam score\".",
@@ -1338,8 +1362,8 @@
"spamfilter_table_empty": "Keine Einträge vorhanden",
"spamfilter_table_remove": "Entfernen",
"spamfilter_table_rule": "Regel",
"spamfilter_wl": "Whitelist",
"spamfilter_wl_desc": "Für E-Mail-Adressen, die vom Spamfilter <b>nicht</b> erfasst werden sollen. Die Verwendung von Wildcards ist gestattet. Ein Filter funktioniert lediglich für direkte nicht-\"Catch All\" Alias-Adressen (Alias-Adressen mit lediglich einer Mailbox als Ziel-Adresse) sowie die Mailbox-Adresse selbst.",
"spamfilter_wl": "Allowliste",
"spamfilter_wl_desc": "Für E-Mail-Adressen, die vom Spamfilter <b>nicht</b> erfasst werden sollen. Die Verwendung von Wildcards ist gestattet. Ein Filter funktioniert lediglich für direkte Nicht-Catch-All“-Alias-Adressen (Alias-Adressen mit lediglich einer Mailbox als Ziel-Adresse) sowie die Mailbox-Adresse selbst.",
"spamfilter_yellow": "Gelb: Die Nachricht ist vielleicht Spam, wird als Spam markiert und in den Junk-Ordner verschoben",
"status": "Status",
"sync_jobs": "Sync Jobs",

View File

@@ -25,7 +25,7 @@
"sogo_access": "Allow management of SOGo access",
"sogo_profile_reset": "Reset SOGo profile",
"spam_alias": "Temporary aliases",
"spam_policy": "Blacklist/Whitelist",
"spam_policy": "Denylist/Allowlist",
"spam_score": "Spam score",
"syncjobs": "Sync jobs",
"tls_policy": "TLS policy",
@@ -71,6 +71,8 @@
"goto_spam": "Learn as <span class=\"text-danger\"><b>spam</b></span>",
"hostname": "Host",
"inactive": "Inactive",
"internal": "Internal",
"internal_info": "Internal aliases are only accessible from the own domain or alias domains.",
"kind": "Kind",
"mailbox_quota_def": "Default mailbox quota",
"mailbox_quota_m": "Max. quota per mailbox (MiB)",
@@ -151,7 +153,7 @@
"arrival_time": "Arrival time (server time)",
"authed_user": "Auth. user",
"ays": "Are you sure you want to proceed?",
"ban_list_info": "See a list of banned IPs below: <b>network (remaining ban time) - [actions]</b>.<br />IPs queued to be unbanned will be removed from the active ban list within a few seconds.<br />Red labels indicate active permanent bans by blacklisting.",
"ban_list_info": "See a list of banned IPs below: <b>network (remaining ban time) - [actions]</b>.<br />IPs queued to be unbanned will be removed from the active ban list within a few seconds.<br />Red labels indicate active permanent bans by denylisting.",
"change_logo": "Change logo",
"logo_normal_label": "Normal",
"logo_dark_label": "Inverted for dark mode",
@@ -190,9 +192,9 @@
"excludes": "Excludes these recipients",
"f2b_ban_time": "Ban time (s)",
"f2b_ban_time_increment": "Ban time is incremented with each ban",
"f2b_blacklist": "Blacklisted networks/hosts",
"f2b_blacklist": "Denylisted networks/hosts",
"f2b_filter": "Regex filters",
"f2b_list_info": "A blacklisted host or network will always outweigh a whitelist entity. <b>List updates will take a few seconds to be applied.</b>",
"f2b_list_info": "A denylisted host or network will always outweigh a allowlist entity. <b>List updates will take a few seconds to be applied.</b>",
"f2b_manage_external": "Manage Fail2Ban externally",
"f2b_manage_external_info": "Fail2ban will still maintain the banlist, but it will not actively set rules to block traffic. Use the generated banlist below to externally block the traffic.",
"f2b_max_attempts": "Max. attempts",
@@ -202,7 +204,7 @@
"f2b_parameters": "Fail2ban parameters",
"f2b_regex_info": "Logs taken into consideration: SOGo, Postfix, Dovecot, PHP-FPM.",
"f2b_retry_window": "Retry window (s) for max. attempts",
"f2b_whitelist": "Whitelisted networks/hosts",
"f2b_whitelist": "Allowlisted networks/hosts",
"filter": "Filter",
"filter_table": "Filter table",
"force_sso_text": "If an external OIDC provider is configured, this option hides the default mailcow login forms and only shows the Single Sign-On button",
@@ -279,6 +281,7 @@
"message": "Message",
"message_size": "Message size",
"nexthop": "Next hop",
"needs_restart": "needs restart",
"no": "&#10005;",
"no_active_bans": "No active bans",
"no_new_rows": "No further rows available",
@@ -364,8 +367,8 @@
"rspamd_com_settings": "A setting name will be auto-generated, please see the example presets below. For more details see <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd docs</a>",
"rspamd_global_filters": "Global filter maps",
"rspamd_global_filters_agree": "I will be careful!",
"rspamd_global_filters_info": "Global filter maps contain different kind of global black and whitelists.",
"rspamd_global_filters_regex": "Their names explain their purpose. All content must contain valid regular expression in the format of \"/pattern/options\" (e.g. <code>/.+@domain\\.tld/i</code>).<br>\r\n Although rudimentary checks are being executed on each line of regex, Rspamds functionality can be broken, if it fails to read the syntax correctly.<br>\r\n Rspamd will try to read the map content when changed. If you experience problems, <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">restart Rspamd</a> to enforce a map reload.<br>Blacklisted elements are excluded from quarantine.",
"rspamd_global_filters_info": "Global filter maps contain different kind of global deny and allowlists.",
"rspamd_global_filters_regex": "Their names explain their purpose. All content must contain valid regular expression in the format of \"/pattern/options\" (e.g. <code>/.+@domain\\.tld/i</code>).<br>\r\n Although rudimentary checks are being executed on each line of regex, Rspamds functionality can be broken, if it fails to read the syntax correctly.<br>\r\n Rspamd will try to read the map content when changed. If you experience problems, <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">restart Rspamd</a> to enforce a map reload.<br>Denylisted elements are excluded from quarantine.",
"rspamd_settings_map": "Rspamd settings map",
"sal_level": "Moo level",
"save": "Save changes",
@@ -482,10 +485,13 @@
"mailboxes_in_use": "Max. mailboxes must be greater or equal to %d",
"malformed_username": "Malformed username",
"map_content_empty": "Map content cannot be empty",
"max_age_invalid": "Max age %s is invalid",
"max_alias_exceeded": "Max. aliases exceeded",
"max_mailbox_exceeded": "Max. mailboxes exceeded (%d of %d)",
"max_quota_in_use": "Mailbox quota must be greater or equal to %d MiB",
"maxquota_empty": "Max. quota per mailbox must not be 0.",
"mode_invalid": "Mode %s is invalid",
"mx_invalid": "MX record %s is invalid",
"mysql_error": "MySQL error: %s",
"network_host_invalid": "Invalid network or host: %s",
"next_hop_interferes": "%s interferes with nexthop %s",
@@ -549,6 +555,7 @@
"username_invalid": "Username %s cannot be used",
"validity_missing": "Please assign a period of validity",
"value_missing": "Please provide all values",
"version_invalid": "Version %s is invalid",
"yotp_verification_failed": "Yubico OTP verification failed: %s"
},
"datatables": {
@@ -685,6 +692,8 @@
"grant_types": "Grant types",
"hostname": "Hostname",
"inactive": "Inactive",
"internal": "Internal",
"internal_info": "Internal aliases are only accessible from the own domain or alias domains.",
"kind": "Kind",
"last_modified": "Last modified",
"lookup_mx": "Destination is a regular expression to match against MX name (<code>.*\\.google\\.com</code> to route all mail targeted to a MX ending in google.com over this hop)",
@@ -703,6 +712,17 @@
"maxbytespersecond": "Max. bytes per second <br><small>(0 = unlimited)</small>",
"mbox_rl_info": "This rate limit is applied on the SASL login name, it matches any \"from\" address used by the logged-in user. A mailbox rate limit overrides a domain-wide rate limit.",
"mins_interval": "Interval (min)",
"mta_sts": "MTA-STS",
"mta_sts_info": "<a href='https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_MTA_Strict_Transport_Security' target='_blank'>MTA-STS</a> is a standard that enforces email delivery between mail servers to use TLS with valid certificates. <br>It is used when <a target='_blank' href='https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities'>DANE</a> is not possible due to missing or unsupported DNSSEC.<br><b>Note</b>: If the receiving domain supports DANE with DNSSEC, DANE is <b>always</b> preferred MTA-STS only acts as a fallback.",
"mta_sts_version": "Version",
"mta_sts_version_info": "Defines the version of the MTA-STS standard currently only <code>STSv1</code> is valid.",
"mta_sts_mode": "Mode",
"mta_sts_mode_info": "There are three modes to choose from:<ul><li><em>testing</em> policy is only monitored, violations have no impact.</li><li><em>enforce</em> policy is strictly enforced, connections without valid TLS are rejected.</li><li><em>none</em> policy is published but not applied.</li></ul>",
"mta_sts_max_age": "Max age",
"mta_sts_max_age_info": "Time in seconds that receiving mail servers may cache this policy until refetching.",
"mta_sts_mx": "MX server",
"mta_sts_mx_info": "Allows sending only to explicitly listed mail server hostnames; the sending MTA checks if the DNS MX hostname matches the policy list, and only allows delivery with a valid TLS certificate (guards against MITM).",
"mta_sts_mx_notice": "Multiple MX servers can be specified (separated by commas).",
"multiple_bookings": "Multiple bookings",
"none_inherit": "None / Inherit",
"nexthop": "Next hop",
@@ -750,7 +770,7 @@
"sogo_visible_info": "This option only affects objects, that can be displayed in SOGo (shared or non-shared alias addresses pointing to at least one local mailbox). If hidden, an alias will not appear as selectable sender in SOGo.",
"spam_alias": "Create or change time limited alias addresses",
"spam_filter": "Spam filter",
"spam_policy": "Add or remove items to white-/blacklist",
"spam_policy": "Add or remove items to allow-/denylist",
"spam_score": "Set a custom spam score",
"subfolder2": "Sync into subfolder on destination<br><small>(empty = do not use subfolder)</small>",
"syncjob": "Edit sync job",
@@ -831,7 +851,8 @@
"password": "Password",
"reset_password": "Reset Password",
"request_reset_password": "Request password change",
"username": "Username"
"username": "Username",
"email": "Email address"
},
"mailbox": {
"action": "Action",
@@ -911,6 +932,7 @@
"in_use": "In use (%)",
"inactive": "Inactive",
"insert_preset": "Insert example preset \"%s\"",
"internal": "Internal",
"kind": "Kind",
"last_mail_login": "Last mail login",
"last_modified": "Last modified",
@@ -1039,7 +1061,7 @@
"notified": "Notified",
"qhandler_success": "Request successfully sent to the system. You can now close the window.",
"qid": "Rspamd QID",
"qinfo": "The quarantine system will save rejected mail to the database (the sender will <em>not</em> be given the impression of a delivered mail) as well as mail, that is delivered as copy into the Junk folder of a mailbox.\r\n <br>\"Learn as spam and delete\" will learn a message as spam via Bayesian theorem and also calculate fuzzy hashes to deny similar messages in the future.\r\n <br>Please be aware that learning multiple messages can be - depending on your system - time consuming.<br>Blacklisted elements are excluded from the quarantine.",
"qinfo": "The quarantine system will save rejected mail to the database (the sender will <em>not</em> be given the impression of a delivered mail) as well as mail, that is delivered as copy into the Junk folder of a mailbox.\r\n <br>\"Learn as spam and delete\" will learn a message as spam via Bayesian theorem and also calculate fuzzy hashes to deny similar messages in the future.\r\n <br>Please be aware that learning multiple messages can be - depending on your system - time consuming.<br>Denylisted elements are excluded from the quarantine.",
"qitem": "Quarantine item",
"quarantine": "Quarantine",
"quick_actions": "Actions",
@@ -1337,8 +1359,8 @@
"spam_score_reset": "Reset to server default",
"spamfilter": "Spam filter",
"spamfilter_behavior": "Rating",
"spamfilter_bl": "Blacklist",
"spamfilter_bl_desc": "Blacklisted email addresses to <b>always</b> classify as spam and reject. Rejected mail will <b>not</b> be copied to quarantine. Wildcards may be used. A filter is only applied to direct aliases (aliases with a single target mailbox) excluding catch-all aliases and a mailbox itself.",
"spamfilter_bl": "Denylist",
"spamfilter_bl_desc": "Denylisted email addresses to <b>always</b> classify as spam and reject. Rejected mail will <b>not</b> be copied to quarantine. Wildcards may be used. A filter is only applied to direct aliases (aliases with a single target mailbox) excluding catch-all aliases and a mailbox itself.",
"spamfilter_default_score": "Default values",
"spamfilter_green": "Green: this message is not spam",
"spamfilter_hint": "The first value describes the \"low spam score\", the second represents the \"high spam score\".",
@@ -1349,8 +1371,8 @@
"spamfilter_table_empty": "No data to display",
"spamfilter_table_remove": "remove",
"spamfilter_table_rule": "Rule",
"spamfilter_wl": "Whitelist",
"spamfilter_wl_desc": "Whitelisted email addresses are programmed to <b>never</b> classify as spam. Wildcards may be used. A filter is only applied to direct aliases (aliases with a single target mailbox) excluding catch-all aliases and a mailbox itself.",
"spamfilter_wl": "Allowlist",
"spamfilter_wl_desc": "Allowlisted email addresses are programmed to <b>never</b> classify as spam. Wildcards may be used. A filter is only applied to direct aliases (aliases with a single target mailbox) excluding catch-all aliases and a mailbox itself.",
"spamfilter_yellow": "Yellow: this message may be spam, will be tagged as spam and moved to your junk folder",
"status": "Status",
"sync_jobs": "Sync jobs",

View File

@@ -10,11 +10,11 @@
"quarantine": "Acciones de cuarentena",
"quarantine_attachments": "Archivos ajuntos en cuarentena",
"quarantine_notification": "Notificaciones de cuarentena",
"ratelimit": "Rate limit",
"ratelimit": "Límite de peticiones",
"recipient_maps": "Rutas del destinatario",
"sogo_profile_reset": "Resetear perfil SOGo",
"spam_alias": "Aliases temporales",
"spam_policy": "Lista blanca/negra",
"spam_policy": "Lista de bloqueo/desbloqueo",
"spam_score": "Puntuación de spam",
"syncjobs": "Trabajos de sincronización",
"tls_policy": "Póliza de TLS",
@@ -25,8 +25,10 @@
"quarantine_category": "Cambiar categoría de las notificaciones de cuarentena",
"domain_relayhost": "Cambiar relayhost por un dominio",
"extend_sender_acl": "Permitir extender la ACL del remitente por direcciones externas",
"pw_reset": "Permitir el reset de la contraseña del usario mailcow",
"sogo_access": "Permitir la gestión del acceso a SOGo"
"pw_reset": "Permitir el restablecimiento de la contraseña del usuario mailcow",
"sogo_access": "Permitir la gestión del acceso a SOGo",
"mailbox_relayhost": "Cambiar el host de reenvío para un buzón",
"smtp_ip_access": "Cambiar hosts permitidos para SMTP"
},
"add": {
"activate_filter_warn": "Todos los demás filtros se desactivarán cuando este filtro se active.",
@@ -34,7 +36,7 @@
"add": "Agregar",
"add_domain_only": "Agregar dominio solamente",
"add_domain_restart": "Agregar dominio y reiniciar SOGo",
"alias_address": "Dirección(es) alias:",
"alias_address": "Dirección(es) alias",
"alias_address_info": "<small>Dirección(es) de correo completa(s) ó @dominio.com, para atrapar todos los mensajes para un dominio (separado por coma). <b>Dominios que existan en mailcow solamente</b>.</small>",
"alias_domain": "Dominio alias",
"alias_domain_info": "<small>Nombres de dominio válidos solamente (separado por coma).</small>",
@@ -45,13 +47,13 @@
"delete1": "Eliminar de la fuente cuando se complete",
"delete2": "Eliminar mensajes en el destino que no están en la fuente",
"delete2duplicates": "Eliminar duplicados en el destino",
"description": "Descripción:",
"description": "Descripción",
"destination": "Destino",
"domain": "Dominio",
"domain_quota_m": "Cuota total del dominio (MiB):",
"domain_quota_m": "Cuota total del dominio (MiB)",
"enc_method": "Método de cifrado",
"exclude": "Excluir objectos (regex)",
"full_name": "Nombre completo:",
"full_name": "Nombre completo",
"gal": "Lista global de direcciones (GAL)",
"gal_info": "El GAL contiene todos los objetos de un dominio y no puede ser editado por ningún usuario. Falta información de disponibilidad en SOGo, si está desactivada. <b>Reinicia SOGo para aplicar los cambios.</b>",
"generate": "Generar",
@@ -61,20 +63,20 @@
"hostname": "Host",
"kind": "Tipo",
"mailbox_quota_def": "Cuota de buzón predeterminada",
"mailbox_quota_m": "Máx. cuota por buzón (MiB):",
"mailbox_username": "Nombre de usuario (parte izquierda de una dirección de correo):",
"max_aliases": "Máx. alias posibles:",
"max_mailboxes": "Máx. buzones posibles:",
"mailbox_quota_m": "Máx. cuota por buzón (MiB)",
"mailbox_username": "Nombre de usuario (parte izquierda de una dirección de correo)",
"max_aliases": "Máx. alias posibles",
"max_mailboxes": "Máx. buzones posibles",
"mins_interval": "Intervalo de sondeo (minutos)",
"multiple_bookings": "Múltiples reservas",
"nexthop": "Siguiente destino",
"password": "Constraseña:",
"password_repeat": "Confirmación de contraseña (repetir):",
"password": "Contraseña",
"password_repeat": "Confirmación de contraseña (repetir)",
"port": "Puerto",
"post_domain_add": "<b>Nota:</b> Necesitarás reiniciar el contenedor del servicio SOGo despues de agregar un nuevo dominio",
"quota_mb": "Cuota (MiB):",
"post_domain_add": "Es necesario reiniciar el contenedor del servicio SOGo, \"sogo-mailcow\", tras agregar un nuevo dominio.<br><br>Además, la configuración DNS de los dominios debería ser comprobada. En cuanto la configuración DNS se apruebe, reinicie \"acme-mailcow\" para generar automáticamente certificados para su nuevo dominio (autoconfig.&lt;dominio&gt;, autodiscover.&lt;dominio&gt;).<br>Este paso es opcional y se reintentará cada 24 horas.",
"quota_mb": "Cuota (MiB)",
"relay_all": "Retransmitir todos los destinatarios",
"relay_all_info": "<small>Si eliges <b>no</b> retransmitir a todos los destinatarios, necesitas agregar un buzón \"ciego\" por cada destinatario que debe ser retransmitido.</small>",
"relay_all_info": "↪ Si se elige <b>no</b> retransmitir todos los destinatarios, será necesario agregar un buzón \"ciego\" por cada destinatario que deba ser retransmitido.",
"relay_domain": "Retransmitir este dominio",
"select": "Por favor selecciona...",
"select_domain": "Por favor elige un dominio primero",
@@ -83,7 +85,7 @@
"skipcrossduplicates": "Omitir mensajes duplicados en carpetas (orden de llegada)",
"subscribeall": "Suscribirse a todas las carpetas",
"syncjob": "Añadir trabajo de sincronización",
"syncjob_hint": "Ten en cuenta que las contraseñas deben guardarse en texto sin cifrado",
"syncjob_hint": "Tenga en cuenta que las contraseñas deben guardarse en texto plano sin cifrar",
"target_address": "Direcciones destino:",
"target_address_info": "<small>Dirección(es) de correo completa(s) (separado por coma).</small>",
"target_domain": "Dominio destino:",
@@ -100,7 +102,13 @@
"comment_info": "Los comentarios privados no son visibles al usuario, mientras que los comentarios públicos aparecerán sobre la información general del usuario",
"dry": "Simular la sincronización",
"private_comment": "Comentario privado",
"app_passwd_protocols": "Protocolos autorizados para la contraseña de la aplicación"
"app_passwd_protocols": "Protocolos autorizados para la contraseña de la aplicación",
"relay_transport_info": "<div class=\"label label-info\">Información</div> Puede definir mapas de transporte para un destino personalizado para este dominio. En caso de no definirlo, se realizará una búsqueda MX.",
"bcc_dest_format": "El destino del CCO debe ser una única dirección de correo electrónico válida.<br>Si necesita enviar una copia a varias direcciones, cree un alias y utilícelo aquí.",
"domain_matches_hostname": "El dominio %s coincide con el nombre de host",
"relay_unknown_only": "Reenviar sólo los buzones no existentes. Los buzones existentes se entregarán localmente.",
"relayhost_wrapped_tls_info": "Por favor, no utilice puertos con TLS (habitualmente, el puerto 465). <br>Utilice cualquier puerto no cifrado y emita STARTTLS. Se puede crear una política para imponer TLS en \"TLS policy maps\".",
"tags": "Etiquetas"
},
"admin": {
"access": "Acceso",
@@ -129,7 +137,7 @@
"app_name": "Nombre de la app",
"apps_name": "Nombre \"mailcow Apps\"",
"arrival_time": "Tiempo de llegada (hora del servidor)",
"ban_list_info": "Lista de IPs bloqueadas: <b>red (tiempo de prohibición restante) - [acciones]</b>.<br />Las IPs en cola para ser desbloqueadas se eliminarán de la lista de bloqueos en unos pocos segundos.<br />Las etiquetas rojas indican bloqueos permanentes mediante la inclusión en la lista negra.",
"ban_list_info": "Lista de direcciones IP bloqueadas: <b>red (tiempo de prohibición restante) - [acciones]</b>.<br />Las direcciones IP en cola para ser desbloqueadas se eliminarán de la lista de bloqueos en unos segundos.<br />Las etiquetas rojas indican bloqueos permanentes por inclusión en la lista de bloqueo.",
"change_logo": "Cambiar logo",
"configuration": "Configuración",
"credentials_transport_warning": "<b>Advertencia</b>: al agregar una nueva entrada de ruta de transporte se actualizarán las credenciales para todas las entradas con una columna de \"siguiente destino\" coincidente.",
@@ -157,15 +165,15 @@
"excludes": "Excluye a estos destinatarios",
"f2b_ban_time": "Tiempo de restricción (s)",
"f2b_ban_time_increment": "Tiempo de restricción se incrementa con cada restricción",
"f2b_blacklist": "Redes y hosts en lista negra",
"f2b_list_info": "Un host o red en lista negra siempre superará a una entidad de la lista blanca. <b>Las actualizaciones de la lista tardarán unos segundos en aplicarse.</b>",
"f2b_blacklist": "Redes y hosts en lista de bloqueo",
"f2b_list_info": "Un host o red en lista de bloqueo siempre tendrá prioridad sobre una entidad de la lista de desbloqueo. <b>Las actualizaciones de la lista tardarán unos segundos en aplicarse.</b>",
"f2b_max_attempts": "Max num. de intentos",
"f2b_max_ban_time": "Max tiempo de restricción (s)",
"f2b_netban_ipv4": "Tamaño de subred IPv4 para aplicar la restricción (8-32)",
"f2b_netban_ipv6": "Tamaño de subred IPv6 para aplicar la restricción (8-128)",
"f2b_parameters": "Parametros Fail2ban",
"f2b_retry_window": "Ventana de tiempo entre reintentos",
"f2b_whitelist": "Redes y hosts en lista blanca",
"f2b_whitelist": "Redes y hosts en lista de desbloqueo",
"filter_table": "Filtrar tabla",
"forwarding_hosts": "Hosts de reenvío",
"forwarding_hosts_add_hint": "Se puede especificar direcciones IPv4 / IPv6, redes en notación CIDR, nombres de host (que se resolverán en direcciones IP) o dominios (que se resolverán en direcciones IP consultando registros SPF o, en su defecto, registros MX)",
@@ -253,7 +261,146 @@
"unban_pending": "Desbloqueo pendiente",
"unchanged_if_empty": "Si no hay cambios déjalo en blanco",
"upload": "Cargar",
"username": "Nombre de usuario"
"username": "Nombre de usuario",
"force_sso_text": "Si se configura un proveedor OIDC externo, esta opción oculta los formularios por defecto de inicio de sesión y muestra solamente el botón de inicio de sesión único",
"admin_quicklink": "Ocultar enlace rápido a página de inicio de sesión para administradores",
"iam_default_template_description": "Si no se asigna una plantilla a un usuario, se utilizará la plantilla por defecto para crear el buzón, pero no para actualizarlo.",
"reset_password_vars": "<code>{{link}}</code> El enlace generado para el restablecimiento de contraseña<br><code>{{username}}</code> El buzón del usuario que ha solicitado el restablecimiento de contraseña<br><code>{{username2}}</code> La dirección del buzón de recuperación de contraseña<br><code>{{date}}</code> La fecha en que se realizó la solicitud de restablecimiento de contraseña<br><code>{{token_lifetime}}</code> El periodo de vigencia del token en minutos<br><code>{{hostname}}</code> El servidor Mailcow",
"api_info": "La API es un trabajo en curso. La documentación se puede encontrar en <a href=\"/api\">/api</a>",
"iam_description": "Configurar un proveedor de autenticación externo<br>Los buzones de usuario se crearán automáticamente la primera vez que se inicie sesión, siempre que se hayan configurado las equivalencias de atributos",
"ui_header_announcement_help": "El anuncio será visible para todos los usuarios conectados y también en la pantalla de inicio de sesión.",
"html": "HTML",
"oauth2_redirect_uri": "URI de redirección",
"quarantine_bcc": "Remitir una copia de todas las notificaciones (CCO) a este destinatario: <br><small>Dejar en blanco para desactivar. <b>Correo sin firmar y sin comprobar. Debe entregarse solo internamente.</b></small>",
"quarantine_redirect": "<b>Redirigir todas las notificaciones</b> a este destinatario:<br><small>Dejar en blanco para desactivar. <b>Correo sin firmar y sin comprobar. Debe entregarse sólo internamente.</b></small>",
"iam_authorize_url": "Endpoint de autorización",
"sal_level": "Nivel de Moo",
"ui_footer": "Pie de página (se permite HTML)",
"is_mx_based": "Basado en MX",
"password_reset_tmpl_text": "Plantilla de texto",
"password_length": "Longitud de la contraseña",
"quicklink_text": "Mostrar u ocultar enlaces rápidos a otras páginas de inicio bajo el formulario de inicio de sesión",
"password_policy_lowerupper": "Debe contener caracteres en minúsculas y mayúsculas",
"rspamd_global_filters_regex": "Sus nombres indican su propósito. Todo el contenido debe constar de expresiones regulares válidas con el formato \"/patrón/opciones\" (por ejemplo, <code>/.+@domain\\.tld/i</code>).<br>\n Si bien se llevan a cabo comprobaciones básicas de cada expresión regular, la funcionalidad de Rspamd puede verse inutilizada, si no consigue interpretar correctamente la sintaxis utilizada.<br>\n Rspamd intentará leer el contenido del mapa cuando éste se modifique. En caso de de problemas, <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">reinicie Rspamd</a> para forzar una recarga del mapa.<br>Los elementos incluidos en listas de bloqueo se excluyen de la cuarentena.",
"iam_use_ssl_info": "Si se habilita SSL y el puerto se establece en el 389, se cambiará automáticamente al 636.",
"iam_login_provisioning": "Crear usuarios automáticamente al iniciar sesión",
"iam_periodic_full_sync": "Sincronización completa periódica",
"iam_port": "Puerto",
"iam_realm": "Ámbito",
"iam_redirect_url": "URL de redirección",
"iam_server_url": "URL del servidor",
"iam_sso": "Inicio de sesión único (SSO)",
"iam_sync_interval": "Intervalo de sincronización/importación (minutos)",
"iam_test_connection": "Comprobar conexión",
"iam_token_url": "Endpoint del token",
"iam_username_field": "Campo de nombre de usuario",
"iam_use_ssl": "Utilizar SSL",
"iam_use_tls": "Utilizar STARTTLS",
"iam_userinfo_url": "Endopint de información de usuario",
"iam_use_tls_info": "Si se habilita TLS, se debe utilizar el puerto por defecto del servidor LDAP (389). No se permiten puertos SSL.",
"iam_version": "Versión",
"ignore_ssl_error": "Ignorar errores de SSL",
"ip_check": "Comprobación IP",
"ip_check_disabled": "La comprobación de IP está desactivada. Puede activarla en<br> <strong>Sistema > Configuración > Opciones > Personalizar</strong>.",
"ip_check_opt_in": "Aceptar utilizar el servicio de terceros <strong>ipv4.mailcow.email</strong> y <strong>ipv6.mailcow.email</strong> para resolver direcciones IP externas.",
"last_applied": "Aplicado por última vez",
"license_info": "No es obligatorio contar con una licencia, pero ayuda a continuar el desarrollo.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">Indique aquí su GUID</a> o <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Support order\">adquiera servicios de soporte para su instalación de Mailcow.</a>",
"login_time": "Hora de inicio de sesión",
"lookup_mx": "Destino es una expresión regular con la que contrastar el nombre MX (<code>.*\\.google\\.com</code> para dirigir todo el tráfico dirigido a un MX que termina en google.com a través de este salto)",
"message": "Mensaje",
"no": "&#10005;",
"optional": "opcional",
"app_hide": "Ocultar para inicio de sesión",
"convert_html_to_text": "Convertir HTML a texto plano",
"cors_settings": "Configuración de CORS",
"customer_id": "ID de cliente",
"dkim_overwrite_key": "Sobrescribir la clave DKIM existente",
"domain_admin": "Administrador de dominio",
"f2b_manage_external": "Gestionar Fail2Ban de manera externa",
"f2b_manage_external_info": "Fail2Ban conservará la lista de bloqueo, pero no establecerá activamente reglas para bloquear el tráfico. Utilizar la lista de bloqueo siguiente para bloquear externamente el tráfico.",
"filter": "Filtrar",
"admins": "Administradores",
"admins_ldap": "Administradores de LDAP",
"advanced_settings": "Configuración avanzada",
"allowed_methods": "Access-Control-Allow-Methods",
"allowed_origins": "Access-Control-Allow-Origin",
"api_read_only": "Acceso de sólo lectura",
"api_read_write": "Acceso de lectura y escritura",
"api_skip_ip_check": "Omitir la comprobación de la IP para la API",
"authed_user": "Usuario autentificado",
"ays": "¿Está seguro de querer continuar?",
"logo_normal_label": "Normal",
"logo_dark_label": "Invertido para modo oscuro",
"copy_to_clipboard": "¡Texto copiado al portapapeles!",
"login_page": "Inicio de sesión",
"domainadmin_quicklink": "Ocultar enlace rápido a página de inicio de sesión para administradores de dominios",
"domain_s": "Dominio(s)",
"f2b_filter": "Filtros regex",
"f2b_regex_info": "Registros tomados en consideración: SOGo, Postfix, Dovecot, PHP-FPM.",
"force_sso": "Deshabilitar el inicio de sesión de Mailcow y mostrar solamente el inicio de sesión único",
"guid": "GUID - ID de instancia único",
"guid_and_license": "GUID y licencia",
"hash_remove_info": "Al eliminar un hash de límite de velocidad (si todavía existe) se reiniciará su contador por completo.<br> Cada hash se indica con un color individual.",
"iam": "Proveedor de identidad",
"iam_attribute_field": "Campo de atributo",
"iam_auth_flow": "Flujo de autenticación",
"iam_basedn": "DN de base",
"iam_client_id": "ID de cliente",
"iam_client_secret": "Secreto de cliente",
"iam_client_scopes": "Ámbitos de cliente",
"iam_default_template": "Plantilla por defecto",
"iam_host": "Host",
"iam_host_info": "Introduzca uno o más hosts de LDAP, separados por comas.",
"iam_import_users": "Importar usuarios",
"iam_mapping": "Equivalencias de atributos",
"needs_restart": "necesita reinicio",
"oauth2_apps": "Aplicaciones OAuth2",
"oauth2_add_client": "Añadir cliente OAuth2",
"oauth2_renew_secret": "Generar nuevo secreto de cliente",
"oauth2_revoke_tokens": "Revocar todos los tokens de cliente",
"options": "Opciones",
"password_policy": "Política de contraseñas",
"password_policy_chars": "Debe contener al menos un caracter alfabético",
"password_policy_length": "La longitud mínima de la contraseña es %d",
"password_policy_numbers": "Debe contener al menos un número",
"password_policy_special_chars": "Debe contener caracteres especiales",
"password_reset_info": "Si no se indica una dirección para la recuperación de contraseñas, esta función no puede utilizarse.",
"password_reset_settings": "Configuración de recuperación de contraseña",
"password_reset_tmpl_html": "Plantilla HTML",
"password_settings": "Configuración de contraseña",
"priority": "Prioridad",
"quarantine_max_score": "Descartar notificación si la puntuación de spam de un mensaje de correo es mayor que este valor:<br><small>Por defecto 9999.0</small>",
"queue_unban": "desbloquear",
"regex_maps": "Mapas regex",
"relay_rcpt": "Dirección \"Para:\"",
"reset_limit": "Eliminar hash",
"restore_template": "Dejar en blanco para restablecer la plantilla por defecto",
"rsetting_no_selection": "Seleccione una regla",
"rsettings_preset_3": "Permitir solamente remitentes específicos para un buzón (utilizar únicamente como buzón interno)",
"rsettings_preset_4": "Deshabilitar Rspamd para un dominio",
"rspamd_global_filters": "Mapas de filtrado globales",
"rspamd_global_filters_agree": "¡Tendré cuidado!",
"rspamd_global_filters_info": "Los mapas de filtrado globales contienen distintos tipos de listos de bloqueo y desbloqueo.",
"service": "Servicio",
"service_id": "ID de servicio",
"success": "Éxito",
"task": "Tarea",
"time": "Tiempo",
"title": "Título",
"transport_dest_format": "Regex o sintaxis: ejemplo.org, .ejemplo.org, *, buzon@ejemplo.org (se pueden introducir varios valores separados por comas)",
"transport_test_rcpt_info": "&#8226; Utilizar null@hosted.mailcow.de para comprobar la retransmisión a un destino externo.",
"ui_header_announcement": "Anuncios",
"ui_header_announcement_content": "Texto (se permite HTML)",
"ui_header_announcement_select": "Seleccionar tipo de anuncio",
"ui_header_announcement_type": "Tipo",
"ui_header_announcement_type_danger": "Muy importante",
"ui_header_announcement_type_info": "Información",
"ui_header_announcement_type_warning": "Importante",
"user_link": "Enlace de usuario",
"user_quicklink": "Ocultar enlace rápido a página de inicio de sesión de usuario",
"validate_license_now": "Validar el GUID contra el servidor de licencias",
"verify": "Verificar",
"yes": "&#10003;"
},
"danger": {
"access_denied": "Acceso denegado o datos del formulario inválidos",
@@ -341,7 +488,60 @@
"username_invalid": "Nombre de usuario no se puede utilizar",
"validity_missing": "Por favor asigna un periodo de validez",
"value_missing": "Por favor proporcione todos los valores",
"yotp_verification_failed": "Verificación Yubico OTP fallida: %s"
"yotp_verification_failed": "Verificación Yubico OTP fallida: %s",
"last_key": "La última clave no se puede eliminar, en su lugar desactive la autenticación de doble factor.",
"img_dimensions_exceeded": "La imagen excede el tamaño máximo permitido",
"authsource_in_use": "El proveedor de identidades no se puede cambiar al estar en uso por uno o más usuario(s).",
"app_name_empty": "El nombre de la aplicación no puede quedar vacío",
"recovery_email_failed": "No se ha podido enviar un correo de recuperación. Contacte con su administrador.",
"tls_policy_map_dest_invalid": "Destino de política no válido",
"cors_invalid_method": "Allow-Method especificado no válido",
"dkim_domain_or_sel_exists": "Ya existe una clave DKIM para \"%s\" y no será sobrescrita",
"webauthn_publickey_failed": "No se ha almacenado ninguna clave pública para el autenticador seleccionado",
"invalid_reset_token": "Token de restablecimiento no válido",
"password_reset_na": "El restablecimiento de contraseña no está disponible en estos momentos. Contacte con su administrador.",
"generic_server_error": "Se ha producido un error inesperado en el servidor. Contacte con su administrador.",
"reset_f2b_regex": "El filtro Regex no se ha podido restablecer a tiempo, inténtelo de nuevo o espere unos segundos y vuelva a cargar la página web.",
"extra_acl_invalid": "Dirección de remitente externo \"%s\" no válida",
"extra_acl_invalid_domain": "El remitente externo \"%s\" utiliza un dominio no válido",
"max_alias_exceeded": "Se ha excedido el número máximo de alias",
"app_passwd_id_invalid": "Contraseña de aplicación con ID %s no válida",
"comment_too_long": "Comentario demasiado largo, máximo de 160 caracteres permitidos",
"cors_invalid_origin": "Allow-Origin especificado no válido",
"demo_mode_enabled": "Modo demo activado",
"description_invalid": "Descripción de recurso para %s no válida",
"extended_sender_acl_denied": "no se encuentra ACL para establecer direcciones de remitente externo",
"fido2_verification_failed": "Verificación FIDO2 fallida: %s",
"file_open_error": "El archivo no se puede abrir para escritura",
"global_filter_write_error": "No se ha podido escribir el archivo de filtro: %s",
"global_map_invalid": "Mapa global con ID %s no válido",
"global_map_write_error": "No se ha podido guardar el mapa global con ID %s: %s",
"ham_learn_error": "Error de aprendizaje de correo deseado: %s",
"iam_test_connection": "Conexión fallida",
"imagick_exception": "Error: Excepción en Imagick al leer la imagen",
"img_invalid": "No se ha podido validar el archivo de imagen",
"img_size_exceeded": "La imagen excede el tamaño máximo de archivo",
"img_tmp_missing": "No se ha podido validar el archivo de imagen: archivo temporal no encontrado",
"invalid_filter_type": "Tipo de filtro no válido",
"invalid_mime_type": "Tipo MIME no válido",
"maxquota_empty": "La cuota máxima por buzón no debe ser cero.",
"nginx_reload_failed": "Recarga de Nginx fallida: %s",
"password_reset_invalid_user": "Buzón no encontrado o dirección de correo para recuperación no establecida",
"pushover_credentials_missing": "Falta el token y/o la clave de Pushover",
"pushover_key": "La clave de Pushover tiene un formato incorrecto",
"pushover_token": "El token de Pushover tiene un formato incorrecto",
"required_data_missing": "Datos necesarios %s no proporcionados",
"reset_token_limit_exceeded": "Se ha superado el límite de tokens de restablecimiento. Inténtelo más tarde.",
"resource_invalid": "Nombre de recurso %s no válido",
"targetd_relay_domain": "El dominio de destino %s es un dominio de retransmisión",
"template_exists": "La plantilla %s ya existe",
"template_id_invalid": "Plantilla con ID %s no válida",
"template_name_invalid": "Nombre de plantilla no válido",
"temp_error": "Error transitorio",
"tfa_token_invalid": "Token de autenticación de doble factor no válido",
"to_invalid": "El destinatario no puede quedar en blanco",
"webauthn_authenticator_failed": "No se ha localizado el autenticador seleccionado",
"webauthn_username_failed": "El autenticador seleccionado pertenece a otra cuenta"
},
"debug": {
"containers_info": "Información de los contenedores",
@@ -357,7 +557,29 @@
"started_at": "Iniciado el",
"uptime": "Uptime",
"static_logs": "Logs estáticos",
"system_containers": "Sistema y Contenedores"
"system_containers": "Sistema y Contenedores",
"show_ip": "Mostrar IP pública",
"wip": "Actualmente incompleto",
"current_time": "Hora del sistema",
"service": "Servicio",
"timezone": "Huso horario",
"update_available": "Hay una actualización disponible",
"update_failed": "No se han podido comprobar las actualizaciones",
"architecture": "Arquitectura",
"chart_this_server": "Gráfico (este servidor)",
"container_running": "En ejecución",
"container_disabled": "Contenedor detenido o desactivado",
"container_stopped": "Detenido",
"cores": "Núcleos",
"error_show_ip": "No se han podido resolver las direcciones IP públicas",
"history_all_servers": "Historial (todos los servidores)",
"login_time": "Tiempo",
"memory": "Memoria",
"online_users": "Usuarios conectados",
"started_on": "Iniciado",
"success": "Éxito",
"no_update_available": "El sistema está actualizado",
"username": "Nombre de usuario"
},
"diagnostics": {
"cname_from_a": "Valor derivado del registro A / AAAA. Esto es permitido siempre que el registro apunte al recurso correcto.",
@@ -367,7 +589,8 @@
"dns_records_name": "Nombre",
"dns_records_status": "Información actual",
"dns_records_type": "Tipo",
"optional": "Este récord es opcional."
"optional": "Este récord es opcional.",
"dns_records_docs": "Consulte también <a target=\"_blank\" href=\"https://docs.mailcow.email/getstarted/prerequisite-dns\">la documentación</a>."
},
"edit": {
"active": "Activo",
@@ -435,13 +658,79 @@
"title": "Editar objeto",
"unchanged_if_empty": "Si no hay cambios dejalo en blanco",
"username": "Nombre de usuario",
"validate_save": "Validar y guardar"
"validate_save": "Validar y guardar",
"app_passwd_protocols": "Protocolos permitidos con contraseña de aplicación",
"domain_footer_info": "Los pies de página de dominio se añaden a todos los mensajes salientes remitidos por una dirección de dicho dominio.<br> Están disponibles las siguientes variables para el pie de página:",
"sender_acl_info": "Si el usuario del buzón A tiene permitido enviar como el buzón B, la dirección de remitente no se mostrará automáticamente como seleccionable en el campo \"De\" en SOGo.<br>\n El usuario del buzón B necesitará crear una delegación en SOGo para permitir al usuario A seleccionar su dirección como remitente. Para delegar un buzón en SOGo, utilice el menú (tres puntos) a la derecha del nombre del buzón en la esquina superior izquierda, en la vista de correo. Este comportamiento no se aplica a direcciones alias.",
"sogo_access_info": "Tras iniciar sesión, el usuario será redirigido automáticamente a SOGo.",
"comment_info": "Un comentario privado no es visible para el usuario, mientras que un comentario público se muestra como descripción emergente al pasar el ratón en la vista general del usuario",
"quota_warning_bcc_info": "Los avisos se enviarán como copias separadas a los siguientes destinatarios. Se indicará en el asunto el usuario afectado entre paréntesis, como por ejemplo: <code>Aviso de cuota (usuario@ejemplo.com)</code>.",
"sogo_access": "Redirección directa a SOGo",
"sogo_visible_info": "Esta opción solamente afecta a objetos que puedan ser visualizados en SOGo (alias compartidos o no compartidos que apunten al menos a un buzón interno). Si se oculta, el alias no aparecerá como seleccionable en SOGo.",
"extended_sender_acl_info": "Se aconseja importar una clave de dominio DKIM, si está disponible.<br>\n Recuerde añadir este servidor al registro SPF correspondiente.<br>\n Siempre que se añada un dominio o alias a este servidor, que se superponga con una dirección externa, se eliminará la dirección externa.<br>\n Utilice @dominio.tld para permitir enviar como *@dominio.tld.",
"pushover_info": "La configuración de notificaciones push se aplicará a todos los mensajes limpios (no spam) entregados a <b>%s</b> incluyendo alias (compartidos, no compartidos, etiquetados).",
"mbox_rl_info": "Este límite de peticiones se aplica al nombre de inicio de sesión SASL, coincide con cualquier dirección \"de\" que utilice el usuario conectado. Un límite de buzón tiene precedencia sobre un límite del dominio.",
"admin": "Editar administrador",
"none_inherit": "Ninguno / heredar",
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Comprobación de remitente desactivada</span>",
"footer_exclude": "Excluir del pie de página",
"acl": "ACL (permisos)",
"advanced_settings": "Configuración avanzada",
"allow_from_smtp": "Permitir únicamente a las siguientes direcciones IP utilizar <b>SMTP</b>",
"allow_from_smtp_info": "Dejar en blanco para permitir cualquier remitente.<br>Direcciones y redes IPv4/IPv6.",
"allowed_protocols": "Protocolos permitidos para acceso directo del usuario (no afecta a protocolos con contraseña de aplicación)",
"app_name": "Nombre de aplicación",
"app_passwd": "Contraseña de aplicación",
"created_on": "Creado",
"custom_attributes": "Atributos personalizados",
"delete_ays": "Por favor, confirme el proceso de eliminación.",
"disable_login": "Deshabilitar inicio de sesión (se aceptará el correo entrante)",
"domain_footer": "Pie de página para todos los usuarios del dominio",
"domain_footer_html": "Pie de página HTML",
"domain_footer_skip_replies": "Descartar pie de página en correos de respuesta",
"extended_sender_acl": "Direcciones de remisión externas",
"generate": "generar",
"lookup_mx": "El destino es una expresión regular con la que contrastar el nombre MX (<code>.*\\.google\\.com</code> para dirigir todo el correo enviado a un MX que termine en google.com a través de este salto)",
"mailbox_relayhost_info": "Aplicable únicamente al buzón y sus alias directos, anula el host de retransmisión para el dominio",
"mailbox_rename": "Renombrar buzón",
"mailbox_rename_agree": "He creado una copia de seguridad.",
"mailbox_rename_warning": "¡IMPORTANTE! Realice una copia de seguridad antes de renombrar el buzón.",
"mailbox_rename_alias": "Crear alias automáticamente",
"mailbox_rename_title": "Nuevo nombre de buzón local",
"password_recovery_email": "Dirección de correo para recuperación de contraseña",
"private_comment": "Comentario privado",
"public_comment": "Comentario público",
"pushover": "Pushover",
"pushover_evaluate_x_prio": "Escalar correo de alta prioridad [<code>X-Priority: 1</code>]",
"pushover_sender_array": "Tener en cuenta únicamente las siguientes direcciones de correo de remitente <small>(separados por comas)</small>",
"pushover_text": "Texto de notificación",
"pushover_title": "Título de notificación",
"pushover_sound": "Sonido",
"pushover_verify": "Verificar credenciales",
"quota_warning_bcc": "CCO de aviso de cuota",
"ratelimit": "Límite de peticiones",
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Información</div> Puede definir mapas de transporte para destinatarios personalizados para este dominio. Si no se establece, se realizará una búsqueda MX.",
"relay_unknown_only": "Reenviar solamente los buzones no existentes. Los buzones existentes se entregarán localmente.",
"sogo_visible": "Alias visible en SOGo.",
"spam_alias": "Crear o modificar alias temporales (con caducidad)",
"spam_filter": "Filtro de spam",
"spam_policy": "Añadir o eliminar elementos de la lista de bloqueo/desbloqueo",
"spam_score": "Establecer una puntuación de spam personalizada"
},
"footer": {
"hibp_nok": "¡Se encontró coincidencia - esta es una contraseña <b>no segura</b>, selecciona otra!",
"hibp_ok": "No se encontraron coincidencias",
"loading": "Espera por favor...",
"restart_now": "Reiniciar ahora"
"restart_now": "Reiniciar ahora",
"restart_container": "Reiniciar contenedor",
"restart_container_info": "<b>Importante:</b> Un reinicio limpio puede llevar un tiempo. Por favor, espere a que finalice.",
"cancel": "Cancelar",
"confirm_delete": "Confirmar eliminación",
"delete_now": "Eliminar ahora",
"delete_these_items": "Confirme sus cambios para el siguiente ID de objeto",
"hibp_check": "Comprobar en haveibeenpwned.com",
"nothing_selected": "Nada seleccionado",
"restarting_container": "Reiniciando contenedor, puede llevar un tiempo"
},
"header": {
"administration": "Administración",
@@ -450,17 +739,38 @@
"mailcow_config": "Configuración",
"quarantine": "Cuarentena",
"restart_sogo": "Reiniciar SOGo",
"user_settings": "Configuraciones de usuario"
"user_settings": "Configuraciones de usuario",
"mailcow_system": "Sistema",
"apps": "Aplicaciones",
"restart_netfilter": "Reiniciar netfilter"
},
"info": {
"awaiting_tfa_confirmation": "En espera de confirmación de TFA",
"no_action": "No hay acción aplicable"
"no_action": "No hay acción aplicable",
"session_expires": "Su sesión expirará en unos 15 segundos"
},
"login": {
"delayed": "El inicio de sesión ha sido retrasado %s segundos.",
"login": "Inicio de sesión",
"password": "Contraseña",
"username": "Nombre de usuario"
"username": "Nombre de usuario",
"login_admin": "Inicio de sesión de administrador",
"invalid_pass_reset_token": "El token de restablecimiento de contraseña no es válido o ha caducado.<br>Solicite un nuevo enlace de restablecimiento de contraseña.",
"fido2_webauthn": "Inicio de sesión FIDO2/WebAuthn",
"forgot_password": "> ¿Contraseña olvidada?",
"mobileconfig_info": "Inicie sesión como usuario de buzón para descargar el perfil de conexión solicitado para dispositivos Apple.",
"new_password": "Nueva contraseña",
"back_to_mailcow": "Volver a mailcow",
"login_linkstext": "¿Sesión incorrecta?",
"login_usertext": "Iniciar sesión como usuario",
"login_domainadmintext": "Iniciar sesión como administrador de dominio",
"login_admintext": "Iniciar sesión como administrador",
"login_user": "Inicio de sesión de usuario",
"login_dadmin": "Inicio de sesión de administrador de dominio",
"new_password_confirm": "Confirmar nueva contraseña",
"other_logins": "o iniciar sesión con",
"reset_password": "Restablecer contraseña",
"request_reset_password": "Solicitar cambio de contraseña"
},
"mailbox": {
"action": "Acción",
@@ -572,7 +882,67 @@
"toggle_all": "Selecionar todo",
"username": "Nombre de usuario",
"waiting": "Esperando",
"weekly": "Cada semana"
"weekly": "Cada semana",
"sieve_preset_4": "Colocar en bandeja de entrada, omitir procesamiento posterior en filtros de sieve",
"goto_spam": "Aprender como <b>correo no deseado</b>",
"sieve_preset_header": "Vea los preajustes de ejemplo más abajo. Para más detalles, consulte <a href=\"https://en.wikipedia.org/wiki/Sieve_(mail_filtering_language)\" target=\"_blank\">Wikipedia</a>.",
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Nombre de usuario o contraseña incorrectos",
"tls_policy_maps_enforced_tls": "Estas políticas tendrán precedencia también para aquellos usuarios de buzones en los que sea obligatoria una conexión TLS. Si no se indica ninguna política a continuación, dichos usuarios aplicarán los valores predeterminados que se especifiquen en <code>smtp_tls_mandatory_protocols</code> y <code>smtp_tls_mandatory_ciphers</code>.",
"alias_domain_alias_hint": "Los alias <b>no</b> se aplican a dominios de alias automáticamente. Una dirección alias <code>mi-alias@dominio</code> <b>no cubre</b> la dirección <code>mi-alias@dominio-alias</code> (donde \"dominio-alias\" es un hipotético alias para el dominio \"dominio\").<br>Utilice un filtro sieve para redirigir el correo a un buzón externo (ver la pestaña \"Filtros\" o utilice SOGo -> Desvío). Utilice \"expandir alias a dominio de alias\" para agregar automáticamente los alias que falten.",
"domain_templates": "Plantillas de dominio",
"sieve_preset_1": "Desechar correo con tipos de archivo probablemente peligrosos",
"created_on": "Creado",
"disable_login": "No permitir iniciar sesión (se seguirá aceptando el correo entrante)",
"mailbox": "Buzón",
"mailbox_defaults": "Ajustes por defecto",
"sogo_visible_y": "Mostrar alias en SOGo",
"spam_aliases": "Alias temporal",
"add_template": "Añadir plantilla",
"all_domains": "Todos los dominios",
"allow_from_smtp": "Permitir únicamente a estas direcciones IP utilizar <b>SMTP</b>",
"allow_from_smtp_info": "Dejar vacío para permitir cualquier remitente.<br>Direcciones y redes IPv4/IPv6.",
"allowed_protocols": "Protocolos permitidos",
"goto_ham": "Aprender como <b>correo deseado</b>",
"iam": "Proveedor de identidad",
"insert_preset": "Insertar valor predeterminado de ejemplo \"%s\"",
"last_mail_login": "Último acceso al correo",
"last_pw_change": "Último cambio de contraseña",
"mailbox_defaults_info": "Definir configuración por defecto para nuevos buzones.",
"mailbox_templates": "Plantillas de buzón",
"no": "&#10005;",
"open_logs": "Abrir registros",
"owner": "Propietario",
"private_comment": "Comentario privado",
"public_comment": "Comentario público",
"q_add_header": "al mover a carpeta de Spam",
"q_all": " al mover a carpeta de Spam y al rechazar",
"q_reject": "al rechazar",
"quarantine_category": "Categoría de notificación de cuarentena",
"recipient": "Destinatario",
"relay_unknown": "Retransmitir buzones desconocidos",
"sender": "Remitente",
"sieve_preset_2": "Marcar siempre el correo de un remitente específico como leído",
"sieve_preset_3": "Descartar silenciosamente, detener procesado de sieve",
"sieve_preset_5": "Respuesta automática (vacaciones)",
"sieve_preset_6": "Rechazar correo con respuesta",
"sieve_preset_7": "Redireccionar y guardar/descartar",
"sieve_preset_8": "Redirigir correo de un remitente específico, marcarlo como leído y clasificarlo en subcarpeta",
"sogo_visible": "Alias visible en SOGo",
"sogo_visible_n": "Ocultar alias en SOGo",
"stats": "Estadísticas",
"syncjob_check_log": "Comprobar registros",
"syncjob_last_run_result": "Resultado de la última ejecución",
"syncjob_EX_OK": "Éxito",
"syncjob_EXIT_CONNECTION_FAILURE": "Problema de conexión",
"syncjob_EXIT_TLS_FAILURE": "Problema con la conexión cifrada",
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Problema de autenticación",
"syncjob_EXIT_OVERQUOTA": "El buzón de destino ha superado la cuota",
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "No es posible conectar con el servidor remoto",
"table_size": "Tamaño de la tabla",
"table_size_show_n": "Mostrar %s elementos",
"templates": "Plantillas",
"template": "Plantilla",
"yes": "&#10003;"
},
"oauth2": {
"access_denied": "Inicie sesión como propietario del buzón para otorgar acceso a través de OAuth2.",
@@ -614,7 +984,13 @@
"subj": "Asunto",
"text_from_html_content": "Contenido (html convertido)",
"text_plain_content": "Contenido (text/plain)",
"toggle_all": "Seleccionar todos"
"toggle_all": "Seleccionar todos",
"confirm": "Confirmar",
"deliver_inbox": "Entregar en bandeja de entrada",
"download_eml": "Descargar (.eml)",
"info": "Información",
"junk_folder": "Carpeta de correo no deseado",
"notified": "Notificado"
},
"queue": {
"queue_manager": "Administrador de cola"
@@ -773,11 +1149,55 @@
"waiting": "Esperando",
"week": "Semana",
"weekly": "Cada semana",
"weeks": "Semanas"
"weeks": "Semanas",
"with_app_password": "con contraseña de aplicación",
"year": "año",
"years": "años"
},
"warning": {
"domain_added_sogo_failed": "Se agregó el dominio pero no se pudo reiniciar SOGo, revisa los logs del servidor.",
"fuzzy_learn_error": "Error aprendiendo hash: %s",
"ip_invalid": "IP inválida omitida: %s"
"ip_invalid": "IP inválida omitida: %s",
"cannot_delete_self": "No se puede eliminar el usuario conectado"
},
"datatables": {
"collapse_all": "Contraer todo",
"aria": {
"sortAscending": ": activar para ordenar ascendentemente según la columna",
"sortDescending": ": activar para ordenar descendentemente según la columna"
},
"infoEmpty": "Mostrando 0 a 0 de 0 apuntes",
"paginate": {
"last": "Última",
"next": "Siguiente",
"previous": "Anterior",
"first": "Primero"
},
"processing": "Espere, por favor...",
"decimal": ".",
"emptyTable": "Sin datos disponibles en la tabla",
"expand_all": "Ampliar todo",
"info": "Mostrando apuntes _START_ a _END_ de _TOTAL_",
"infoFiltered": "(filtrado a partir de _MAX_ entradas totales)",
"thousands": ",",
"lengthMenu": "Mostrar entradas de _MENU_",
"loadingRecords": "Cargando...",
"search": "Buscar:",
"zeroRecords": "No se han encontrado registros coincidentes"
},
"fido2": {
"set_fido2": "Registrar dispositivo FIDO2",
"set_fido2_touchid": "Registrar Touch ID en Apple M1",
"set_fn": "Establecer nombre amistoso (fácil de recordar)",
"confirm": "Confirmar",
"fido2_auth": "Iniciar sesión con FIDO2",
"fido2_success": "Dispositivo registrado con éxito",
"fido2_validation_failed": "Validación fallida",
"fn": "Nombre amistoso (fácil de recordar)",
"known_ids": "ID conocidas",
"none": "Deshabilitado",
"register_status": "Estado de registro",
"rename": "Renombrar",
"start_fido2_validation": "Iniciar validación FIDO2"
}
}

View File

@@ -9,11 +9,11 @@
"source": "Forrás",
"spamfilter": "Spam szűrő",
"subject": "Tárgy",
"sys_mails": "Rendszer-üzenetek",
"sys_mails": "Rendszer e-mailek",
"text": "Szöveg",
"time": "Idő",
"title": "Cím",
"title_name": "\"mailcow UI\" website címe",
"title_name": "\"mailcow UI\" weboldal címe",
"to_top": "Vissza a tetejére",
"transport_dest_format": "Szintaxis: pelda.hu, .pelda.hu, *, fiok@pelda.hu (több érték esetén vesszővel elválasztva)",
"upload": "Feltöltés",
@@ -29,14 +29,14 @@
"logo_dark_label": "Sötét üzemmódhoz invertálva",
"f2b_regex_info": "Figyelembe vett naplók: SOGo, Postfix, Dovecot, PHP-FPM.",
"f2b_retry_window": "Újrapróbálkozási ablak (s) a maximális próbálkozásokhoz",
"f2b_whitelist": "Fehérlistás hálózatok/hostok",
"f2b_whitelist": "Engedélyezési listás hálózatok/hostok",
"filter_table": "Szűrő táblázat",
"forwarding_hosts": "Továbbító hostok",
"forwarding_hosts_add_hint": "Megadhat IPv4/IPv6 címeket, hálózatokat CIDR jelölésben, állomásneveket (amelyek IP-címekre lesznek feloldva) vagy tartományneveket (amelyek IP-címekre lesznek feloldva az SPF rekordok vagy ezek hiányában az MX rekordok lekérdezésével).",
"forwarding_hosts_add_hint": "Megadhat IPv4/IPv6 címeket, hálózatokat CIDR jelölésben, állomásneveket (amelyek IP címekre lesznek feloldva) vagy tartományneveket (amelyek IP címekre lesznek feloldva az SPF rekordok vagy ezek hiányában az MX rekordok lekérdezésével).",
"from": "A címről",
"copy_to_clipboard": "Szöveg másolva a vágólapra!",
"f2b_manage_external": "A Fail2Ban külső kezelése",
"f2b_manage_external_info": "A Fail2ban továbbra is karbantartja a tiltólistát, de nem állít be aktívan szabályokat a forgalom blokkolására. Használja az alábbi generált tiltólistát a forgalom külső blokkolásához.",
"f2b_manage_external_info": "A Fail2ban továbbra is karbantartja a tiltólistát, de nem állít be aktívan szabályokat a forgalom blokkolásához. Használja az alábbi generált tiltólistát a forgalom külső blokkolásához.",
"f2b_max_ban_time": "Maximális tiltási idő (s)",
"f2b_netban_ipv4": "IPv4 alhálózat mérete, amelyre tilalmat kell alkalmazni (8-32)",
"f2b_netban_ipv6": "IPv6 alhálózat mérete, amelyre tilalmat kell alkalmazni (8-128)",
@@ -47,13 +47,13 @@
"html": "HTML",
"import": "Import",
"ip_check": "IP ellenőrzés",
"ip_check_disabled": "Az IP-ellenőrzés le van tiltva. Bekapcsolhatja a következő menüpont alatt<br> <strong>Rendszer > Beállítások > Opciók > Személyreszabás</strong>",
"ip_check_disabled": "Az IP ellenőrzés le van tiltva. Bekapcsolhatja a következő menüpont alatt<br> <strong>Rendszer > Beállítások > Opciók > Személyreszabás</strong>",
"is_mx_based": "MX alapú",
"last_applied": "Utoljára alkalmazott",
"link": "Link",
"loading": "Kérjük, várj...",
"login_time": "Bejelentkezési idő",
"f2b_list_info": "Egy feketelistán szereplő állomás vagy hálózat mindig nagyobb súlyú, mint egy fehérlistás entitás. <b>A lista frissítései néhány másodpercig tartanak.</b>",
"f2b_list_info": "Egy tiltólistán szereplő állomás vagy hálózat mindig nagyobb súlyú, mint egy engedélyezési listás elem. <b>A lista frissítései néhány másodpercig tartanak.</b>",
"f2b_ban_time_increment": "A tiltási idő minden egyes tiltással növekszik",
"additional_rows": " - további sorokat adtak hozzá",
"admin": "Adminisztrátor",
@@ -68,7 +68,7 @@
"api_key": "API-kulcs",
"api_read_only": "Csak olvasható hozzáférés",
"api_read_write": "Olvasás-írás hozzáférés",
"api_skip_ip_check": "IP-ellenőrzés kihagyása az API esetében",
"api_skip_ip_check": "IP ellenőrzés kihagyása az API esetében",
"cors_settings": "CORS beállítások",
"guid": "GUID - egyedi példányazonosító",
"dkim_to": "A címre",
@@ -82,8 +82,8 @@
"edit": "Szerkesztés",
"empty": "Nincs eredmény",
"excludes": "Kizárja ezeket a kedvezményezetteket",
"f2b_ban_time": "Tilalmi idő (s)",
"f2b_blacklist": "Feketelistás hálózatok/hostok",
"f2b_ban_time": "Tiltás időtartam (s)",
"f2b_blacklist": "Tiltólistás címek",
"f2b_filter": "Regex szűrők",
"logo_info": "A képed 40px magasságúra lesz méretezve a felső navigációs sávhoz és max. 250px szélességűre a kezdőlaphoz. A skálázható grafika használata erősen ajánlott.",
"dkim_add_key": "ARC/DKIM kulcs hozzáadása",
@@ -122,21 +122,187 @@
"arrival_time": "Érkezési idő (szerveridő)",
"authed_user": "Azonosított felhasználó",
"ays": "Biztos, hogy folytatni akarod?",
"ban_list_info": "A tiltott IP-címek listáját lásd alább: <b>hálózat (fennmaradó tiltási idő) - [akciók]</b>.<br />A tiltás feloldására várakozó IP-ket néhány másodpercen belül eltávolítjuk az aktív tiltási listáról.<br />A piros címkék a feketelistán szereplő aktív állandó tiltásokat jelzik.",
"ban_list_info": "A tiltott IP címek listáját lásd alább: <b>hálózat (fennmaradó tiltási idő) - [akciók]</b>.<br />A tiltás feloldására várakozó IP-ket néhány másodpercen belül eltávolítjuk az aktív tiltási listáról.<br />A piros címkék a tiltólistán szereplő aktív állandó tiltásokat jelzik.",
"configuration": "Konfiguráció",
"convert_html_to_text": "HTML átalakítása egyszerű szöveggé",
"credentials_transport_warning": "<b>Figyelmeztetés</b>: Egy új közlekedési térképbejegyzés hozzáadása frissíti a hitelesítő adatokat minden olyan bejegyzéshez, amelynek a következő ugrás oszlopa megegyezik.",
"customize": "Testreszabás",
"destination": "Célállomás",
"customer_id": "Ügyfél azonosító",
"apps_name": "\"mailcow Apps\" név"
"apps_name": "\"mailcow Apps\" név",
"admin_quicklink": "Gyorshivatkozás elrejtése az Adminisztrátori bejelentkezési oldalra",
"app_hide": "Elrejtés a bejelentkezéshez",
"domainadmin_quicklink": "Gyorshivatkozás elrejtése a Domain adminisztrátori bejelentkezési oldalra",
"filter": "Szűrő",
"force_sso_text": "Ha egy külső OIDC-szolgáltató van beállítva, ez az opció elrejti az alapértelmezett mailcow bejelentkezési űrlapokat, és csak az egységes bejelentkezési (Single Sign-On) gombot jeleníti meg",
"force_sso": "A mailcow bejelentkezés letiltása és csak az egységes bejelentkezés megjelenítése",
"hash_remove_info": "Egy arányszám-korlát hash eltávolítása (ha még létezik) teljesen visszaállítja a számlálóját.<br>\r\n Minden hash-t egyedi szín jelöl.",
"iam": "Azonosítási szolgáltató",
"iam_attribute_field": "Attribútum mező",
"iam_authorize_url": "Engedélyezési végpont",
"iam_auth_flow": "Azonosítási folyamat",
"iam_auth_flow_info": "Az engedélyezési kód áramláson (Authorization Code Flow) kívül, amelyet az egységes bejelentkezéshez (Single-Sign On) használnak (ez a standard áramlás Keycloak-ban), a mailcow támogatja a közvetlen hitelesítő adatokkal történő hitelesítési áramlást is. A Jelszóáramlás (Mailpassword Flow) megpróbálja érvényesíteni a felhasználó hitelesítő adatait a Keycloak Admin REST API használatával. A mailcow a <code>mailcow_password</code> attribútumból olvassa be a hash-elt jelszót, amely a Keycloak-ban van leképezve.",
"iam_basedn": "Bázis DN",
"iam_client_id": "Kliens azonosító",
"iam_client_secret": "Kliens titok",
"iam_client_scopes": "Kliens hatókörök",
"iam_default_template": "Alapértelmezett sablon",
"iam_default_template_description": "Ha nincs sablon hozzárendelve egy felhasználóhoz, az alapértelmezett sablon lesz felhasználva a postafiók létrehozásához, de a postafiók frissítéséhez nem.",
"iam_description": "Külső azonosítási szolgáltató konfigurálása.<br>A felhasználók postafiókjai automatikusan létrejönnek az első bejelentkezéskor, feltéve, hogy van attribútum-hozzárendelés beállítva.",
"iam_extra_permission": "A következő beállításokhoz a Keycloak-ban lévő mailcow kliensnek szüksége van egy <code>Service account</code>-ra és a <code>view-users</code> engedélyre.",
"iam_host": "Házigazda",
"iam_host_info": "Adjon meg egy vagy több LDAP állomást, vesszővel elválasztva.",
"iam_import_users": "Felhasználók importálása",
"iam_login_provisioning": "Felhasználók automatikus létrehozása bejelentkezéskor",
"iam_mapping": "Attribútum-hozzárendelés",
"iam_bindpass": "Bind jelszó",
"iam_periodic_full_sync": "Időszakos teljes szinkronizálás",
"iam_port": "Port",
"iam_realm": "Tartomány",
"iam_redirect_url": "Átirányítási URL",
"iam_rest_flow": "Mailpassword Flow",
"iam_server_url": "Szerver URL",
"iam_sso": "Egységes bejelentkezés",
"iam_sync_interval": "Szinkronizálási / importálási időtartam (perc)",
"iam_test_connection": "Kapcsolat tesztelése",
"iam_token_url": "Token végpont",
"iam_userinfo_url": "Felhasználói információ végpont",
"iam_username_field": "Felhasználónév mező",
"iam_binddn": "Bind DN",
"iam_use_ssl": "SSL használata",
"iam_use_ssl_info": "Ha az SSL-t engedélyezi, és a port 389-re van állítva, az automatikusan felülíródik 636-ra.",
"iam_use_tls": "StartTLS használata",
"iam_use_tls_info": "Ha a TLS-t engedélyezi, az LDAP szerver alapértelmezett portját kell használnia (389). Az SSL portok nem használhatók.",
"iam_version": "Verzió",
"ignore_ssl_error": "SSL hibák figyelmen kívül hagyása",
"ip_check_opt_in": "Választás a harmadik féltől származó <strong>ipv4.mailcow.email</strong> és <strong>ipv6.mailcow.email</strong> szolgáltatás használatára a külső IP címek feloldásához.",
"license_info": "A licensz nem kötelező, de segít a további fejlesztésben.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">Regisztrálja a GUID-ját itt</a> vagy <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Support order\">vásároljon támogatást a mailcow telepítéséhez.</a>",
"lookup_mx": "A cél egy reguláris kifejezés, amely illeszkedik az MX névre (<code>.*\\.google\\.com</code>, hogy a google.com-ra végződő MX-en keresztül továbbítsa az összes levelet)",
"main_name": "\"mailcow UI\" név",
"merged_vars_hint": "A szürkével jelölt sorok a <code>vars.(local.)inc.php</code> fájlból lettek összevonva, és nem módosíthatók.",
"message": "Üzenet",
"message_size": "Üzenet mérete",
"nexthop": "Következő ugrás",
"no": "&#10005;",
"no_active_bans": "Nincs aktív tiltás",
"no_new_rows": "Nincs több sor elérhető",
"no_record": "Nincs bejegyzés",
"oauth2_apps": "OAuth2 alkalmazások",
"oauth2_add_client": "OAuth2 kliens hozzáadása",
"oauth2_client_id": "Kliens azonosító",
"oauth2_client_secret": "Kliens titok",
"oauth2_info": "Az OAuth2 implementáció támogatja az \"Authorization Code\" engedélyezési típust és frissítési tokeneket ad ki.<br>\r\nA szerver automatikusan új frissítési tokeneket is kiad, miután egy frissítési token fel lett használva.<br><br>\r\n&#8226; Az alapértelmezett hatókör a <i>profile</i>. Csak postafiók-felhasználók hitelesíthetők az OAuth2-vel szemben. Ha a scope paraméter elmarad, az visszaesik a <i>profile</i>-ra.<br>\r\n&#8226; A <i>state</i> paramétert a kliensnek kötelező elküldenie az engedélyezési kérelem részeként.<br><br>\r\nAz OAuth2 API-hoz intézett kérések útvonalai: <br>\r\n<ul>\r\n <li>Engedélyezési végpont: <code>/oauth/authorize</code></li>\r\n <li>Token végpont: <code>/oauth/token</code></li>\r\n <li>Erőforrás oldal: <code>/oauth/profile</code></li>\r\n</ul>\r\nA kliens titok újragenerálása nem jár le a meglévő engedélyezési kódok lejáratával, de azok nem tudják megújítani a tokenjüket.<br><br>\r\nA kliens tokenek visszavonása az összes aktív munkamenet azonnali leállítását okozza. Minden kliensnek újra kell hitelesítenie magát.",
"oauth2_redirect_uri": "Átirányítási URI",
"oauth2_renew_secret": "Új kliens titok generálása",
"oauth2_revoke_tokens": "Minden kliens token visszavonása",
"optional": "opcionális",
"options": "Opciók",
"password": "Jelszó",
"password_length": "Jelszó hossza",
"password_policy": "Jelszó házirend",
"password_policy_chars": "Legalább egy betűkaraktert kell tartalmaznia",
"password_policy_length": "A jelszó minimális hossza %d",
"password_policy_lowerupper": "Kis- és nagybetűket kell tartalmaznia",
"password_policy_numbers": "Legalább egy számot kell tartalmaznia",
"password_policy_special_chars": "Speciális karaktereket kell tartalmaznia",
"password_repeat": "Megerősítő jelszó (ismétlés)",
"password_reset_info": "Ha nincs megadva helyreállítási e-mail cím, ez a funkció nem használható.",
"password_reset_settings": "Jelszó-helyreállítási beállítások",
"password_reset_tmpl_html": "HTML sablon",
"password_reset_tmpl_text": "Szöveges sablon",
"password_settings": "Jelszó beállítások",
"priority": "Prioritás",
"private_key": "Privát kulcs",
"quarantine": "Karantén",
"quarantine_bcc": "Az összes értesítés másolatának elküldése (BCC) erre a címzettnek:<br><small>Hagyja üresen a letiltáshoz. <b>Aláíratlan, nem ellenőrzött levél. Csak belső kézbesítésre alkalmas.</b></small>",
"quarantine_exclude_domains": "Tartományok és alias-tartományok kizárása",
"quarantine_max_age": "Maximális életkor napokban<br><small>Az értéknek legalább 1 napnak kell lennie.</small>",
"quarantine_max_score": "Az értesítés elvetése, ha egy levél spam pontszáma magasabb ennél az értéknél:<br><small>Alapértelmezett értéke 9999.0</small>",
"quarantine_max_size": "Maximális méret MiB-ban (a nagyobb elemeket elveti):<br><small>A 0 <b>nem</b> jelent korlátlant.</small>",
"quarantine_notification_html": "Értesítő e-mail sablon:<br><small>Hagyja üresen az alapértelmezett sablon visszaállításához.</small>",
"quarantine_notification_sender": "Értesítő e-mail feladója",
"quarantine_notification_subject": "Értesítő e-mail tárgya",
"quarantine_redirect": "<b>Az összes értesítés átirányítása</b> erre a címzettnek:<br><small>Hagyja üresen a letiltáshoz. <b>Aláíratlan, nem ellenőrzött levél. Csak belső kézbesítésre alkalmas.</b></small>",
"quarantine_release_format": "A feloldott elemek formátuma",
"quarantine_release_format_att": "Csatolmányként",
"quarantine_release_format_raw": "Eredeti, módosítatlan formában",
"quarantine_retention_size": "Megőrzések postafiókonként:<br><small>A 0 <b>inaktívat</b> jelent.</small>",
"quicklink_text": "A gyorshivatkozások megjelenítése vagy elrejtése a bejelentkezési űrlap alatt",
"quota_notification_html": "Értesítő e-mail sablon:<br><small>Hagyja üresen az alapértelmezett sablon visszaállításához.</small>",
"quota_notification_sender": "Kvóta értesítő e-mail feladója",
"quota_notification_subject": "Kvóta értesítő e-mail tárgya",
"quota_notifications": "Kvóta értesítések",
"quota_notifications_info": "A kvóta értesítéseket a felhasználók egyszer kapják meg, amikor a 80%-os határt, majd a 95%-os határt átlépik.",
"quota_notifications_vars": "{{percent}} a felhasználó aktuális kvótáját jelenti<br>{{username}} a postafiók neve",
"queue_unban": "tiltás feloldása",
"r_active": "Aktív korlátozások",
"r_inactive": "Inaktív korlátozások",
"r_info": "A szürkével/letiltva jelölt elemek az aktív korlátozások listáján a mailcow számára nem érvényes korlátozások, és nem mozgathatók. Az ismeretlen korlátozások a megjelenési sorrendben lesznek beállítva. <br>Új elemeket adhat hozzá a <code>inc/vars.local.inc.php</code> fájlban, hogy váltani tudja őket.",
"rate_name": "Arányszám neve",
"recipients": "Címzettek",
"refresh": "Frissítés",
"regen_api_key": "API kulcs újragenerálása",
"regex_maps": "Regex térképek",
"relay_from": "\"Feladó:\" cím",
"relay_rcpt": "\"Címzett:\" cím",
"relay_run": "Teszt futtatása",
"relayhosts": "Feladófüggő szállítások",
"relayhosts_hint": "Határozzon meg feladófüggő szállításokat, hogy kiválaszthassa őket egy tartomány konfigurációs párbeszédpanelén.<br>\r\n A szállítási szolgáltatás mindig \"smtp:\" és ezért megpróbálja a TLS-t, ha felajánlják. A becsomagolt TLS (SMTPS) nem támogatott. A felhasználók egyéni kimenő TLS-szabályzati beállításai figyelembe vételre kerülnek.<br>\r\n Érintik a kiválasztott tartományokat, beleértve az alias tartományokat is.",
"remove": "Eltávolítás",
"remove_row": "Sor eltávolítása",
"reset_default": "Visszaállítás alapértelmezettre",
"reset_limit": "Hash eltávolítása",
"reset_password_vars": "<code>{{link}}</code> A generált jelszó-helyreállítási link<br><code>{{username}}</code> A jelszó-helyreállítást kérő felhasználó postafiók neve<br><code>{{username2}}</code> A helyreállítási postafiók neve<br><code>{{date}}</code> A jelszó-helyreállítási kérelem dátuma<br><code>{{token_lifetime}}</code> A token élettartama percekben<br><code>{{hostname}}</code> A mailcow hosztnév",
"restore_template": "Hagyja üresen az alapértelmezett sablon visszaállításához.",
"routing": "Útválasztás",
"rsetting_add_rule": "Szabály hozzáadása",
"rsetting_content": "Szabály tartalma",
"rsetting_desc": "Rövid leírás",
"rsetting_no_selection": "Kérjük, válasszon egy szabályt",
"rsetting_none": "Nincsenek elérhető szabályok",
"rsettings_insert_preset": "Példa előre beállított \"%s\" beillesztése",
"rsettings_preset_1": "Minden letiltása, kivéve a DKIM és az arányszám-korlátot a hitelesített felhasználók számára",
"rsettings_preset_2": "A Postmasterek spamet akarnak",
"rsettings_preset_3": "Csak bizonyos feladókat engedélyezzen egy postafiók számára (pl. csak belső postafiókként használva)",
"rsettings_preset_4": "Rspamd letiltása egy tartomány számára",
"rspamd_com_settings": "A beállítás neve automatikusan generálódik, kérjük, nézze meg a lenti példa-előrebeállításokat. További részletekért lásd a <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd dokumentációját</a>",
"rspamd_global_filters": "Globális szűrőtérképek",
"rspamd_global_filters_agree": "Óvatos leszek!",
"rspamd_global_filters_info": "A globális szűrőtérképek különböző típusú globális tiltó- és engedélyezési listákat tartalmaznak.",
"rspamd_global_filters_regex": "A nevük elmagyarázza a céljukat. Minden tartalomnak érvényes reguláris kifejezést kell tartalmaznia \"/pattern/options\" formátumban (pl. <code>/.+@domain\\.tld/i</code>).<br>\r\n Bár alapvető ellenőrzések történnek minden regex soron, az Rspamd funkcionalitása megszakadhat, ha nem sikerül helyesen értelmeznie a szintaxist.<br>\r\n Az Rspamd megpróbálja elolvasni a térkép tartalmát, amikor az megváltozik. Ha problémákat tapasztal, <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">indítsa újra az Rspamd-et</a>, hogy kikényszerítse a térkép újratöltését.<br>A tiltólistára került elemek ki vannak zárva a karanténból.",
"rspamd_settings_map": "Rspamd beállítási térkép",
"sal_level": "Moo szint",
"service": "Szolgáltatás",
"service_id": "Szolgáltatás azonosító",
"task": "Feladat",
"transport_maps": "Szállítási térképek",
"transport_test_rcpt_info": "&#8226; Használja a null@hosted.mailcow.de címet a külföldi célra történő továbbítás teszteléséhez.",
"transports_hint": "&#8226; Egy szállítási térkép bejegyzés <b>felülírja</b> a feladófüggő szállítási térképet</b>.<br>\r\n&#8226; Az MX-alapú szállítások előnyben részesítettek.<br>\r\n&#8226; A felhasználónkénti kimenő TLS-szabályzati beállítások figyelmen kívül hagyódnak, és csak a TLS-szabályzati térkép bejegyzései kényszeríthetik ki őket.<br>\r\n&#8226; A definiált szállításokhoz a szállítási szolgáltatás mindig \"smtp:\" és ezért megpróbálja a TLS-t, ha felajánlják. A becsomagolt TLS (SMTPS) nem támogatott.<br>\r\n&#8226; A \"/localhost$/\"-nek megfelelő címek mindig \"local:\"-on keresztül lesznek szállítva, ezért a \"*\" cél nem vonatkozik ezekre a címekre.<br>\r\n&#8226; A hitelesítő adatok meghatározásához egy példa következő ugráshoz \"[host]:25\", a Postfix <b>mindig</b> lekérdezi a \"host\"-ot, mielőtt a \"[host]:25\"-re keresne. Ez a viselkedés lehetetlenné teszi a \"host\" és a \"[host]:25\" egyidejű használatát.",
"ui_footer": "Lábléc (HTML engedélyezett)",
"ui_header_announcement": "Közlemények",
"ui_header_announcement_active": "Közlemény beállítása aktívra",
"ui_header_announcement_content": "Szöveg (HTML engedélyezett)",
"ui_header_announcement_help": "A közlemény minden bejelentkezett felhasználó számára látható, valamint a felhasználói felület bejelentkezési képernyőjén.",
"ui_header_announcement_select": "Válassza ki a közlemény típusát",
"ui_header_announcement_type": "Típus",
"ui_header_announcement_type_danger": "Nagyon fontos",
"ui_header_announcement_type_info": "Információ",
"ui_header_announcement_type_warning": "Fontos",
"ui_texts": "Felhasználói felület címkéi és szövegei",
"unban_pending": "tiltás feloldása függőben",
"unchanged_if_empty": "Ha nem változik, hagyja üresen",
"user_link": "Felhasználói-link",
"user_quicklink": "Gyorshivatkozás elrejtése a Felhasználói bejelentkezési oldalra",
"validate_license_now": "GUID érvényesítése a licenszszerverrel szemben",
"yes": "&#10003;",
"success": "Siker"
},
"edit": {
"active": "Aktív",
"advanced_settings": "Haladó beállítások",
"alias": "Alias szerkesztése",
"allow_from_smtp": "Kizárólag ezen IP-címek használhatnak <b>SMTP</b>-t",
"allow_from_smtp_info": "Leave empty to allow all senders.<br>IPv4/IPv6 addresses and networks.",
"allow_from_smtp": "Kizárólag ezen IP címek használhatnak <b>SMTP</b>-t",
"allow_from_smtp_info": "Hagyja üresen minden feladó engedélyezéséhez.<br>IPv4/IPv6 címek és hálózatok.",
"allowed_protocols": "Engedélyezett protokollok",
"app_name": "Applikáció neve",
"app_passwd": "Applikáció jelszava",
@@ -146,7 +312,127 @@
"description": "Leírás",
"domain_quota": "Domain kvóta",
"domains": "Domainek",
"edit_alias_domain": "Alias domain szerkesztése"
"edit_alias_domain": "Alias domain szerkesztése",
"acl": "ACL (Engedélyek)",
"admin": "Adminisztrátor szerkesztése",
"app_passwd_protocols": "Engedélyezett protokollok az alkalmazás jelszavához",
"automap": "Próbálja automatikusan feltérképezni a mappákat (\"Elküldött elemek\", \"Elküldött\" => \"Elküldött\" stb.)",
"bcc_dest_format": "A BCC-célpontnak egyetlen érvényes e-mail címnek kell lennie.<br>Ha több címre kell másolatot küldenie, hozzon létre egy aliast, és használja azt itt.",
"comment_info": "A privát megjegyzés nem látható a felhasználó számára, míg a nyilvános megjegyzés tooltip-ként jelenik meg, amikor a felhasználó áttekintésében a megjegyzésre mutat.",
"created_on": "Létrehozva",
"custom_attributes": "Egyéni attribútumok",
"delete1": "Törlés a forrásból, ha befejeződött",
"delete2": "Üzenetek törlése a célállomáson, amelyek nincsenek a forráson",
"delete2duplicates": "Duplikáltak törlése a célállomáson",
"delete_ays": "Erősítse meg a törlési folyamatot.",
"disable_login": "Bejelentkezés letiltása (a bejövő leveleket továbbra is elfogadja)",
"domain": "Domain szerkesztése",
"domain_admin": "Domain adminisztrátor szerkesztése",
"domain_footer": "Tartományszintű lábléc",
"domain_footer_html": "HTML lábléc",
"domain_footer_info": "A tartományszintű lábléceket a tartományon belüli címmel társított összes kimenő e-mailhez hozzáadják. <br> A következő változók használhatók a lábléchez:",
"domain_footer_info_vars": {
"auth_user": "{= auth_user =} - Hitelesített felhasználónév az MTA által megadott",
"from_user": "{= from_user =} - A boríték feladójának felhasználói része, pl. a \"moo@mailcow.tld\" esetén \"moo\"-t ad vissza",
"from_name": "{= from_name =} - A boríték feladójának neve, pl. a \"Mailcow &lt;moo@mailcow.tld&gt;\" esetén \"Mailcow\"-t ad vissza",
"from_addr": "{= from_addr =} - A boríték feladójának címe",
"from_domain": "{= from_domain =} - A boríték feladójának tartománya",
"custom": "{= foo =} - Ha a postafiók rendelkezik a \"foo\" egyéni attribútummal, amelynek értéke \"bar\", akkor \"bar\"-t ad vissza"
},
"domain_footer_plain": "Egyszerű szöveges lábléc",
"domain_footer_skip_replies": "Lábléc figyelmen kívül hagyása válasz e-maileknél",
"dont_check_sender_acl": "Küldő ellenőrzés letiltása a(z) %s tartományhoz (+ alias tartományok)",
"encryption": "Titkosítás",
"exclude": "Objektumok kizárása (regex)",
"extended_sender_acl": "Külső feladói címek",
"extended_sender_acl_info": "Importálni kell egy DKIM tartomány kulcsot, ha elérhető.<br>\r\n Ne felejtse el hozzáadni ezt a szervert a megfelelő SPF TXT rekordhoz.<br>\r\n Amikor egy tartományt vagy alias tartományt ad hozzá ehhez a szerverhez, amely átfedésben van egy külső címmel, a külső cím eltávolításra kerül.<br>\r\n Használja a @domain.tld címet, hogy engedélyezze a küldést *@domain.tld néven.",
"force_pw_update": "Jelszófrissítés kényszerítése a következő bejelentkezéskor",
"force_pw_update_info": "Ez a felhasználó csak a(z) %s címre tud bejelentkezni. Az alkalmazás jelszavak használhatóak maradnak.",
"footer_exclude": "Kizárás a láblécből",
"full_name": "Teljes név",
"gal": "Globális címlista",
"gal_info": "A GAL tartalmazza a tartomány összes objektumát, és egyetlen felhasználó sem szerkesztheti. A Szabad/Foglalt információ a SOGo-ban hiányzik, ha le van tiltva! <b>Indítsa újra a SOGo-t a változások alkalmazásához.</b>",
"generate": "generál",
"grant_types": "Engedélyezési típusok",
"hostname": "Hosztnév",
"inactive": "Inaktív",
"kind": "Típus",
"last_modified": "Utoljára módosítva",
"lookup_mx": "A cél egy reguláris kifejezés, amely illeszkedik az MX névre (<code>.*\\.google\\.com</code>, hogy a google.com-ra végződő MX-en keresztül továbbítsa az összes levelet)",
"mailbox": "Postafiók szerkesztése",
"mailbox_quota_def": "Alapértelmezett postafiók kvóta",
"mailbox_relayhost_info": "A postafiókra és csak a közvetlen aliasokra vonatkozik, felülírja a tartományi továbbító hostot.",
"mailbox_rename": "Postafiók átnevezése",
"mailbox_rename_agree": "Készítettem biztonsági másolatot.",
"mailbox_rename_warning": "FONTOS! Hozzon létre biztonsági másolatot a postafiók átnevezése előtt.",
"mailbox_rename_alias": "Alias automatikus létrehozása",
"mailbox_rename_title": "Új helyi postafiók neve",
"max_aliases": "Max. aliasok",
"max_mailboxes": "Max. lehetséges postafiókok",
"max_quota": "Max. kvóta postafiókonként (MiB)",
"maxage": "Üzenetek maximális életkora napokban, amelyek lekérdezésre kerülnek a távolról<br><small>(0 = figyelmen kívül hagyás)</small>",
"maxbytespersecond": "Max. bájt/másodperc <br><small>(0 = korlátlan)</small>",
"mbox_rl_info": "Ez a sebességkorlátozás a SASL bejelentkezési névre vonatkozik, és illeszkedik minden, a bejelentkezett felhasználó által használt \"from\" címre. Egy postafiók sebességkorlátozása felülírja a tartományszintű sebességkorlátozást.",
"mins_interval": "Időköz (perc)",
"multiple_bookings": "Több foglalás",
"none_inherit": "Nincs / Örökölt",
"nexthop": "Következő ugrás",
"password": "Jelszó",
"password_recovery_email": "Jelszó-helyreállítási e-mail",
"password_repeat": "Megerősítő jelszó (ismétlés)",
"previous": "Előző oldal",
"private_comment": "Privát megjegyzés",
"public_comment": "Nyilvános megjegyzés",
"pushover": "Pushover",
"pushover_evaluate_x_prio": "Magas prioritású levelek továbbítása [<code>X-Priority: 1</code>]",
"pushover_info": "A push értesítési beállítások az összes tiszta (nem-spam) levélre vonatkoznak, amelyeket a <b>%s</b> címre kézbesítettek, beleértve az aliasokat is (megosztott, nem megosztott, címkézett).",
"pushover_only_x_prio": "Csak a magas prioritású leveleket vegye figyelembe [<code>X-Priority: 1</code>]",
"pushover_sender_array": "Csak a következő feladói e-mail címeket vegye figyelembe <small>(vesszővel elválasztva)</small>",
"pushover_sender_regex": "Feladók egyeztetése a következő regex-szel",
"pushover_text": "Értesítési szöveg",
"pushover_title": "Értesítési cím",
"pushover_sound": "Hang",
"pushover_vars": "Ha nincs feladói szűrő meghatározva, minden e-mail figyelembe vételre kerül.<br>A Regex szűrők, valamint a pontos feladói ellenőrzések egyénileg definiálhatók, és sorban lesznek figyelembe véve. Nem függenek egymástól.<br>Használható változók a szöveghez és a címhez (kérjük, vegye figyelembe az adatvédelmi szabályzatokat)",
"pushover_verify": "Hitelesítő adatok ellenőrzése",
"quota_mb": "Kvóta (MiB)",
"quota_warning_bcc": "Kvóta figyelmeztetés BCC",
"quota_warning_bcc_info": "A figyelmeztetések külön másolatként lesznek elküldve a következő címzetteknek. A tárgyat a megfelelő felhasználónévvel egészítik ki zárójelben, például: <code>Quota warning (user@example.com)</code>.",
"ratelimit": "Arányszám-korlát",
"redirect_uri": "Átirányítási/Visszahívási URL",
"relay_all": "Az összes címzett továbbítása",
"relay_all_info": "↪ Ha úgy döntesz, hogy <b>nem</b> továbbítod az összes címzettet, akkor minden egyes címzett számára, akit továbbítani kell, létre kell hoznod egy (\"vak\") postafiókot.",
"relay_domain": "Továbbítsa ezt a tartományt",
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Információ</div> Definiálhatsz szállítási térképeket ehhez a tartományhoz egyedi célállomásra. Ha nincs beállítva, egy MX lekérdezés történik.",
"relay_unknown_only": "Csak a nem létező postafiókok továbbítása. A létező postafiókok helyben lesznek kézbesítve.",
"relayhost": "Feladófüggő szállítások",
"remove": "Eltávolítás",
"resource": "Erőforrás",
"save": "Módosítások mentése",
"scope": "Hatókör",
"sender_acl": "Engedélyezés küldésre mint",
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">A küldő ellenőrzése le van tiltva</span>",
"sender_acl_info": "Ha az A postafiók felhasználója küldhet a B postafiók felhasználójaként, a feladói cím nem jelenik meg automatikusan választható \"from\" mezőként a SOGo-ban.<br>\r\n A B postafiók felhasználójának delegálást kell létrehoznia a SOGo-ban, hogy az A postafiók felhasználója kiválaszthassa a címét feladóként. A SOGo-ban egy postafiók delegálásához használja a menüt (három pont) a postafiók neve jobb oldalán a bal felső sarokban, a levélnézetben. Ez a viselkedés nem vonatkozik az alias címekre.",
"sieve_desc": "Rövid leírás",
"sieve_type": "Szűrő típusa",
"skipcrossduplicates": "Átugrani a duplikált üzeneteket a mappák között (aki előbb jön, előbb kapja)",
"sogo_access": "Közvetlen továbbítás a SOGo-ra",
"sogo_access_info": "A bejelentkezés után a felhasználó automatikusan átirányításra kerül a SOGo-ra.",
"sogo_visible": "Alias látható a SOGo-ban",
"sogo_visible_info": "Ez az opció csak azokra az objektumokra vonatkozik, amelyek megjeleníthetők a SOGo-ban (megosztott vagy nem megosztott alias címek, amelyek legalább egy helyi postafiókra mutatnak). Ha el van rejtve, egy alias nem jelenik meg választható feladóként a SOGo-ban.",
"spam_alias": "Időkorlátos alias címek létrehozása vagy módosítása",
"spam_filter": "Spam szűrő",
"spam_policy": "Elemek hozzáadása vagy eltávolítása a tiltó- vagy engedélyezési listán",
"spam_score": "Egyéni spam pontszám beállítása",
"subfolder2": "Szinkronizálás a célállomáson egy almappába<br><small>(üres = ne használjon almappát)</small>",
"syncjob": "Szinkronizálási feladat szerkesztése",
"target_address": "Célcím(ek) <small>(vesszővel elválasztva)</small>",
"target_domain": "Cél domain",
"timeout1": "Időtúllépés a távoli állomáshoz való csatlakozáskor",
"timeout2": "Időtúllépés a helyi állomáshoz való csatlakozáskor",
"title": "Objektum szerkesztése",
"unchanged_if_empty": "Ha nem változik, hagyja üresen",
"username": "Felhasználónév",
"validate_save": "Érvényesítés és mentés"
},
"footer": {
"cancel": "Mégse",
@@ -159,7 +445,9 @@
"restart_container": "Konténer újraindítása",
"restart_container_info": "<b>Fontos:</b> A teljes újraindulás eltarthat egy ideig, kérjük várjon, amíg befejeződik!",
"restart_now": "Újraindítás most",
"restarting_container": "Konténer újraindítása. Ez eltarthat egy darabig."
"restarting_container": "Konténer újraindítása. Ez eltarthat egy darabig.",
"hibp_check": "Ellenőrzés a haveibeenpwned.com-on",
"nothing_selected": "Nincs semmi kiválasztva"
},
"header": {
"administration": "Beállítások és részletek",
@@ -170,7 +458,8 @@
"quarantine": "Karantén",
"restart_netfilter": "Netfilter újraindítása",
"restart_sogo": "SOGo újraindítása",
"user_settings": "Felhasználó beállításai"
"user_settings": "Felhasználó beállításai",
"mailcow_system": "Rendszer"
},
"info": {
"awaiting_tfa_confirmation": "TFA megerősítésre várakozás",
@@ -182,7 +471,23 @@
"login": "Bejelentkezés",
"mobileconfig_info": "A kért Apple kapcsolat profil letöltéséhez jelentkezzen be, mint postafiók-felhasználó.",
"password": "Jelszó",
"username": "Felhasználónév"
"username": "Felhasználónév",
"back_to_mailcow": "Vissza a mailcow-hoz",
"fido2_webauthn": "FIDO2/WebAuthn bejelentkezés",
"forgot_password": "> Elfelejtett jelszó?",
"invalid_pass_reset_token": "A jelszó-helyreállítási token érvénytelen vagy lejárt.<br>Kérjen új jelszó-helyreállítási linket.",
"login_linkstext": "Nem a megfelelő bejelentkezés?",
"login_usertext": "Bejelentkezés felhasználóként",
"login_domainadmintext": "Bejelentkezés domain adminisztrátorként",
"login_admintext": "Bejelentkezés adminisztrátorként",
"login_user": "Felhasználói bejelentkezés",
"login_dadmin": "Domain-adminisztrátori bejelentkezés",
"login_admin": "Adminisztrátori bejelentkezés",
"new_password": "Új jelszó",
"new_password_confirm": "Új jelszó megerősítése",
"other_logins": "vagy bejelentkezés",
"reset_password": "Jelszó visszaállítása",
"request_reset_password": "Jelszó módosítás kérése"
},
"mailbox": {
"action": "Művelet",
@@ -200,10 +505,10 @@
"add_resource": "Erőforrás hozzáadása",
"add_tls_policy_map": "TLS irányelv-térkép hozzáadása",
"address_rewriting": "Címátírás",
"alias": "Alias",
"alias": "Álnév",
"alias_domain_backupmx": "Alias domain inaktív a továbbító domain részére",
"aliases": "Alias-ok",
"allow_from_smtp": "Kizárólag ezek az IP-címek használhatják az <b>SMTP</b>-t",
"aliases": "Álnevek",
"allow_from_smtp": "Kizárólag ezek az IP címek használhatják az <b>SMTP</b>-t",
"allow_from_smtp_info": "Hagyja üresen minden feladó engedélyezéséhez.<br>IPv4/IPv6 címek és hálózatok.",
"allowed_protocols": "Engedélyezett protokollok",
"backup_mx": "Továbbító domain",
@@ -221,7 +526,7 @@
"domain_admins": "Domain adminisztrátorok",
"domain_aliases": "Domain alias-ok",
"domain_quota": "Kvóta",
"domains": "Domain-ek",
"domains": "Domainek",
"edit": "Szerkesztés",
"empty": "Nincs találat",
"enable_x": "Engedélyezés",
@@ -277,7 +582,87 @@
"toggle_all": "Összes átváltása",
"username": "Felhasználónév",
"waiting": "Várakozás",
"weekly": "Hetente"
"weekly": "Hetente",
"add_alias_expand": "Alias kiterjesztése alias tartományokra",
"alias_domain_alias_hint": "Az aliasok <b>nem</b> vonatkoznak automatikusan a domain aliasokra. Egy <code>my-alias@domain</code> alias cím <b>nem</b> fedezi a <code>my-alias@alias-domain</code> címet (ahol az \"alias-domain\" a \"domain\" képzeletbeli alias tartománya).<br>Kérjük, használjon sieve szűrőt a levél külső postafiókba történő átirányításához (lásd a \"Szűrők\" fület vagy a SOGo -> Továbbító). Használja az \"Alias kiterjesztése alias tartományokra\" opciót a hiányzó aliasok automatikus hozzáadásához.",
"all_domains": "Minden tartomány",
"bcc_info": "A BCC térképek arra szolgálnak, hogy csendesen továbbítsák az összes üzenet másolatát egy másik címre. A címzett térkép típust akkor használják, ha a helyi célpont egy levél címzettjeként működik. A feladói térképek ugyanazon elv szerint működnek.<br/>\r\n A helyi célpontot nem értesítik a sikertelen kézbesítésről.",
"bcc_map_type": "BCC típus",
"bcc_maps": "BCC térképek",
"bcc_rcpt_map": "Címzett térkép",
"bcc_sender_map": "Feladó térkép",
"bcc_to_rcpt": "Váltás címzett térkép típusra",
"bcc_to_sender": "Váltás feladó térkép típusra",
"bcc_type": "BCC típus",
"booking_null": "Mindig szabadként mutat",
"booking_0_short": "Mindig szabad",
"booking_custom": "Kemény korlát a foglalások egyéni számára",
"booking_custom_short": "Kemény korlát",
"booking_ltnull": "Korlátlan, de foglaltnak mutatja magát, ha le van foglalva",
"booking_lt0_short": "Lágy korlát",
"catch_all": "Catch-All",
"created_on": "Létrehozva",
"dkim_domains_selector": "Válogató",
"dkim_key_length": "DKIM kulcs hossza (bit)",
"domain_templates": "Domain sablonok",
"domain_quota_total": "Teljes domain kvóta",
"gal": "Globális címlista",
"goto_ham": "Tanulás <b>ham</b>-ként",
"goto_spam": "Tanulás <b>spam</b>-ként",
"iam": "Azonosítási szolgáltató",
"last_modified": "Utoljára módosítva",
"last_pw_change": "Utolsó jelszócsere",
"mailbox_defaults": "Alapértelmezett beállítások",
"mailbox_defaults_info": "Alapértelmezett beállítások meghatározása az új postafiókokhoz.",
"mailbox_templates": "Postafiók sablonok",
"max_aliases": "Max. aliasok",
"max_mailboxes": "Max. lehetséges postafiókok",
"max_quota": "Max. kvóta postafiókonként",
"no": "&#10005;",
"open_logs": "Naplók megnyitása",
"q_add_header": "amikor a levélszemét mappába kerül",
"q_all": " amikor a levélszemét mappába kerül és elutasításkor",
"q_reject": "elutasításkor",
"quarantine_category": "Karantén értesítési kategória",
"recipient": "Címzett",
"recipient_map_info": "A címzett térképeket arra használják, hogy egy üzenet célcímét kicseréljék, mielőtt azt kézbesítenék.",
"recipient_map_new_info": "A címzett térkép célja érvényes e-mail címnek vagy tartománynévnek kell lennie.",
"recipient_map_old_info": "Egy címzett térkép eredeti céljának érvényes e-mail címnek vagy tartománynévnek kell lennie.",
"relay_all": "Az összes címzett továbbítása",
"relay_unknown": "Ismeretlen postafiókok továbbítása",
"sender": "Feladó",
"set_postfilter": "Megjelölés poszt-szűrőként",
"set_prefilter": "Megjelölés pre-szűrőként",
"sieve_info": "Több szűrőt is tárolhatsz felhasználónként, de egyszerre csak egy pre-szűrő és egy poszt-szűrő lehet aktív.<br>\r\nMinden szűrő a leírt sorrendben lesz feldolgozva. Sem a sikertelen szkript, sem a kiadott \"keep;\" parancs nem állítja le a további szkriptek feldolgozását. A globális sieve szkriptek változásai a Dovecot újraindítását váltják ki.<br><br>Globális sieve pre-szűrő &#8226; Pre-szűrő &#8226; Felhasználói szkriptek &#8226; Poszt-szűrő &#8226; Globális sieve poszt-szűrő",
"sieve_preset_1": "Levél eldobása valószínűleg veszélyes fájltípusokkal",
"sieve_preset_2": "Egy adott feladó e-mailjét mindig olvasottként jelölje meg",
"sieve_preset_3": "Csendesen elvetni, leállítani minden további sieve feldolgozást",
"sieve_preset_4": "Fájl az INBOX-ba, kihagyni a további feldolgozást a sieve szűrőkkel",
"sieve_preset_5": "Auto válaszadó (szabadság)",
"sieve_preset_6": "Levél elutasítása válasszal",
"sieve_preset_7": "Átirányítás és megtartás/eldobás",
"sieve_preset_8": "E-mail átirányítása egy adott feladótól, olvasottként jelölés és almappába rendezés",
"sieve_preset_header": "Kérjük, nézze meg az alábbi példa-előrebeállításokat. További részletekért lásd a <a href=\"https://en.wikipedia.org/wiki/Sieve_(mail_filtering_language)\" target=\"_blank\">Wikipedia</a>-t.",
"sogo_visible": "Alias látható a SOGo-ban",
"sogo_visible_n": "Alias elrejtése a SOGo-ban",
"sogo_visible_y": "Alias megjelenítése a SOGo-ban",
"syncjob_check_log": "Napló ellenőrzése",
"syncjob_last_run_result": "Utolsó futás eredménye",
"syncjob_EX_OK": "Siker",
"syncjob_EXIT_CONNECTION_FAILURE": "Kapcsolati probléma",
"syncjob_EXIT_TLS_FAILURE": "Probléma a titkosított kapcsolattal",
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Hitelesítési probléma",
"syncjob_EXIT_OVERQUOTA": "A cél postafiók túllépte a kvótát",
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Nem lehet csatlakozni a távoli szerverhez",
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Hibás felhasználónév vagy jelszó",
"templates": "Sablonok",
"template": "Sablon",
"tls_map_policy": "Irányelv",
"tls_policy_maps": "TLS irányelv térképek",
"tls_policy_maps_enforced_tls": "Ezek az irányelvek felülírják a kimenő TLS szállítási szabályokat függetlenül a felhasználó TLS irányelvi beállításaitól. Ha nincs alább egyetlen irányelv sem, ezek a felhasználók az alapértelmezett értékeket alkalmazzák, amelyeket a <code>smtp_tls_mandatory_protocols</code> és a <code>smtp_tls_mandatory_ciphers</code> határoz meg.",
"tls_policy_maps_info": "Ez az irányelv térkép felülírja a kimenő TLS szállítási szabályokat függetlenül a felhasználó TLS irányelvi beállításaitól.<br>\r\n Kérjük, ellenőrizze a <a href=\"http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps\" target=\"_blank\">\"smtp_tls_policy_maps\" dokumentációját</a> további információkért.",
"tls_policy_maps_long": "Kimenő TLS irányelv térkép felülírások",
"yes": "&#10003;"
},
"oauth2": {
"access_denied": "Kérjük jelentkezzen be postafiók felhasználójával az OAuth2 használatához.",
@@ -301,7 +686,7 @@
"medium_danger": "Közepes veszély",
"neutral_danger": "Semleges",
"notified": "Értesítve",
"qinfo": "A karantén-rendszer elmenti a visszautasított leveleket az adatbázisba, miközben a feladónak nem lesz az a benyomása, hogy a levelet kézbesítették.\r\n <br>\"Spamnek jelölés és törlés\" spam-ként jegyzi meg az üzenetet a Bayes-tétel segítségével, illetve fuzzy hash-eket számít, hogy hasonló üzenetek is spam-be kerüljenek a jövőben.\r\n <br>Több üzenet spamként való megjegyzése időigényes lehet.<br>Feketelistára vett levelek nem kerülnek karanténba.",
"qinfo": "A karantén-rendszer elmenti a visszautasított leveleket az adatbázisba, miközben a feladónak nem lesz az a benyomása, hogy a levelet kézbesítették.\r\n <br>\"Spamnek jelölés és törlés\" spam-ként jegyzi meg az üzenetet a Bayes-tétel segítségével, illetve fuzzy hash-eket számít, hogy hasonló üzenetek is spam-be kerüljenek a jövőben.\r\n <br>Több üzenet spamként való megjegyzése időigényes lehet.<br>Tiltólistára vett levelek nem kerülnek karanténba.",
"qitem": "Tétel",
"quarantine": "Karantén",
"quick_actions": "Műveletek",
@@ -324,10 +709,38 @@
"table_size_show_n": "%s tétel mutatása",
"text_from_html_content": "Tartalom (konvertált html)",
"text_plain_content": "Tartalom (sima szöveg)",
"toggle_all": "Összes átkapcsolása"
"toggle_all": "Összes átkapcsolása",
"check_hash": "Fájl hash keresése @ VT",
"confirm": "Megerősítés",
"deliver_inbox": "Kézbesítés a beérkező mappába",
"disabled_by_config": "A jelenlegi rendszerkonfiguráció letiltja a karantén funkcionalitást. Kérjük, állítsa be a \"megőrzéseket postafiókonként\" és a \"maximális méretet\" a karantén elemek számára.",
"info": "Információ",
"junk_folder": "Levélszemét mappa",
"qhandler_success": "A kérés sikeresen elküldve a rendszernek. Most már bezárhatja az ablakot.",
"qid": "Rspamd QID",
"rejected": "Elutasítva",
"release_body": "A levelét eml fájlként csatoltuk ehhez az üzenethez.",
"rewrite_subject": "Tárgy átírása",
"settings_info": "A karanténba helyezhető elemek maximális száma: %s<br>Maximális e-mail méret: %s MiB",
"spam": "Spam",
"quick_info_link": "Információs link megnyitása",
"type": "Típus"
},
"queue": {
"queue_manager": "Queue Manager"
"queue_manager": "Queue Manager",
"delete": "Összes törlése",
"flush": "Üzenetsor ürítése",
"info": "A levelezési üzenetsor tartalmazza az összes kézbesítésre váró e-mailt. Ha egy e-mail hosszú ideig ragad az üzenetsorban, a rendszer automatikusan törli.<br>A megfelelő levél hibaüzenete tájékoztatást ad arról, miért nem lehetett a levelet kézbesíteni.",
"legend": "A levelezési üzenetsor műveleti funkciói:",
"ays": "Kérjük, erősítse meg, hogy törölni szeretné az összes elemet az aktuális üzenetsorból.",
"deliver_mail": "Kézbesítés",
"deliver_mail_legend": "Megpróbálja újra kézbesíteni a kiválasztott leveleket.",
"hold_mail": "Visszatartás",
"hold_mail_legend": "Visszatartja a kiválasztott leveleket. (Megakadályozza a további kézbesítési kísérleteket)",
"show_message": "Üzenet megjelenítése",
"unban": "üzenetsor tiltás feloldása",
"unhold_mail": "Visszatartás feloldása",
"unhold_mail_legend": "Kiadja a kiválasztott leveleket a kézbesítéshez. (Előzetes visszatartás szükséges)"
},
"start": {
"help": "Súgó panel megjelenítése/elrejtése",
@@ -380,7 +793,49 @@
"resource_modified": "Postafiók %s módosításai mentve",
"resource_removed": "Erőforrás %s eltávolítva",
"saved_settings": "Beállítások mentve",
"upload_success": "File sikeresen feltöltve"
"upload_success": "File sikeresen feltöltve",
"acl_saved": "Az ACL a(z) %s objektumhoz mentve",
"bcc_deleted": "BCC térkép bejegyzések törölve: %s",
"bcc_edited": "BCC térkép bejegyzés %s szerkesztve",
"bcc_saved": "BCC térkép bejegyzés mentve",
"cors_headers_edited": "A CORS beállítások mentve",
"custom_login_modified": "A bejelentkezési testreszabás sikeresen mentve",
"domain_add_dkim_available": "Egy DKIM kulcs már létezett",
"dkim_duplicated": "A DKIM kulcs a(z) %s tartományhoz sikeresen átmásolva a(z) %s tartományba",
"domain_footer_modified": "A(z) %s tartományi lábléc módosításai mentve",
"f2b_banlist_refreshed": "A tiltólista azonosítója sikeresen frissítve.",
"f2b_modified": "A Fail2ban paraméterek módosításai mentve",
"forwarding_host_added": "A továbbító állomás %s hozzáadva",
"forwarding_host_removed": "A továbbító állomás %s eltávolítva",
"iam_test_connection": "Kapcsolat sikeres",
"ip_check_opt_in_modified": "Az IP ellenőrzés sikeresen mentve",
"nginx_reloaded": "Az Nginx újra lett töltve",
"password_policy_saved": "A jelszó házirend sikeresen mentve",
"password_changed_success": "A jelszó sikeresen megváltoztatva",
"pushover_settings_edited": "A Pushover beállítások sikeresen elmentve, kérjük, ellenőrizze a hitelesítő adatokat.",
"queue_command_success": "A sor parancs sikeresen befejeződött",
"recipient_map_entry_deleted": "A címzett térkép ID %s törölve",
"recipient_map_entry_saved": "A címzett térkép bejegyzés \"%s\" mentve",
"recovery_email_sent": "Helyreállítási e-mail elküldve a(z) %s címre",
"relayhost_added": "A térkép bejegyzés %s hozzáadva",
"relayhost_removed": "A térkép bejegyzés %s eltávolítva",
"reset_main_logo": "Visszaállítás alapértelmezett logóra",
"rl_saved": "Arányszám-korlát a(z) %s objektumhoz mentve",
"rspamd_ui_pw_set": "Rspamd UI jelszó sikeresen beállítva",
"settings_map_added": "Hozzáadott beállítási térkép bejegyzés",
"settings_map_removed": "Eltávolított beállítási térkép ID %s",
"sogo_profile_reset": "A SOGo profil a(z) %s felhasználóhoz visszaállítva",
"template_added": "Hozzáadott sablon %s",
"template_modified": "A(z) %s sablon módosításai mentve",
"template_removed": "A sablon ID %s törölve",
"tls_policy_map_entry_deleted": "TLS irányelv térkép ID %s törölve",
"tls_policy_map_entry_saved": "TLS irányelv térkép bejegyzés \"%s\" mentve",
"ui_texts": "A felhasználói felület szövegeinek módosításai mentve",
"verified_fido2_login": "FIDO2 bejelentkezés ellenőrizve",
"verified_totp_login": "TOTP bejelentkezés ellenőrizve",
"verified_webauthn_login": "WebAuthn bejelentkezés ellenőrizve",
"verified_yotp_login": "Yubico OTP bejelentkezés ellenőrizve",
"mailbox_renamed": "A postafiók átnevezve %s-ről %s-re"
},
"user": {
"action": "Művelet",
@@ -449,15 +904,14 @@
"spam_score_reset": "Szerver szerinti alapértelmezésre visszaállítás",
"spamfilter": "Spam szűrő",
"spamfilter_behavior": "Osztályozás",
"spamfilter_bl": "Feketelista",
"spamfilter_bl_desc": "A feketelistán szereplő email címek mindig spam-ként lesznek kezelve és vissza lesznek utasítva. Joker karakter használható. A szűrő csak közvetlen aliasokra vonatkozik (alias egyetlen cél-postafiókkal), magára a postafiókra, illetve mindent elkapó aliasokra nem.",
"spamfilter_bl": "Tiltólista",
"spamfilter_bl_desc": "A tiltólistán szereplő email címek mindig spam-ként lesznek kezelve és vissza lesznek utasítva. Joker karakter használható. A szűrő csak közvetlen aliasokra vonatkozik (alias egyetlen cél-postafiókkal), magára a postafiókra, illetve mindent elkapó aliasokra nem.",
"spamfilter_default_score": "Alapértelmezett értékek",
"spamfilter_green": "Zöld: ez az üzenet nem spam",
"spamfilter_hint": "Az első érték az alacsony spam pontszámot, a második a magas spam pontszámot jelöli.",
"spamfilter_red": "Vörös: Ez az üzenet spam, a szerver el fogja vetni.",
"spamfilter_table_action": "Művelet",
"spamfilter_table_add": "Tétel hozzáadása",
"spamfilter_table_empty": "Nincs megjeleníthető adat",
"spamfilter_table_remove": "eltávolítás",
"spamfilter_table_rule": "Szabály",
"spamfilter_wl": "Engedélyezőlista",
@@ -482,15 +936,88 @@
"waiting": "Várakozás",
"week": "hét",
"weekly": "heti",
"weeks": "hét"
"weeks": "hét",
"aliases_also_send_as": "Küldhet még mint felhasználó",
"aliases_send_as_all": "Ne ellenőrizze a küldő hozzáférését a következő tartomány(ok) és annak alias tartományai számára",
"app_hint": "Az alkalmazás jelszavak alternatív jelszavak az IMAP, SMTP, CalDAV, CardDAV és EAS bejelentkezéshez. A felhasználónév változatlan marad. A SOGo webmail nem érhető el az alkalmazás jelszavakon keresztül.",
"allowed_protocols": "Engedélyezett protokollok",
"apple_connection_profile_complete": "Ez a kapcsolati profil tartalmazza az IMAP és SMTP paramétereket, valamint a CalDAV (naptárak) és CardDAV (névjegyek) útvonalakat egy Apple eszközhöz.",
"apple_connection_profile_mailonly": "Ez a kapcsolati profil csak IMAP és SMTP konfigurációs paramétereket tartalmaz egy Apple eszközhöz.",
"apple_connection_profile_with_app_password": "Új alkalmazás jelszó generálódik és hozzáadódik a profilhoz, így nem kell jelszót megadni az eszköz beállításakor. Kérjük, ne ossza meg a fájlt, mivel teljes hozzáférést biztosít a postafiókjához.",
"attribute": "Attribútum",
"authentication": "Hitelesítés",
"change_password_hint_app_passwords": "Fiókodnak %d alkalmazás jelszava van, amelyek nem lesznek megváltoztatva. Ezek kezeléséhez menj az Alkalmazás jelszavak fülre.",
"clear_recent_successful_connections": "Sikeres kapcsolatok törlése",
"created_on": "Létrehozva",
"direct_aliases_desc": "A közvetlen alias címeket érintik a spam szűrő és a TLS irányelv beállításai.",
"direct_protocol_access": "Ennek a postafiók felhasználónak <b>közvetlen, külső hozzáférése</b> van a következő protokollokhoz és alkalmazásokhoz. Ezt a beállítást az adminisztrátor vezérli. Az alkalmazás jelszavak létrehozhatók, hogy hozzáférést biztosítsanak az egyedi protokollokhoz és alkalmazásokhoz.<br>A \"Webmail\" gomb egységes bejelentkezést biztosít a SOGo-ra, és mindig elérhető.",
"eas_reset_help": "Sok esetben a eszköz gyorsítótárának visszaállítása segít egy sérült ActiveSync profil helyreállításában.<br><b>Figyelem:</b> Minden elem újra letöltődik!",
"empty": "Nincs eredmény",
"from": "feladó",
"is_catch_all": "Catch-all a tartomány(ok)hoz",
"last_pw_change": "Utolsó jelszócsere",
"last_ui_login": "Utolsó UI bejelentkezés",
"login_history": "Bejelentkezési előzmények",
"mailbox": "Postafiók",
"mailbox_general": "Általános",
"mailbox_settings": "Beállítások",
"month": "hónap",
"months": "hónap",
"open_logs": "Naplók megnyitása",
"open_webmail_sso": "Webmail",
"overview": "Áttekintés",
"password_reset_info": "Ha nincs megadva e-mail a jelszó-helyreállításhoz, ez a funkció nem használható.",
"protocols": "Protokollok",
"pushover_evaluate_x_prio": "Magas prioritású levelek továbbítása [<code>X-Priority: 1</code>]",
"pushover_info": "A push értesítési beállítások az összes tiszta (nem-spam) levélre vonatkoznak, amelyeket a <b>%s</b> címre kézbesítettek, beleértve az aliasokat is (megosztott, nem megosztott, címkézett).",
"pushover_only_x_prio": "Csak a magas prioritású leveleket vegye figyelembe [<code>X-Priority: 1</code>]",
"pushover_sender_array": "A következő feladói e-mail címek figyelembe vétele <small>(vesszővel elválasztva)</small>",
"pushover_sender_regex": "Feladók egyeztetése a következő regex-szel",
"pushover_text": "Értesítési szöveg",
"pushover_title": "Értesítési cím",
"pushover_sound": "Hang",
"pushover_vars": "Ha nincs feladói szűrő meghatározva, minden e-mail figyelembe vételre kerül.<br>A Regex szűrők, valamint a pontos feladói ellenőrzések egyénileg definiálhatók, és sorban lesznek figyelembe véve. Nem függenek egymástól.<br>Használható változók a szöveghez és a címhez (kérjük, vegye figyelembe az adatvédelmi szabályzatokat)",
"pushover_verify": "Hitelesítő adatok ellenőrzése",
"pw_recovery_email": "Jelszó-helyreállítási e-mail",
"q_add_header": "Levélszemét mappa",
"q_all": "Összes kategória",
"q_reject": "Elutasítva",
"quarantine_category": "Karantén értesítési kategória",
"quarantine_category_info": "Az \"Elutasítva\" értesítési kategória magában foglalja azokat a leveleket, amelyeket elutasítottak, míg a \"Levélszemét mappa\" értesíti a felhasználót a levélszemét mappába helyezett levelekről.",
"recent_successful_connections": "Látott sikeres kapcsolatok",
"shared_aliases_desc": "A megosztott aliasokat nem érintik a felhasználóspecifikus beállítások, mint a spam szűrő vagy a titkosítási szabályzat. A megfelelő spam szűrőket csak egy adminisztrátor hozhatja létre tartományszintű szabályzatként.",
"sogo_profile_reset": "SOGo profil visszaállítása",
"sogo_profile_reset_help": "Ez tönkreteszi a felhasználó SOGo profilját, és <b>visszavonhatatlanul törli az összes névjegy- és naptáradatot</b>.",
"sogo_profile_reset_now": "Profil visszaállítása most",
"spamfilter_table_domain_policy": "n/a (tartományi szabályzat)",
"syncjob_check_log": "Napló ellenőrzése",
"syncjob_last_run_result": "Utolsó futás eredménye",
"syncjob_EX_OK": "Siker",
"syncjob_EXIT_CONNECTION_FAILURE": "Kapcsolati probléma",
"syncjob_EXIT_TLS_FAILURE": "Probléma a titkosított kapcsolattal",
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Hitelesítési probléma",
"syncjob_EXIT_OVERQUOTA": "A cél postafiók túllépte a kvótát",
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Nem lehet csatlakozni a távoli szerverhez",
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Hibás felhasználónév vagy jelszó",
"tfa_info": "A kétlépcsős hitelesítés segít megvédeni a fiókodat. Ha engedélyezed, alkalmazás jelszavakra lesz szükséged, hogy bejelentkezz olyan alkalmazásokba vagy szolgáltatásokba, amelyek nem támogatják a kétlépcsős hitelesítést (pl. levelező kliensek).",
"tls_policy_warning": "<strong>Figyelem:</strong> Ha titkosított levélátvitelt kényszerítesz ki, elveszíthetsz e-maileket.<br>Azok az üzenetek, amelyek nem felelnek meg a szabályzatnak, kemény hibával visszapattannak a levelezőrendszerből.<br>Ez az opció a fő e-mail címedre (bejelentkezési név), az alias tartományokból származó összes címre, valamint az alias címekre vonatkozik, amelyeknek <b>csak ez az egy postafiók</b> a célja.",
"value": "Érték",
"with_app_password": "alkalmazás jelszóval",
"year": "év",
"years": "év"
},
"warning": {
"cannot_delete_self": "Bejelentkezett felhasználó nem törölhető.",
"ip_invalid": "Érvénytelen IP-cím átugorva: %s",
"ip_invalid": "Érvénytelen IP cím átugorva: %s",
"no_active_admin": "Utolsó aktív admin felhasználó nem deaktiválható.",
"quota_exceeded_scope": "Domain kvóta átlépve: csak korlátok nélküli postafiókok hozhatók létre ebben a domain-ben.",
"session_token": "Űrlap-token érvénytelen: Tokenek nem egyeznek",
"session_ua": "Űrlap-token érvénytelen: User-Agent hitelesítési probléma"
"session_token": "Űrlaptoken érvénytelen: Tokenek nem egyeznek",
"session_ua": "Űrlaptoken érvénytelen: User-Agent hitelesítési probléma",
"domain_added_sogo_failed": "A tartomány hozzáadva, de a SOGo újraindítása sikertelen, kérjük, ellenőrizze a szerver naplókat.",
"dovecot_restart_failed": "A Dovecot újraindítása sikertelen, kérjük, ellenőrizze a naplókat",
"fuzzy_learn_error": "Fuzzy hash tanulási hiba: %s",
"hash_not_found": "A hash nem található vagy már törölve lett",
"is_not_primary_alias": "Nem elsődleges alias %s kihagyva"
},
"acl": {
"delimiter_action": "Elhatárolás",
@@ -516,15 +1043,24 @@
"smtp_ip_access": "Az SMTP engedélyezett állomásainak módosítása",
"sogo_profile_reset": "SOGo profil visszaállítása",
"spam_alias": "Ideiglenes álnevek",
"spam_policy": "Fekete/Fehér lista",
"spam_policy": "Tiltó/engedélyezési lista",
"spam_score": "Spam pontszám",
"syncjobs": "Szinkronizálási feladatok",
"tls_policy": "TLS szabályzat",
"unlimited_quota": "Korlátlan kvóta a postafiókok számára",
"sogo_access": "A SOGo-hozzáférés kezelésének lehetővé tétele"
"sogo_access": "A SOGo-hozzáférés kezelésének lehetővé tétele",
"pw_reset": "Lehetővé teszi a mailcow felhasználói jelszavak visszaállítását"
},
"diagnostics": {
"dns_records": "DNS bejegyzések"
"dns_records": "DNS bejegyzések",
"cname_from_a": "Az A/AAAA rekordból származó érték. Ez addig támogatott, amíg a rekord a megfelelő erőforrásra mutat.",
"dns_records_24hours": "Kérjük, vegye figyelembe, hogy a DNS-ben végrehajtott változtatások akár 24 órát is igénybe vehetnek, amíg a jelenlegi állapotuk helyesen megjelenik ezen az oldalon. Ez a célja, hogy könnyen láthassa, hogyan kell konfigurálnia a DNS rekordokat, és ellenőrizze, hogy az összes rekordja helyesen van-e tárolva a DNS-ben.",
"dns_records_data": "Helyes adatok",
"dns_records_docs": "Kérjük, konzultáljon a <a target=\"_blank\" href=\"https://docs.mailcow.email/getstarted/prerequisite-dns\">dokumentációval</a> is.",
"dns_records_name": "Név",
"dns_records_status": "Jelenlegi állapot",
"dns_records_type": "Típus",
"optional": "Ez a rekord opcionális."
},
"add": {
"username": "Felhasználónév",
@@ -588,6 +1124,22 @@
"alias_domain": "Alias domain",
"alias_domain_info": "<small>Csak érvényes tartománynevek (vesszővel elválasztva).</small>",
"app_name": "Alkalmazás neve",
"app_passwd_protocols": "Engedélyezett protokollok az alkalmazás jelszavához"
"app_passwd_protocols": "Engedélyezett protokollok az alkalmazás jelszavához",
"automap": "Próbálja automatikusan feltérképezni a mappákat (\"Elküldött elemek\", \"Elküldött\" => \"Elküldött\" stb.)",
"multiple_bookings": "Több foglalás",
"quota_mb": "Kvóta (MiB)",
"relay_all": "Az összes címzett továbbítása",
"relay_all_info": "↪ Ha úgy döntesz, hogy <b>nem</b> továbbítod az összes címzettet, akkor minden egyes címzett számára, akit továbbítani kell, létre kell hoznod egy (\"vak\") postafiókot.",
"relay_domain": "Továbbítsa ezt a tartományt",
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Információ</div> Definiálhatsz szállítási térképeket ehhez a tartományhoz egyedi célállomásra. Ha nincs beállítva, egy MX lekérdezés történik.",
"relay_unknown_only": "Csak a nem létező postafiókok továbbítása. A létező postafiókok helyben lesznek kézbesítve.",
"relayhost_wrapped_tls_info": "Kérjük, <b>ne</b> használjon TLS-be csomagolt portokat (többnyire a 465-ös porton használatosak).<br>\r\nHasználjon bármilyen nem csomagolt portot és adjon ki STARTTLS-t. A TLS kikényszerítésére egy TLS irányelv hozható létre a \"TLS irányelv térképek\" alatt.",
"select": "Kérjük, válasszon...",
"select_domain": "Kérjük, először válasszon egy domaint",
"sieve_desc": "Rövid leírás",
"sieve_type": "Szűrő típusa",
"skipcrossduplicates": "Duplikált üzenetek átugrása mappák között (érkezési sorrendben)",
"subscribeall": "Feliratkozás minden mappára",
"syncjob": "Szinkronizálási feladat hozzáadása"
}
}

View File

@@ -359,7 +359,12 @@
"username": "Nome de usuário",
"validate_license_now": "Valide o GUID em relação ao servidor de licenças",
"verify": "Verificar",
"yes": "✓"
"yes": "✓",
"iam_client_id": "ID de cliente",
"iam_client_secret": "Senha de cliente",
"iam_auth_flow": "Fluxo de autenticação",
"iam_client_scopes": "Escopo do cliente",
"iam_default_template": "Template Padrão"
},
"danger": {
"access_denied": "Acesso negado ou dados de formulário inválidos",
@@ -508,7 +513,7 @@
"infoFiltered": "(filtrado do total de entradas _MAX_)",
"infoPostFix": "",
"thousands": ",",
"lengthMenu": "Mostrar _ MENU_ entradas",
"lengthMenu": "Mostrar _MENU_ entradas",
"loadingRecords": "Carregando...",
"processing": "Por favor, aguarde...",
"search": "Pesquisa:",

View File

@@ -184,7 +184,7 @@
"excludes": "Исключает этих получателей",
"f2b_ban_time": "Время бана (в секундах)",
"f2b_ban_time_increment": "Время бана увеличивается с каждым баном",
"f2b_blacklist": "Черный список подсетей/хостов",
"f2b_blacklist": "Черный список сетей/хостов",
"f2b_filter": "Правила фильтрации с помощью регулярных выражений",
"f2b_list_info": "Хосты или подсети, занесенные в черный список, всегда будут перевешивать объекты из белого списка. <b>Обновление списка займет несколько секунд.</b>",
"f2b_manage_external": "Внешнее управление Fail2Ban",
@@ -196,7 +196,7 @@
"f2b_parameters": "Настройки Fail2ban",
"f2b_regex_info": "Журналы которые принимаются во внимание: SOGo, Postfix, Dovecot, PHP-FPM.",
"f2b_retry_window": "Промежуток времени для следующего бана (в секундах)",
"f2b_whitelist": "Белый список подсетей/хостов",
"f2b_whitelist": "Белый список сетей/хостов",
"filter_table": "Поиск",
"forwarding_hosts": "Переадресация хостов",
"forwarding_hosts_add_hint": "Можно указывать: IPv4/IPv6 подсети в нотации CIDR, имена хостов (которые будут разрешаться в IP-адреса) или доменные имена (которые будут решаться с IP-адресами путем запроса SPF записей или, в случае их отсутствия - запросом MX записей).",
@@ -319,7 +319,7 @@
"rspamd_global_filters": "Глобальные правила фильтрации",
"rspamd_global_filters_agree": "Я понимаю, что я делаю, и буду осторожен!",
"rspamd_global_filters_info": "Глобальные правила фильтрации содержат различные виды глобальных черных и белых списков.",
"rspamd_global_filters_regex": "Названия фильтров отражают их предназначение. Все правила должены состоять из регулярных выражений в формате \"/pattern/options\" (например: <code>/.+@domain\\.tld/i</code>).<br>\r\nНесмотря на то, что перед сохранением правил выполняется проверка регулярных выражений, функциональность Rspamds может быть нарушена, если будет использован<br>\r\n некорректный синтаксис. Будьте внимательны при написании правил.<br>Электронные письма от адресов электронной почты, проходящие по регулярным выражениям черных списков, будут отклонены без сохранения в карантин.<br>\r\n Rspamd попытается прочитать содержимое правил при их изменении. Но, если что, вы можете <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">перезапустить Rspamd</a>, чтобы принять последние изменения принудительно.",
"rspamd_global_filters_regex": "Названия фильтров отражают их предназначение. Все правила должны состоять из регулярных выражений в формате \"/pattern/options\" (например: <code>/.+@domain\\.tld/i</code>).<br>\nНесмотря на то, что перед сохранением правил выполняется проверка регулярных выражений, функциональность Rspamds может быть нарушена, если будет использован<br>\n некорректный синтаксис. Будьте внимательны при написании правил.<br>Электронные письма от адресов электронной почты, проходящие по регулярным выражениям черных списков, будут отклонены без сохранения в карантин.<br>\n Rspamd попытается прочитать содержимое правил при их изменении. Но, если что, вы можете <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">перезапустить Rspamd</a>, чтобы принять последние изменения принудительно.",
"rspamd_settings_map": "Правила Rspamd",
"sal_level": "Уровень Муу",
"save": "Сохранить изменения",
@@ -408,7 +408,8 @@
"iam_host": "Хост",
"iam_host_info": "Укажите один или несколько LDAP-хостов через запятую.",
"iam_import_users": "Импорт пользователей",
"admin_quicklink": "Скрыть ссылку на вход для администраторов"
"admin_quicklink": "Скрыть ссылку на вход для администраторов",
"needs_restart": "необходим перезапуск"
},
"danger": {
"access_denied": "Доступ запрещён, или указаны неверные данные",
@@ -750,7 +751,7 @@
"sogo_visible_info": "Влияет только на объекты, которые могут отображаться в SOGo (персональные или общие псевдонимы, указывающие как минимум на один локальный почтовый аккаунт). Учтите, что если функция отключена, у пользователей не будет возможности выбрать адрес псевдонима в качестве отправителя в SOGo.",
"spam_alias": "Создать или изменить временные (спам) псевдонимы",
"spam_filter": "Спам фильтр",
"spam_policy": "Добавление или удаление элементов в белом/черном списке",
"spam_policy": "Добавить или удалить элементы белого/черного списка",
"spam_score": "Задать индивидуальное определение спама",
"subfolder2": "Синхронизировать в подпапку<br><small>(пусто = в корень)</small>",
"syncjob": "Изменить задание синхронизации",
@@ -1039,7 +1040,7 @@
"notified": "Увед.",
"qhandler_success": "Запрос успешно отправлен в систему. Теперь вы можете закрыть окно.",
"qid": "Rspamd QID",
"qinfo": "Карантин сохраняет входящие сообщения, классифицированные как нежелательные, в базу данных.\r\n <br>Отправители писем, которые помечены как отвергнутые, будут уверены что их письма <b>не</b> были доставлены вам.\r\n <br>\"Освободить из карантина\" изучит сообщение как полезную почту; по теореме Байеса и доставит его вам в Inbox.\r\n <br>\"Запомнить как спам и удалить\" изучит сообщение как спам по теореме Байеса, а также вычислит нечёткие хэши, чтобы лучше блокировать подобные сообщения в дальнейшем.\r\n <br>Учтите, что в зависимости от технических характеристик вашей системы, изучение большого количества сообщений может занять много времени.",
"qinfo": "Карантин сохраняет входящие сообщения, классифицированные как нежелательные, в базу данных.\n <br>Отправители писем, которые помечены как отвергнутые, будут уверены что их письма <b>не</b> были доставлены вам.\n <br>\"Освободить из карантина\" изучит сообщение как полезную почту; по теореме Байеса и доставит его вам в Inbox.\n <br>\"Запомнить как спам и удалить\" изучит сообщение как спам по теореме Байеса, а также вычислит нечёткие хэши, чтобы лучше блокировать подобные сообщения в дальнейшем.\n <br>Учтите, что в зависимости от технических характеристик вашей системы, изучение большого количества сообщений может занять много времени.",
"qitem": "Обьект карантина",
"quarantine": "Карантин",
"quick_actions": "Действия",

View File

@@ -20,7 +20,7 @@
"sogo_access": "Dovoli upravljanje SOGo dostopa",
"sogo_profile_reset": "Ponastavi SOGo profil",
"spam_alias": "Začasni vzdevki",
"spam_policy": "Črna lista/Bela lista",
"spam_policy": "Seznam zavrnjenih/dovoljenih",
"spam_score": "Ocena neželene pošte",
"tls_policy": "Politika TLS",
"unlimited_quota": "Neomejena kvota za poštne predale",
@@ -172,7 +172,7 @@
"excludes": "Izključuje te prejemnike",
"f2b_ban_time": "Čas blokade (s)",
"f2b_ban_time_increment": "Čas blokade se poveča z vsako blokado",
"f2b_blacklist": "Mreže/gostitelji na blacklisti",
"f2b_blacklist": "Omrežja/gostitelji na seznamu zavrnjenih",
"f2b_filter": "Regex filtri",
"f2b_max_attempts": "Največ poskusov",
"f2b_max_ban_time": "Maksimalno trajanje blokade (s)",
@@ -181,7 +181,7 @@
"f2b_parameters": "Fail2ban parametri",
"f2b_regex_info": "Upoštevajo se dnevniki SOGo, Postfix, Dovecot, PHP-FPM.",
"f2b_retry_window": "Upoštevan čas (s) za največ poskusov",
"f2b_whitelist": "Mreže/gostitelji na whitelisti",
"f2b_whitelist": "Omrežja/gostitelji na seznamu dovoljenih",
"filter_table": "Filtriraj tabelo",
"from": "Od",
"generate": "ustvari",
@@ -281,16 +281,16 @@
"rspamd_com_settings": "Ime nastavitve bo samodejno generirano. Prosim oglejte si primere nastavitev spodaj. Za več informacij si oglejte <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">dokumentacijo Rspamd</a>",
"rspamd_global_filters": "Globalne preslikave filtrov",
"rspamd_global_filters_agree": "Previden bom!",
"rspamd_global_filters_info": "Globalne preslikave filtrov vsebujejo različne vrste globalnih blacklist in whitelist.",
"rspamd_global_filters_info": "Globalni filtri vsebujejo različne vrste globalnih seznamov zavrnjenih in dovoljenih vsebin.",
"add_admin": "Dodaj skrbnika",
"add_relayhost_hint": "Prosimo zavedajte se, da se podatki za avtentikacijo, če obstajajo, shranijo v golo besedilo.",
"admin": "Skrbnik",
"api_allow_from": "Dovoli API dostop s teh IP naslovov / CIDR mrežnih zapisov",
"apps_name": "Ime aplikacije v mailcow",
"ban_list_info": "Oglejte si seznam blokiranih IP naslovov spodaj: <b>network (remaining ban time) - [actions]</b>.<br />. IPji v vrsti za odstranitev blokade bodo odstranjeni iz aktivnega seznama blokad v nekaj sekundah.<br />Rdeče oznake prikazujejo trajne blokade z blacklisto.",
"ban_list_info": "Spodaj si oglejte seznam prepovedanih IP-jev: <b>omrežje (preostali čas prepovedi) - [dejanja]</b>.<br />IP-ji, ki so v čakalni vrsti za odpravo prepovedi, bodo v nekaj sekundah odstranjeni s seznama aktivnih prepovedi.<br />Rdeče oznake označujejo aktivne trajne prepovedi s seznama zavrnjenih.",
"dkim_key_length": "Dolžina DKIM ključa (v bitih)",
"dkim_to_title": "Ciljne domene bodo prepisane",
"f2b_list_info": "Gostitelj ali omrežje na blacklisti bo vedno prevladal zapis na whitelisti. <b>Apliciranje sprememb seznama traja nekaj sekund.</b>",
"f2b_list_info": "Gostitelj ali omrežje na seznamu zavrnjenih bo vedno imelo prednost pred entiteto na seznamu dovoljenih. <b>Posodobitve seznama bodo trajale nekaj sekund, da se uporabijo.</b>",
"forwarding_hosts": "Gostitelji za posredovanje",
"forwarding_hosts_add_hint": "Lahko vpišete IPv4/IPv6 naslove, mreže v CIDR obliki, imena gostiteljev (kateri se prevedejo v IP naslove) ali imena domen (katera se prevedejo v IP naslove glede na poizvedbo po SPF zapisih, v primeru manjkajočih zapisov pa MX zapisih).",
"forwarding_hosts_hint": "Dohodna sporočila so brezpogojno sprejeta od katerih koli gostiteljev v tem seznamu. Ti gostitelji se ne bodo preverjali po DNSBL seznamih in ne bodo dodani v greyliste. Prejeti spam s teh gostiteljev ni nikoli zavrnjen, opcijsko pa se lahko premakne v mapo neželene pošte. Najpogostejša uporaba za to je navedba poštnih strežnikov, iz katerih ste nastavili pravilo za posredovanje pošte na vaš mailcow strežnik.",
@@ -306,7 +306,7 @@
"relayhosts_hint": "Določite transporte glede na pošiljatelja, da jih lahko izberete v konfiguraciji domene.<br>\nTransportni servis je vedno \"smtp:\" in bo poskušal s TLS ko bo na voljo. Wrapped TLS (SMTPS) ni podprto. Upošteva se uporabnikova politika odhodnega TLS.<br>\nVpliva na izbrane domene vključno z alias domenami.",
"transport_dest_format": "Regex ali sintaksa: example.org, .example.org, *, box@example.org (več vrednosti ločite z vejico)",
"transport_test_rcpt_info": "&#8226; Uporabite null@hosted.mailcow.de za testiranje relaya na drugo destinacijo.",
"rspamd_global_filters_regex": "Njihovi nazivi pojasnijo njihov namen. Vsa vsebina mora imeti veljaven regular expression v obliki \"/pattern/options\" (npr. <code>/.+@domain\\.tld/i</code>).<br>\nČeprav se v vsaki vrstici regexa izvedejo osnovni pregledi, je lahko funkcionalnost programa Rspamd motena, če sintaksa ni pravilna.<br>\nRspamd bo poskušal prebrati vsebino preslikave, ko bo spremenjena. Če imate težave, <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">ponovno zaženite Rspamd</a>, da prisilite ponovno nalaganje preslikav.<br> Elementi z Blackliste so izključeni iz karantene.",
"rspamd_global_filters_regex": "Njihovi nazivi pojasnijo njihov namen. Vsa vsebina mora imeti veljaven regular expression v obliki \"/pattern/options\" (npr. <code>/.+@domain\\.tld/i</code>).<br>\nČeprav se v vsaki vrstici regexa izvedejo osnovni pregledi, je lahko funkcionalnost programa Rspamd motena, če sintaksa ni pravilna.<br>\nRspamd bo poskušal prebrati vsebino preslikave, ko bo spremenjena. Če imate težave, <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">ponovno zaženite Rspamd</a>, da prisilite ponovno nalaganje preslikav.<br> Elementi na seznamu zavrnjenih so izključeni iz karantene.",
"rspamd_settings_map": "Preslikava nastavitev Rspamd",
"sal_level": "Moo stopnja",
"save": "Shrani spremembe",
@@ -408,7 +408,8 @@
"restore_template": "Za obnovitev privzete predloge pustite polje prazno.",
"task": "Naloga",
"user_link": "Uporabniška povezava",
"iam_realm": "Realm"
"iam_realm": "Realm",
"needs_restart": "potreben je ponovni zagon"
},
"danger": {
"alias_goto_identical": "Alias in goto naslov morata biti identična",
@@ -549,7 +550,11 @@
"recovery_email_failed": "E-poštnega sporočila za obnovitev ni bilo mogoče poslati. Obrnite se na skrbnika.",
"required_data_missing": "Manjkajo zahtevani podatki %s",
"reset_token_limit_exceeded": "Omejitev žetonov za ponastavitev je bila presežena. Poskusite znova pozneje.",
"to_invalid": "Polje za prejemnika ne sme biti prazno"
"to_invalid": "Polje za prejemnika ne sme biti prazno",
"max_age_invalid": "Najvišja starost %s je neveljavna",
"mode_invalid": "Način %s ni veljaven",
"mx_invalid": "Zapis MX %s je neveljaven",
"version_invalid": "Različica %s je neveljavna"
},
"debug": {
"containers_info": "Informacije o vsebniku (containerju)",
@@ -745,7 +750,7 @@
"sogo_visible_info": "Ta možnost vpliva samo na objekte, ki jih je mogoče prikazati v SOGo (naslovi aliasov v skupni rabi ali brez nje, ki kažejo na vsaj en lokalni poštni predal). Če je skrita, vzdevek ne bo prikazan kot izbirni pošiljatelj v SOGo.",
"spam_alias": "Ustvarjanje ali spreminjanje časovno omejenih vzdevkovnih naslovov",
"spam_filter": "Filter neželene pošte",
"spam_policy": "Dodajanje ali odstranjevanje elementov na beli/črni seznam",
"spam_policy": "Dodajanje ali odstranjevanje elementov na seznam dovoljenih/zavrnjenih",
"spam_score": "Nastavite oceno neželene pošte po meri",
"subfolder2": "Sinhroniziraj v podmapo na cilju<br><small>(prazno = ne uporabi podmape)</small>",
"syncjob": "Urejanje sinhronizacijskega opravila",
@@ -760,7 +765,18 @@
"mailbox_rename": "Preimenuj poštni predal",
"mailbox_rename_agree": "Ustvaril/a sem varnostno kopijo.",
"mailbox_rename_warning": "POMEMBNO! Pred preimenovanjem nabiralnika ustvarite varnostno kopijo.",
"sieve_desc": "Kratek opis"
"sieve_desc": "Kratek opis",
"mta_sts": "MTA-STS",
"mta_sts_info": "<a href='https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_MTA_Strict_Transport_Security' target='_blank'>MTA-STS</a> je standard, ki vsiljuje dostavo e-pošte med poštnimi strežniki z uporabo TLS z veljavnimi potrdili. <br>Uporablja se, kadar <a target='_blank' href='https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities'>DANE</a> ni mogoč zaradi manjkajočega ali nepodprtega DNSSEC.<br><b>Opomba</b>: Če prejemna domena podpira DANE z DNSSEC, je DANE <b>vedno</b> prednost MTA-STS deluje le kot rezervna možnost.",
"mta_sts_version": "Različica",
"mta_sts_version_info": "Določa različico standarda MTA-STS trenutno je veljavna samo različica <code>STSv1</code>.",
"mta_sts_mode": "Način",
"mta_sts_mode_info": "Na voljo so trije načini:<ul><li><em>testiranje</em> pravilnik se samo spremlja, kršitve nimajo vpliva.</li><li><em>uveljavljanje</em> pravilnik se strogo uveljavlja, povezave brez veljavnega TLS so zavrnjene.</li><li><em>brez</em> pravilnik je objavljen, vendar se ne uporablja.</li></ul>",
"mta_sts_max_age": "Najvišja starost",
"mta_sts_max_age_info": "Čas v sekundah, ki ga lahko prejemni poštni strežniki shranijo v predpomnilnik, dokler se ne ponovno naloži.",
"mta_sts_mx": "MX strežnik",
"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)."
},
"footer": {
"restart_container_info": "<b>Pomembno:</b> Ugoden ponovni zagon lahko traja nekaj časa, zato počakajte, da se konča.",
@@ -798,7 +814,8 @@
"other_logins": "ali se prijavite s/z",
"reset_password": "Ponastavi geslo",
"request_reset_password": "Zahteva za spremembo gesla",
"username": "Uporabniško ime"
"username": "Uporabniško ime",
"email": "E-poštni naslov"
},
"mailbox": {
"last_mail_login": "Zadnja prijava v e-pošto",
@@ -1013,7 +1030,7 @@
"medium_danger": "Srednje",
"notified": "Obveščen",
"low_danger": "Nizko",
"qinfo": "Sistem karantene bo zavrnjeno pošto shranil v zbirko podatkov (pošiljatelj ne bo imel vtisa, da je bila pošta dostavljena), prav tako pa bo pošto, ki bo dostavljena kot kopija, shranil v mapo »Neželena pošta« v nabiralniku.\n<br>»Uči kot neželeno pošto in izbriši« bo sporočilo prepoznal kot neželeno pošto prek Bayesovega izreka in izračunal tudi mehke zgoščene vrednosti, da bi v prihodnje zavrnil podobna sporočila.\n<br>Upoštevajte, da je učenje več sporočil lahko odvisno od vašega sistema zamudno.<br>Elementi na črnem seznamu so izključeni iz karantene.",
"qinfo": "Sistem karantene bo zavrnjeno pošto shranil v zbirko podatkov (pošiljatelj ne bo imel vtisa, da je bila pošta dostavljena), prav tako pa bo pošto, ki bo dostavljena kot kopija, shranil v mapo »Neželena pošta« v nabiralniku.\n<br>»Uči kot neželeno pošto in izbriši« bo sporočilo prepoznal kot neželeno pošto prek Bayesovega izreka in izračunal tudi mehke zgoščene vrednosti, da bi v prihodnje zavrnil podobna sporočila.\n<br>Upoštevajte, da je učenje več sporočil lahko odvisno od vašega sistema zamudno.<br>Elementi na seznamu zavrnjenih so izključeni iz karantene.",
"junk_folder": "Mapa z neželeno pošto",
"action": "Dejanje",
"atts": "Priloge",
@@ -1232,8 +1249,8 @@
"pushover_vars": "Če filter pošiljatelja ni definiran, bodo upoštevana vsa e-poštna sporočila.<br>Filtre regularnih izrazov in natančna preverjanja pošiljateljev je mogoče definirati posamično in bodo obravnavana zaporedno. Niso odvisna drug od drugega.<br>Uporabne spremenljivke za besedilo in naslov (upoštevajte pravilnike o varstvu podatkov)",
"quarantine_notification_info": "Ko je obvestilo poslano, bodo elementi označeni kot »obveščeni« in za ta določen element ne bodo poslana nobena nadaljnja obvestila.",
"verify": "Preveri",
"spamfilter_bl_desc": "E-poštni naslovi na črnem seznamu, ki jih <b>vedno</b> razvrstite kot neželeno pošto in zavrnete. Zavrnjena pošta <b>ne</b> bo kopirana v karanteno. Uporabite lahko nadomestne znake. Filter se uporabi samo za neposredne vzdevke (vzdevke z enim samim ciljnim nabiralnikom), izključujoč vseobsegajoče vzdevke in sam nabiralnik.",
"spamfilter_wl_desc": "E-poštni naslovi na belem seznamu so programirani tako, da se <b>nikoli</b> ne razvrstijo kot neželena pošta. Uporabijo se lahko nadomestni znaki. Filter se uporabi samo za neposredne vzdevke (vzdevke z enim samim ciljnim poštnim predalom), izključujoč vseobsegajoče vzdevke in sam poštni predal.",
"spamfilter_bl_desc": "E-poštni naslovi na seznamu zavrnjenih, ki bodo <b>vedno</b> razvrščeni kot neželena pošta in zavrnjeni. Zavrnjena pošta <b>ne</b> bo kopirana v karanteno. Uporabite lahko nadomestne znake. Filter se uporabi samo za neposredne vzdevke (vzdevke z enim samim ciljnim nabiralnikom), izključujoč vseobsegajoče vzdevke in sam nabiralnik.",
"spamfilter_wl_desc": "E-poštni naslovi na seznamu dovoljenih so programirani tako, da se <b>nikoli</b> ne razvrstijo kot neželena pošta. Uporabijo se lahko nadomestni znaki. Filter se uporabi samo za neposredne vzdevke (vzdevke z enim samim ciljnim poštnim predalom), izključujoč vseobsegajoče vzdevke in sam poštni predal.",
"tls_policy_warning": "<strong>Opozorilo:</strong> Če se odločite za uveljavitev šifriranega prenosa pošte, lahko izgubite e-pošto.<br>Sporočila, ki ne ustrezajo pravilniku, bo poštni sistem zavrnil s popolno napako.<br>Ta možnost velja za vaš primarni e-poštni naslov (prijavno ime), vse naslove, izpeljane iz vzdevkov domen, in vzdevke, <b>ki imajo samo ta en poštni predal</b> kot cilj.",
"allowed_protocols": "Dovoljeni protokoli",
"title": "Naslov",
@@ -1341,7 +1358,7 @@
"spam_score_reset": "Ponastavi na privzete nastavitve strežnika",
"spamfilter": "Filter neželene pošte",
"spamfilter_behavior": "Ocena",
"spamfilter_bl": "Črna lista",
"spamfilter_bl": "Seznam zavrnjenih",
"spamfilter_default_score": "Privzete vrednosti",
"spamfilter_green": "Zelena: to sporočilo ni neželena pošta",
"spamfilter_hint": "Prva vrednost opisuje »nizko oceno neželene pošte«, druga pa »visoko oceno neželene pošte«.",
@@ -1352,7 +1369,7 @@
"spamfilter_table_empty": "Ni podatkov za prikaz",
"spamfilter_table_remove": "odstrani",
"spamfilter_table_rule": "Pravilo",
"spamfilter_wl": "Bela lista",
"spamfilter_wl": "Seznam dovoljenih",
"spamfilter_yellow": "Rumena: to sporočilo je morda neželena pošta, označeno bo kot neželena pošta in premaknjeno v mapo z neželeno pošto",
"status": "Stanje",
"sync_jobs": "Sinhronizacija opravil",

View File

@@ -1324,4 +1324,4 @@
"hold_mail": "保留",
"unhold_mail": "取消保留"
}
}
}

30
data/web/mta-sts.php Normal file
View File

@@ -0,0 +1,30 @@
<?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
if (!isset($_SERVER['HTTP_HOST']) || strpos($_SERVER['HTTP_HOST'], 'mta-sts.') !== 0) {
http_response_code(404);
exit;
}
$domain = str_replace('mta-sts.', '', $_SERVER['HTTP_HOST']);
$mta_sts = mailbox('get', 'mta_sts', $domain);
if (count($mta_sts) == 0 ||
!isset($mta_sts['version']) ||
!isset($mta_sts['mode']) ||
!isset($mta_sts['max_age']) ||
!isset($mta_sts['mx']) ||
$mta_sts['active'] != 1) {
http_response_code(404);
exit;
}
header('Content-Type: text/plain; charset=utf-8');
echo "version: {$mta_sts['version']}\n";
echo "mode: {$mta_sts['mode']}\n";
echo "max_age: {$mta_sts['max_age']}\n";
foreach ($mta_sts['mx'] as $mx) {
echo "mx: {$mx}\n";
}
?>

View File

@@ -118,8 +118,8 @@
<span class="d-none d-sm-inline"> - </span>
{% if active_ban.queued_for_unban == 0 %}
<a data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"unban"}' href="#">[{{ lang.admin.queue_unban }}]</a>
<a data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"whitelist"}' href="#">[whitelist]</a>
<a data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"blacklist"}' href="#">[blacklist (<b>needs restart</b>)]</a>
<a data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"whitelist"}' href="#">[allowlist]</a>
<a data-action="edit_selected" data-item="{{ active_ban.network }}" data-id="f2b-quick" data-api-url='edit/fail2ban' data-api-attr='{"action":"blacklist"}' href="#">[denylist (<b>{{ lang.admin.needs_restart }}</b>)]</a>
{% else %}
<i>{{ lang.admin.unban_pending }}</i>
{% endif %}

View File

@@ -166,6 +166,7 @@
var lang_danger = {{ lang_danger|raw }};
var docker_timeout = {{ docker_timeout|raw }} * 1000;
var mailcow_cc_role = '{{ mailcow_cc_role }}';
{% if mailcow_cc_username %}
var mailcow_info = {
version_tag: '{{ mailcow_info.version_tag }}',
last_version_tag: '{{ mailcow_info.last_version_tag }}',
@@ -175,6 +176,17 @@
project_repo: '{{ mailcow_info.git_repo }}',
branch: '{{ mailcow_info.mailcow_branch }}'
};
{% else %}
var mailcow_info = {
version_tag: '',
last_version_tag: '',
updatedAt: '',
project_url: '',
project_owner: '',
project_repo: '',
branch: ''
};
{% endif %}
$(window).scroll(function() {
sessionStorage.scrollTop = $(this).scrollTop();

View File

@@ -6,6 +6,7 @@
<br>
<form class="form-horizontal" data-id="editalias" role="form" method="post">
<input type="hidden" value="0" name="active">
<input type="hidden" value="0" name="internal">
{% if not skip_sogo %}
<input type="hidden" value="0" name="sogo_visible">
{% endif %}
@@ -33,8 +34,12 @@
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_visible"{% if result.sogo_visible == '1' %} checked{% endif %}> {{ lang.edit.sogo_visible }}</label>
</div>
<p class="text-muted">{{ lang.edit.sogo_visible_info }}</p>
<small class="text-muted d-block mb-2">{{ lang.edit.sogo_visible_info }}</small>
{% endif %}
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="internal"{% if result.internal == '1' %} checked{% endif %}> {{ lang.edit.internal }}</label>
</div>
<small class="text-muted d-block">{{ lang.edit.internal_info }}</small>
</div>
</div>
<hr>

View File

@@ -8,6 +8,7 @@
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dratelimit">{{ lang.edit.ratelimit }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dspamfilter">{{ lang.edit.spam_filter }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dqwbcc">{{ lang.edit.quota_warning_bcc }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dmtasts">{{ lang.edit.mta_sts }}</button></li>
<li role="presentation" class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#dfooter">{{ lang.edit.domain_footer }}</button></li>
</ul>
<hr class="d-none d-md-block">
@@ -278,6 +279,82 @@
</div>
</div>
</div>
<div id="dmtasts" class="tab-pane fade" role="tabpanel" aria-labelledby="domain-mtasts">
<div class="card mb-4">
<div class="card-header d-flex d-md-none fs-5">
<button class="btn flex-grow-1 text-start" data-bs-target="#collapse-tab-mtasts" data-bs-toggle="collapse" aria-controls="collapse-tab-mtasts">
{{ lang.edit.mta_sts }} <span class="badge bg-info table-lines"></span>
</button>
</div>
<div id="collapse-tab-mtasts" class="card-body collapse" data-bs-parent="#domain-content">
<h4>{{ lang.edit.mta_sts }}</h4>
<p>{{ lang.edit.mta_sts_info|raw }}</p>
<form data-id="dommtasts" method="post">
<input type="hidden" value="0" name="active">
<input type="hidden" value="{{ domain }}" name="domain">
<div class="row mb-2">
<label class="control-label col-sm-2" for="version">
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill m-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.edit.mta_sts_version_info|raw }}"></i>
{{ lang.edit.mta_sts_version }}
</label>
<div class="col-sm-10">
<select data-style="btn btn-light" class="form-control" name="version" title="" required>
<option value="stsv1"{% if mta_sts.version == 'STSv1' %} selected{% endif %}>STSv1</option>
</select>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="mode">
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill m-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.edit.mta_sts_mode_info|raw }}"></i>
{{ lang.edit.mta_sts_mode }}
</label>
<div class="col-sm-10">
<select data-style="btn btn-light" class="form-control" name="mode" title="" required>
<option value="enforce"{% if mta_sts.mode == 'enforce' %} selected{% endif %}>enforce</option>
<option value="testing"{% if mta_sts.mode == 'testing' %} selected{% endif %}>testing</option>
<option value="none"{% if mta_sts.mode == 'none' %} selected{% endif %}>none</option>
</select>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="max_age">
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill m-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.edit.mta_sts_max_age_info|raw }}"></i>
{{ lang.edit.mta_sts_max_age }}
</label>
<div class="col-sm-10">
<input type="number" class="form-control" name="max_age" value="{{ mta_sts.max_age }}">
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2" for="mx">
<i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill m-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.edit.mta_sts_mx_info|raw }}"></i>
{{ lang.edit.mta_sts_mx }}
</label>
<div class="col-sm-10">
<textarea autocorrect="off" autocapitalize="none" class="form-control" rows="5" name="mx">{{ mta_sts.mx }}</textarea>
<small class="text-muted">{{ lang.edit.mta_sts_mx_notice|raw }}</small>
</div>
</div>
<div class="row mb-4">
<div class="offset-sm-2 col-sm-10">
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if mta_sts.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
</div>
</div>
</div>
<div class="row mb-2">
<div class="offset-sm-2 col-sm-10">
{% if mta_sts == false %}
<button class="btn btn-xs-lg d-block d-sm-inline btn-secondary" data-action="add_item" data-id="dommtasts" data-item="{{ domain }}" data-api-url='add/mta-sts' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
{% else %}
<button class="btn btn-xs-lg d-block d-sm-inline btn-secondary" data-action="edit_selected" data-id="dommtasts" data-item="{{ domain }}" data-api-url='edit/mta-sts' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>
{% endif %}
</div>
</div>
</form>
</div>
</div>
</div>
<div id="dfooter" class="tab-pane fade" role="tabpanel" aria-labelledby="domain-footer">
<div class="card mb-4">
<div class="card-header d-flex d-md-none fs-5">

View File

@@ -36,6 +36,23 @@
<small class="text-muted">0 = ∞</small>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2">{{ lang.user.tag_handling }}</label>
<div class="col-sm-10">
<div class="btn-group">
<input type="radio" class="btn-check" name="tagged_mail_handler" id="tagged_mail_handler_subfolder" autocomplete="off" value="subfolder" {% if template.attributes.tagged_mail_handler == 'subfolder' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="tagged_mail_handler_subfolder">{{ lang.user.tag_in_subfolder }}</label>
<input type="radio" class="btn-check" name="tagged_mail_handler" id="tagged_mail_handler_subject" autocomplete="off" value="subject" {% if template.attributes.tagged_mail_handler == 'subject' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="tagged_mail_handler_subject">{{ lang.user.tag_in_subject }}</label>
<input type="radio" class="btn-check" name="tagged_mail_handler" id="tagged_mail_handler_none" autocomplete="off" value="none" {% if template.attributes.tagged_mail_handler == 'none' %}checked{% endif %}>
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="tagged_mail_handler_none">{{ lang.user.tag_in_none }}</label>
</div>
<p class="text-muted"><small>{{ lang.user.tag_help_explain|raw }}</small></p>
<p class="text-muted"><small>{{ lang.user.tag_help_example|raw }}</small></p>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2">{{ lang.user.quarantine_notification }}</label>
<div class="col-sm-10">

View File

@@ -117,7 +117,7 @@
<div class="row mb-2">
<label class="control-label col-sm-2" for="relayhost">{{ lang.edit.relayhost }}</label>
<div class="col-sm-10">
<select data-acl="{{ acl.mailbox_relayhost }}" data-live-search="true" id="relayhost" name="relayhost" class="form-control mb-4">
<select data-acl="{{ acl.mailbox_relayhost }}" data-live-search="true" id="relayhost" name="relayhost" class="form-control">
{% for rlyhost in rlyhosts %}
<option
style="{% if rlyhost.active != '1' %}background: #ff4136; color: #fff{% endif %}"
@@ -131,7 +131,34 @@
</option>
</select>
<p class="d-block d-sm-none" style="margin: 0;padding: 0">&nbsp;</p>
<small class="text-muted d-block">{{ lang.edit.mailbox_relayhost_info }}</small>
<small class="text-muted d-block mb-4">{{ lang.edit.mailbox_relayhost_info }}</small>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2">{{ lang.user.tag_handling }}</label>
<div class="col-sm-10">
<div class="btn-group" data-acl="{{ acl.delimiter_action }}">
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if get_tagging_options == 'subfolder' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="delimiter_action"
data-api-url='edit/delimiter_action'
data-api-attr='{"tagged_mail_handler":"subfolder"}'>{{ lang.user.tag_in_subfolder }}</button>
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if get_tagging_options == 'subject' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="delimiter_action"
data-api-url='edit/delimiter_action'
data-api-attr='{"tagged_mail_handler":"subject"}'>{{ lang.user.tag_in_subject }}</button>
<button type="button" class="btn btn-sm btn-xs-third d-block d-sm-inline{% if get_tagging_options == 'none' %} btn-dark{% else %} btn-light{% endif %}"
data-action="edit_selected"
data-item="{{ mailbox }}"
data-id="delimiter_action"
data-api-url='edit/delimiter_action'
data-api-attr='{"tagged_mail_handler":"none"}'>{{ lang.user.tag_in_none }}</button>
</div>
<p class="text-muted"><small>{{ lang.user.tag_help_explain|raw }}</small></p>
<p class="text-muted"><small>{{ lang.user.tag_help_example|raw }}</small></p>
</div>
</div>
<div class="row mb-2">

View File

@@ -76,6 +76,23 @@
<div class="badge fs-5 bg-warning addInputQuotaExhausted" style="display:none;">{{ lang.warning.quota_exceeded_scope }}</div>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2 text-sm-end text-sm-end">{{ lang.user.tag_handling }}</label>
<div class="col-sm-10">
<div class="btn-group">
<input type="radio" class="btn-check" name="tagged_mail_handler" id="tagged_mail_handler_subfolder" autocomplete="off" value="subfolder">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="tagged_mail_handler_subfolder">{{ lang.user.tag_in_subfolder }}</label>
<input type="radio" class="btn-check" name="tagged_mail_handler" id="tagged_mail_handler_subject" autocomplete="off" value="subject">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="tagged_mail_handler_subject">{{ lang.user.tag_in_subject }}</label>
<input type="radio" class="btn-check" name="tagged_mail_handler" id="tagged_mail_handler_none" autocomplete="off" value="none">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="tagged_mail_handler_none">{{ lang.user.tag_in_none }}</label>
</div>
<p class="text-muted"><small>{{ lang.user.tag_help_explain|raw }}</small></p>
<p class="text-muted"><small>{{ lang.user.tag_help_example|raw }}</small></p>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2 text-sm-end text-sm-end">{{ lang.user.quarantine_notification }}</label>
<div class="col-sm-10">
@@ -246,6 +263,23 @@
<small class="text-muted">0 = ∞</small>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2 text-sm-end text-sm-end">{{ lang.user.tag_handling }}</label>
<div class="col-sm-10">
<div class="btn-group">
<input type="radio" class="btn-check" name="tagged_mail_handler" id="template_tagged_mail_handler_subfolder" autocomplete="off" value="subfolder">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_tagged_mail_handler_subfolder">{{ lang.user.tag_in_subfolder }}</label>
<input type="radio" class="btn-check" name="tagged_mail_handler" id="template_tagged_mail_handler_subject" autocomplete="off" value="subject">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_tagged_mail_handler_subject">{{ lang.user.tag_in_subject }}</label>
<input type="radio" class="btn-check" name="tagged_mail_handler" id="template_tagged_mail_handler_none" autocomplete="off" value="none">
<label class="btn btn-sm btn-xs-quart d-block d-sm-inline btn-light" for="template_tagged_mail_handler_none">{{ lang.user.tag_in_none }}</label>
</div>
<p class="text-muted"><small>{{ lang.user.tag_help_explain|raw }}</small></p>
<p class="text-muted"><small>{{ lang.user.tag_help_example|raw }}</small></p>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-2 text-sm-end text-sm-end">{{ lang.user.quarantine_notification }}</label>
<div class="col-sm-10">
@@ -743,6 +777,7 @@
<div class="modal-body">
<form class="form-horizontal" data-cached-form="true" role="form" data-id="add_alias">
<input type="hidden" value="0" name="active">
<input type="hidden" value="0" name="internal">
<div class="row mb-2">
<label class="control-label col-sm-2 text-sm-end" for="address">{{ lang.add.alias_address }}</label>
<div class="col-sm-10">
@@ -769,11 +804,15 @@
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="sogo_visible" checked> {{ lang.edit.sogo_visible }}</label>
</div>
<p class="text-muted">{{ lang.edit.sogo_visible_info }}</p>
<small class="text-muted d-block mb-2">{{ lang.edit.sogo_visible_info }}</small>
{% endif %}
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="internal"> {{ lang.add.internal }}</label>
</div>
<small class="text-muted d-block">{{ lang.edit.internal_info }}</small>
</div>
</div>
<div class="row mb-2">
<div class="row mb-4">
<div class="offset-sm-2 col-sm-10">
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="active" checked> {{ lang.add.active }}</label>

View File

@@ -48,7 +48,7 @@
<label class="visually-hidden" for="login_user">{{ lang.login.username }}</label>
<div class="input-group">
<div class="input-group-text"><i class="bi bi-person-fill"></i></div>
<input name="login_user" autocorrect="off" autocapitalize="none" type="{% if is_mobileconfig %}email{% else %}text{% endif %}" id="login_user" class="form-control" placeholder="{{ lang.login.username }}" required="" autofocus="" autocomplete="username">
<input name="login_user" autocorrect="off" autocapitalize="none" type="{% if is_mobileconfig %}email{% else %}text{% endif %}" id="login_user" class="form-control" placeholder="{{ lang.login.email }}" required="" autofocus="" autocomplete="username">
</div>
</div>
<div class="d-flex mt-3">

View File

@@ -65,7 +65,7 @@ services:
- redis
clamd-mailcow:
image: ghcr.io/mailcow/clamd:1.70
image: ghcr.io/mailcow/clamd:1.71
restart: always
depends_on:
unbound-mailcow:
@@ -84,7 +84,7 @@ services:
- clamd
rspamd-mailcow:
image: ghcr.io/mailcow/rspamd:2.2
image: ghcr.io/mailcow/rspamd:2.3
stop_grace_period: 30s
depends_on:
- dovecot-mailcow
@@ -200,7 +200,7 @@ services:
- phpfpm
sogo-mailcow:
image: ghcr.io/mailcow/sogo:1.133
image: ghcr.io/mailcow/sogo:1.134
environment:
- DBNAME=${DBNAME}
- DBUSER=${DBUSER}
@@ -251,7 +251,7 @@ services:
- sogo
dovecot-mailcow:
image: ghcr.io/mailcow/dovecot:2.34
image: ghcr.io/mailcow/dovecot:2.35
depends_on:
- mysql-mailcow
- netfilter-mailcow
@@ -338,12 +338,14 @@ services:
- dovecot
postfix-mailcow:
image: ghcr.io/mailcow/postfix:1.80
image: ghcr.io/mailcow/postfix:1.81
depends_on:
mysql-mailcow:
condition: service_started
unbound-mailcow:
condition: service_healthy
postfix-tlspol-mailcow:
condition: service_started
volumes:
- ./data/hooks/postfix:/hooks:Z
- ./data/conf/postfix:/opt/postfix/conf:z
@@ -378,6 +380,28 @@ services:
aliases:
- postfix
postfix-tlspol-mailcow:
image: ghcr.io/mailcow/postfix-tlspol:1.0
depends_on:
unbound-mailcow:
condition: service_healthy
volumes:
- postfix-tlspol-vol-1:/var/lib/postfix-tlspol
environment:
- LOG_LINES=${LOG_LINES:-9999}
- TZ=${TZ}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- REDISPASS=${REDISPASS}
- DEV_MODE=${DEV_MODE:-n}
restart: always
dns:
- ${IPV4_NETWORK:-172.22.1}.254
networks:
mailcow-network:
aliases:
- postfix-tlspol
memcached-mailcow:
image: memcached:alpine
restart: always
@@ -394,7 +418,7 @@ services:
- php-fpm-mailcow
- sogo-mailcow
- rspamd-mailcow
image: ghcr.io/mailcow/nginx:1.03
image: ghcr.io/mailcow/nginx:1.04
dns:
- ${IPV4_NETWORK:-172.22.1}.254
environment:
@@ -405,7 +429,7 @@ services:
- TZ=${TZ}
- SKIP_SOGO=${SKIP_SOGO:-n}
- SKIP_RSPAMD=${SKIP_RSPAMD:-n}
- DISABLE_IPv6=${DISABLE_IPv6:-n}
- ENABLE_IPV6=${ENABLE_IPV6:-true}
- HTTP_REDIRECT=${HTTP_REDIRECT:-n}
- PHPFPMHOST=${PHPFPMHOST:-}
- SOGOHOST=${SOGOHOST:-}
@@ -440,7 +464,7 @@ services:
condition: service_started
unbound-mailcow:
condition: service_healthy
image: ghcr.io/mailcow/acme:1.93
image: ghcr.io/mailcow/acme:1.94
dns:
- ${IPV4_NETWORK:-172.22.1}.254
environment:
@@ -477,7 +501,7 @@ services:
- acme
netfilter-mailcow:
image: ghcr.io/mailcow/netfilter:1.61
image: ghcr.io/mailcow/netfilter:1.62
stop_grace_period: 30s
restart: always
privileged: true
@@ -497,7 +521,7 @@ services:
- /lib/modules:/lib/modules:ro
watchdog-mailcow:
image: ghcr.io/mailcow/watchdog:2.08
image: ghcr.io/mailcow/watchdog:2.09
dns:
- ${IPV4_NETWORK:-172.22.1}.254
tmpfs:
@@ -553,6 +577,7 @@ services:
- MYSQL_REPLICATION_THRESHOLD=${MYSQL_REPLICATION_THRESHOLD:-1}
- SOGO_THRESHOLD=${SOGO_THRESHOLD:-3}
- POSTFIX_THRESHOLD=${POSTFIX_THRESHOLD:-8}
- POSTFIX_TLSPOL_THRESHOLD=${POSTFIX_TLSPOL_THRESHOLD:-8}
- CLAMD_THRESHOLD=${CLAMD_THRESHOLD:-15}
- DOVECOT_THRESHOLD=${DOVECOT_THRESHOLD:-12}
- DOVECOT_REPL_THRESHOLD=${DOVECOT_REPL_THRESHOLD:-20}
@@ -564,6 +589,7 @@ services:
- OLEFY_THRESHOLD=${OLEFY_THRESHOLD:-5}
- MAILQ_THRESHOLD=${MAILQ_THRESHOLD:-20}
- MAILQ_CRIT=${MAILQ_CRIT:-30}
- DEV_MODE=${DEV_MODE:-n}
networks:
mailcow-network:
aliases:
@@ -629,41 +655,12 @@ services:
aliases:
- ofelia
ipv6nat-mailcow:
depends_on:
- unbound-mailcow
- mysql-mailcow
- redis-mailcow
- clamd-mailcow
- rspamd-mailcow
- php-fpm-mailcow
- sogo-mailcow
- dovecot-mailcow
- postfix-mailcow
- memcached-mailcow
- nginx-mailcow
- acme-mailcow
- netfilter-mailcow
- watchdog-mailcow
- dockerapi-mailcow
environment:
- TZ=${TZ}
image: robbertkl/ipv6nat
security_opt:
- label=disable
restart: always
privileged: true
network_mode: "host"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /lib/modules:/lib/modules:ro
networks:
mailcow-network:
driver: bridge
driver_opts:
com.docker.network.bridge.name: br-mailcow
enable_ipv6: true
enable_ipv6: ${ENABLE_IPV6:-true}
ipam:
driver: default
config:
@@ -678,6 +675,7 @@ volumes:
redis-vol-1:
rspamd-vol-1:
postfix-vol-1:
postfix-tlspol-vol-1:
crypt-vol-1:
sogo-web-vol-1:
sogo-userdata-backup-vol-1:

View File

@@ -1,32 +1,13 @@
#!/usr/bin/env bash
# Load mailcow Generic Scripts
source _modules/scripts/core.sh
source _modules/scripts/ipv6_controller.sh
set -o pipefail
if [[ "$(uname -r)" =~ ^4\.15\.0-60 ]]; then
echo "DO NOT RUN mailcow ON THIS UBUNTU KERNEL!";
echo "Please update to 5.x or use another distribution."
exit 1
fi
if [[ "$(uname -r)" =~ ^4\.4\. ]]; then
if grep -q Ubuntu <<< "$(uname -a)"; then
echo "DO NOT RUN mailcow ON THIS UBUNTU KERNEL!";
echo "Please update to linux-generic-hwe-16.04 by running \"apt-get install --install-recommends linux-generic-hwe-16.04\""
exit 1
fi
fi
if grep --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo "BusyBox grep detected, please install gnu grep, \"apk add --no-cache --upgrade grep\""; exit 1; fi
# This will also cover sort
if cp --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo "BusyBox cp detected, please install coreutils, \"apk add --no-cache --upgrade coreutils\""; exit 1; fi
if sed --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo "BusyBox sed detected, please install gnu sed, \"apk add --no-cache --upgrade sed\""; exit 1; fi
for bin in openssl curl docker git awk sha1sum grep cut; do
if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi
done
# Check Docker Version (need at least 24.X)
docker_version=$(docker version --format '{{.Server.Version}}' | cut -d '.' -f 1)
get_installed_tools
get_docker_version
if [[ $docker_version -lt 24 ]]; then
echo -e "\e[31mCannot find Docker with a Version higher or equals 24.0.0\e[0m"
@@ -35,65 +16,7 @@ if [[ $docker_version -lt 24 ]]; then
exit 1
fi
if docker compose > /dev/null 2>&1; then
if docker compose version --short | grep -e "^2." -e "^v2." > /dev/null 2>&1; then
COMPOSE_VERSION=native
echo -e "\e[33mFound Docker Compose Plugin (native).\e[0m"
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
sleep 2
echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
else
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
exit 1
fi
elif docker-compose > /dev/null 2>&1; then
if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
if docker-compose version --short | grep "^2." > /dev/null 2>&1; then
COMPOSE_VERSION=standalone
echo -e "\e[33mFound Docker Compose Standalone.\e[0m"
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
sleep 2
echo -e "\e[33mNotice: For an automatic update of docker-compose please use the update_compose.sh scripts located at the helper-scripts folder.\e[0m"
else
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
echo -e "\e[31mPlease update/install manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
exit 1
fi
fi
else
echo -e "\e[31mCannot find Docker Compose.\e[0m"
echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
exit 1
fi
detect_bad_asn() {
echo -e "\e[33mDetecting if your IP is listed on Spamhaus Bad ASN List...\e[0m"
response=$(curl --connect-timeout 15 --max-time 30 -s -o /dev/null -w "%{http_code}" "https://asn-check.mailcow.email")
if [ "$response" -eq 503 ]; then
if [ -z "$SPAMHAUS_DQS_KEY" ]; then
echo -e "\e[33mYour server's public IP uses an AS that is blocked by Spamhaus to use their DNS public blocklists for Postfix.\e[0m"
echo -e "\e[33mmailcow did not detected a value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf!\e[0m"
sleep 2
echo ""
echo -e "\e[33mTo use the Spamhaus DNS Blocklists again, you will need to create a FREE account for their Data Query Service (DQS) at: https://www.spamhaus.com/free-trial/sign-up-for-a-free-data-query-service-account\e[0m"
echo -e "\e[33mOnce done, enter your DQS API key in mailcow.conf and mailcow will do the rest for you!\e[0m"
echo ""
sleep 2
else
echo -e "\e[33mYour server's public IP uses an AS that is blocked by Spamhaus to use their DNS public blocklists for Postfix.\e[0m"
echo -e "\e[32mmailcow detected a Value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf. Postfix will use DQS with the given API key...\e[0m"
fi
elif [ "$response" -eq 200 ]; then
echo -e "\e[33mCheck completed! Your IP is \e[32mclean\e[0m"
elif [ "$response" -eq 429 ]; then
echo -e "\e[33mCheck completed! \e[31mYour IP seems to be rate limited on the ASN Check service... please try again later!\e[0m"
else
echo -e "\e[31mCheck failed! \e[0mMaybe a DNS or Network problem?\e[0m"
fi
}
detect_bad_asn
### If generate_config.sh is started with --dev or -d it will not check out nightly or master branch and will keep on the current branch
if [[ ${1} == "--dev" || ${1} == "-d" ]]; then
@@ -217,6 +140,8 @@ if [ ! -z "${MAILCOW_BRANCH}" ]; then
git_branch=${MAILCOW_BRANCH}
fi
configure_ipv6
[ ! -f ./data/conf/rspamd/override.d/worker-controller-password.inc ] && echo '# Placeholder' > ./data/conf/rspamd/override.d/worker-controller-password.inc
cat << EOF > mailcow.conf
@@ -510,6 +435,13 @@ WEBAUTHN_ONLY_TRUSTED_VENDORS=n
# Otherwise it will work normally.
SPAMHAUS_DQS_KEY=
# IPv6 Controller Section
# This variable controls the usage of IPv6 within mailcow.
# Can either be true or false | Defaults to true
# WARNING: MAKE SURE TO PROPERLY CONFIGURE IPv6 ON YOUR HOST FIRST BEFORE ENABLING THIS AS FAULTY CONFIGURATIONS CAN LEAD TO OPEN RELAYS!
# A COMPLETE DOCKER STACK REBUILD (compose down && compose up -d) IS NEEDED TO APPLY THIS.
ENABLE_IPV6=${IPV6_BOOL}
# Prevent netfilter from setting an iptables/nftables rule to isolate the mailcow docker network - y/n
# CAUTION: Disabling this may expose container ports to other neighbors on the same subnet, even if the ports are bound to localhost
DISABLE_NETFILTER_ISOLATION_RULE=n
@@ -588,6 +520,4 @@ else
echo ' $MAILCOW_UPDATEDAT='$(date +%s)';' >> data/web/inc/app_info.inc.php
echo '?>' >> data/web/inc/app_info.inc.php
echo -e "\e[33mCannot determine current git repository version...\e[0m"
fi
detect_bad_asn
fi

View File

@@ -0,0 +1,18 @@
services:
prometheus-exporter-mailcow:
image: ghcr.io/mailcow/prometheus-exporter:2
ports:
- "9099:9099"
restart: always
environment:
MAILCOW_EXPORTER_HOST: "<your-mail-domain>" # Replace with your Mailcow hostname
MAILCOW_EXPORTER_API_KEY: "<your-API-Key>" # Replace with your API key
MAILCOW_EXPORTER_TOKEN: "<your-secure-token>" # Replace with your secure key
# MAILCOW_EXPORTER_TOKEN_DISABLE: "true" # Uncomment only if it is safe to disable token authentication (e.g., internal network only)
dns:
- ${IPV4_NETWORK:-172.22.1}.254
networks:
mailcow-network:
ipv4_address: ${IPV4_NETWORK:-172.22.1}.209
aliases:
- prometheus-exporter

View File

@@ -6,9 +6,10 @@ SPFTOOLS_DIR=${WORKING_DIR}/spf-tools
POSTWHITE_DIR=${WORKING_DIR}/postwhite
POSTWHITE_CONF=${POSTWHITE_DIR}/postwhite.conf
CUSTOM_HOSTS='"web.de gmx.net mail.de freenet.de arcor.de unity-mail.de"'
CUSTOM_HOSTS='"web.de gmx.net mail.de freenet.de arcor.de unity-mail.de protonmail.ch ionos.com strato.com t-online.de"'
STATIC_HOSTS=(
"194.25.134.0/24 permit # t-online.de"
"49.12.4.251 permit # checks.mailcow.email"
"2a01:4f8:c17:7906::10 permit # checks.mailcow.email"
)
mkdir ${SCRIPT_DIR}/postwhite_tmp

1227
update.sh

File diff suppressed because it is too large Load Diff