Răsfoiți Sursa

Merge pull request #6948 from mailcow/staging

2025-12
DerLinkman 1 săptămână în urmă
părinte
comite
4ef65fc382
39 a modificat fișierele cu 1749 adăugiri și 307 ștergeri
  1. 1 1
      .github/workflows/close_old_issues_and_prs.yml
  2. 1 1
      .github/workflows/image_builds.yml
  3. 1 1
      .github/workflows/pr_to_nightly.yml
  4. 1 1
      .github/workflows/rebuild_backup_image.yml
  5. 1 1
      .github/workflows/update_postscreen_access_list.yml
  6. 7 3
      CONTRIBUTING.md
  7. 2 2
      data/Dockerfiles/backup/Dockerfile
  8. 4 3
      data/Dockerfiles/dovecot/docker-entrypoint.sh
  9. 1 1
      data/Dockerfiles/phpfpm/docker-entrypoint.sh
  10. 1 1
      data/Dockerfiles/postfix-tlspol/Dockerfile
  11. 2 2
      data/Dockerfiles/postfix/postfix.sh
  12. 0 4
      data/Dockerfiles/sogo/bootstrap-sogo.sh
  13. 1 0
      data/conf/nginx/templates/nginx.conf.j2
  14. 0 1
      data/conf/nginx/templates/sites-default.conf.j2
  15. 13 91
      data/conf/postfix/postscreen_access.cidr
  16. 6 0
      data/conf/sogo/sogo.conf
  17. 27 10
      data/web/inc/functions.mailbox.inc.php
  18. 3 2
      data/web/inc/init_db.inc.php
  19. 1 1
      data/web/inc/vars.inc.php
  20. 19 3
      data/web/js/site/user.js
  21. 1 0
      data/web/json_api.php
  22. 29 2
      data/web/lang/lang.ca-es.json
  23. 16 13
      data/web/lang/lang.cs-cz.json
  24. 5 2
      data/web/lang/lang.de-de.json
  25. 4 1
      data/web/lang/lang.en-gb.json
  26. 6 1
      data/web/lang/lang.es-es.json
  27. 40 12
      data/web/lang/lang.fr-fr.json
  28. 167 1
      data/web/lang/lang.gr-gr.json
  29. 3 0
      data/web/lang/lang.ja-jp.json
  30. 3 2
      data/web/lang/lang.nb-no.json
  31. 924 69
      data/web/lang/lang.pl-pl.json
  32. 31 7
      data/web/lang/lang.ru-ru.json
  33. 8 5
      data/web/lang/lang.si-si.json
  34. 2 1
      data/web/lang/lang.vi-vn.json
  35. 8 6
      data/web/templates/user/SpamAliases.twig
  36. 20 20
      docker-compose.yml
  37. 88 35
      helper-scripts/backup_and_restore.sh
  38. 301 0
      helper-scripts/dev_tests/test_backup_and_restore.sh
  39. 1 1
      helper-scripts/docker-compose.override.yml.d/EXTERNAL_MYSQL_SOCKET/docker-compose.override.yml

+ 1 - 1
.github/workflows/close_old_issues_and_prs.yml

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

+ 1 - 1
.github/workflows/image_builds.yml

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

+ 1 - 1
.github/workflows/pr_to_nightly.yml

@@ -8,7 +8,7 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout repository
-        uses: actions/checkout@v5
+        uses: actions/checkout@v6
         with:
           fetch-depth: 0
       - name: Run the Action

+ 1 - 1
.github/workflows/rebuild_backup_image.yml

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

+ 1 - 1
.github/workflows/update_postscreen_access_list.yml

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

+ 7 - 3
CONTRIBUTING.md

@@ -1,11 +1,11 @@
 # Contribution Guidelines
-**_Last modified on 15th August 2024_**
+**_Last modified on 12th November 2025_**
 
 First of all, thank you for wanting to provide a bugfix or a new feature for the mailcow community, it's because of your help that the project can continue to grow!
 
 As we want to keep mailcow's development structured we setup these Guidelines which helps you to create your issue/pull request accordingly.
 
-**PLEASE NOTE, THAT WE MIGHT CLOSE ISSUES/PULL REQUESTS IF THEY DON'T FULLFIL OUR WRITTEN GUIDELINES WRITTEN INSIDE THIS DOCUMENT**. So please check this guidelines before you propose a Issue/Pull Request.
+**PLEASE NOTE, THAT WE WILL CLOSE ISSUES/PULL REQUESTS IF THEY DON'T FULFILL OUR WRITTEN GUIDELINES WRITTEN INSIDE THIS DOCUMENT**. So please check this guidelines before you propose a Issue/Pull Request.
 
 ## Topics
 
@@ -27,14 +27,18 @@ However, please note the following regarding pull requests:
 6. Please **ALWAYS** create the actual pull request against the staging branch and **NEVER** directly against the master branch. *If you forget to do this, our moobot will remind you to switch the branch to staging.*
 7. Wait for a merge commit: It may happen that we do not accept your pull request immediately or sometimes not at all for various reasons. Please do not be disappointed if this is the case. We always endeavor to incorporate any meaningful changes from the community into the mailcow project.
 8. If you are planning larger and therefore more complex pull requests, it would be advisable to first announce this in a separate issue and then start implementing it after the idea has been accepted in order to avoid unnecessary frustration and effort!
+9. If your PR requires a Docker image rebuild (changes to Dockerfiles or files in data/Dockerfiles/), update the image tag in docker-compose.yml. Use the base-image versioning (e.g. ghcr.io/mailcow/sogo:5.12.4 → :5.12.5 for version bumps; append a letter for patch fixes, e.g. :5.12.4a). Follow this scheme.
 
 ---
 
 ## Issue Reporting
-**_Last modified on 15th August 2024_**
+**_Last modified on 12th November 2025_**
 
 If you plan to report a issue within mailcow please read and understand the following rules:
 
+### Security disclosures / Security-related fixes
+- Security vulnerabilities and security fixes must always be reported confidentially first to the contact address specified in SECURITY.md before they are integrated, published, or publicly disclosed in issues/PRs. Please wait for a response from the specified contact to ensure coordinated and responsible disclosure.
+
 ### Issue Reporting Guidelines
 
 1. **ONLY** use the issue tracker for bug reports or improvement requests and NOT for support questions. For support questions you can either contact the [mailcow community on Telegram](https://docs.mailcow.email/#community-support-and-chat) or the mailcow team directly in exchange for a [support fee](https://docs.mailcow.email/#commercial-support).

+ 2 - 2
data/Dockerfiles/backup/Dockerfile

@@ -1,3 +1,3 @@
-FROM debian:bookworm-slim
+FROM debian:trixie-slim
 
-RUN apt update && apt install pigz -y --no-install-recommends
+RUN apt update && apt install pigz zstd -y --no-install-recommends

+ 4 - 3
data/Dockerfiles/dovecot/docker-entrypoint.sh

@@ -204,16 +204,17 @@ EOF
 # Create random master Password for SOGo SSO
 RAND_PASS=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 32 | head -n 1)
 echo -n ${RAND_PASS} > /etc/phpfpm/sogo-sso.pass
-# Creating additional creds file for SOGo notify crons (calendars, etc)
-echo -n ${RAND_USER}@mailcow.local:${RAND_PASS} > /etc/sogo/cron.creds
 cat <<EOF > /etc/dovecot/sogo-sso.conf
 # Autogenerated by mailcow
 passdb {
   driver = static
-  args = allow_real_nets=${IPV4_NETWORK}.248/32 password={plain}${RAND_PASS}
+  args = allow_nets=${IPV4_NETWORK}.248/32 password={plain}${RAND_PASS}
 }
 EOF
 
+# Creating additional creds file for SOGo notify crons (calendars, etc) (dummy user, sso password)
+echo -n ${RAND_USER}@mailcow.local:${RAND_PASS} > /etc/sogo/cron.creds
+
 if [[ "${MASTER}" =~ ^([nN][oO]|[nN])+$ ]]; then
   # Toggling MASTER will result in a rebuild of containers, so the quota script will be recreated
   cat <<'EOF' > /usr/local/bin/quota_notify.py

+ 1 - 1
data/Dockerfiles/phpfpm/docker-entrypoint.sh

@@ -167,7 +167,7 @@ DELIMITER //
 CREATE EVENT clean_spamalias
 ON SCHEDULE EVERY 1 DAY DO
 BEGIN
-  DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP();
+  DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP() AND permanent = 0;
 END;
 //
 DELIMITER ;

+ 1 - 1
data/Dockerfiles/postfix-tlspol/Dockerfile

@@ -4,7 +4,7 @@ WORKDIR /src
 ENV CGO_ENABLED=0 \
     GO111MODULE=on \
 		NOOPT=1 \
-    VERSION=1.8.14
+    VERSION=1.8.22
 
 RUN git clone --branch v${VERSION} https://github.com/Zuplu/postfix-tlspol && \
     cd /src/postfix-tlspol && \

+ 2 - 2
data/Dockerfiles/postfix/postfix.sh

@@ -390,7 +390,7 @@ hosts = unix:/var/run/mysqld/mysqld.sock
 dbname = ${DBNAME}
 query = SELECT goto FROM spamalias
   WHERE address='%s'
-    AND validity >= UNIX_TIMESTAMP()
+    AND (validity >= UNIX_TIMESTAMP() OR permanent != 0)
 EOF
 
 if [ ! -f /opt/postfix/conf/dns_blocklists.cf ]; then
@@ -524,4 +524,4 @@ if [[ $? != 0 ]]; then
 else
   postfix -c /opt/postfix/conf start
   sleep 126144000
-fi
+fi

+ 0 - 4
data/Dockerfiles/sogo/bootstrap-sogo.sh

@@ -50,10 +50,6 @@ cat <<EOF > /var/lib/sogo/GNUstep/Defaults/sogod.plist
     <string>YES</string>
     <key>SOGoEncryptionKey</key>
     <string>${RAND_PASS}</string>
-    <key>SOGoURLEncryptionEnabled</key>
-    <string>YES</string>
-    <key>SOGoURLEncryptionPassphrase</key>
-    <string>${SOGO_URL_ENCRYPTION_KEY}</string>
     <key>OCSAdminURL</key>
     <string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_admin</string>
     <key>OCSCacheFolderURL</key>

+ 1 - 0
data/conf/nginx/templates/nginx.conf.j2

@@ -13,6 +13,7 @@ events {
 http {
     include /etc/nginx/mime.types;
     default_type  application/octet-stream;
+    server_tokens off;
 
     log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                       '$status $body_bytes_sent "$http_referer" '

+ 0 - 1
data/conf/nginx/templates/sites-default.conf.j2

@@ -14,7 +14,6 @@ ssl_session_tickets off;
 
 add_header Strict-Transport-Security "max-age=15768000;";
 add_header X-Content-Type-Options nosniff;
-add_header X-XSS-Protection "1; mode=block";
 add_header X-Robots-Tag none;
 add_header X-Download-Options noopen;
 add_header X-Frame-Options "SAMEORIGIN" always;

+ 13 - 91
data/conf/postfix/postscreen_access.cidr

@@ -1,6 +1,6 @@
-# Whitelist generated by Postwhite v3.4 on Wed Oct  1 00:21:33 UTC 2025
+# Whitelist generated by Postwhite v3.4 on Mon Dec  1 00:24:43 UTC 2025
 # https://github.com/stevejenkins/postwhite/
-# 2216 total rules
+# 2186 total rules
 2a00:1450:4000::/36	permit
 2a01:111:f400::/48	permit
 2a01:111:f403:2800::/53	permit
@@ -29,7 +29,9 @@
 2a01:b747:3005:200::/56	permit
 2a01:b747:3006:200::/56	permit
 2a02:a60:0:5::/64	permit
+2a0f:f640::/56	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
@@ -50,14 +52,11 @@
 8.25.194.0/23	permit
 8.25.196.0/23	permit
 8.36.116.0/24	permit
-8.39.54.0/23	permit
-8.39.54.250/31	permit
 8.39.144.0/24	permit
-8.40.222.0/23	permit
-8.40.222.250/31	permit
 12.130.86.238	permit
-13.107.213.41	permit
-13.107.246.41	permit
+13.107.213.69	permit
+13.107.246.69	permit
+13.108.16.0/20	permit
 13.110.208.0/21	permit
 13.110.209.0/24	permit
 13.110.216.0/22	permit
@@ -66,6 +65,7 @@
 13.111.191.0/24	permit
 13.216.7.111	permit
 13.216.54.180	permit
+13.247.164.219	permit
 15.200.21.50	permit
 15.200.44.248	permit
 15.200.201.185	permit
@@ -169,7 +169,6 @@
 34.215.104.144	permit
 34.218.115.239	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
@@ -193,7 +192,6 @@
 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
@@ -275,7 +273,6 @@
 50.112.246.219	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
@@ -302,7 +299,6 @@
 52.96.91.34	permit
 52.96.111.82	permit
 52.96.172.98	permit
-52.96.214.50	permit
 52.96.222.194	permit
 52.96.222.226	permit
 52.96.223.2	permit
@@ -341,7 +337,6 @@
 54.244.54.130	permit
 54.244.242.0/24	permit
 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
@@ -402,23 +397,15 @@
 64.207.219.143	permit
 64.233.160.0/19	permit
 65.52.80.137	permit
-65.54.51.64/26	permit
-65.54.61.64/26	permit
 65.54.121.120/29	permit
-65.54.190.0/24	permit
-65.54.241.0/24	permit
 65.55.29.77	permit
 65.55.33.64/28	permit
-65.55.34.0/24	permit
 65.55.42.224/28	permit
 65.55.52.224/27	permit
 65.55.78.128/25	permit
 65.55.81.48/28	permit
-65.55.90.0/24	permit
 65.55.94.0/25	permit
-65.55.111.0/24	permit
 65.55.113.64/26	permit
-65.55.116.0/25	permit
 65.55.126.0/25	permit
 65.55.174.0/25	permit
 65.55.178.128/27	permit
@@ -426,7 +413,6 @@
 65.110.161.77	permit
 65.123.29.213	permit
 65.123.29.220	permit
-65.154.166.0/24	permit
 65.212.180.36	permit
 66.102.0.0/20	permit
 66.119.150.192/26	permit
@@ -640,7 +626,6 @@
 74.208.4.220	permit
 74.208.4.221	permit
 74.209.250.0/24	permit
-75.2.70.75	permit
 76.223.128.0/19	permit
 76.223.176.0/20	permit
 77.238.176.0/24	permit
@@ -669,18 +654,12 @@
 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
-82.165.159.4	permit
 82.165.159.12	permit
 82.165.159.13	permit
 82.165.159.14	permit
-82.165.159.34	permit
-82.165.159.35	permit
 82.165.159.40	permit
 82.165.159.41	permit
 82.165.159.42	permit
-82.165.159.45	permit
 82.165.159.130	permit
 82.165.159.131	permit
 85.9.206.169	permit
@@ -1230,11 +1209,8 @@
 98.139.245.208/30	permit
 98.139.245.212/31	permit
 99.78.197.208/28	permit
-99.83.190.102	permit
 103.9.96.0/22	permit
 103.28.42.0/24	permit
-103.84.217.238	permit
-103.89.75.238	permit
 103.151.192.0/23	permit
 103.168.172.128/27	permit
 103.237.104.0/22	permit
@@ -1400,9 +1376,6 @@
 117.120.16.0/21	permit
 119.42.242.52/31	permit
 119.42.242.156	permit
-121.244.91.48	permit
-121.244.91.52	permit
-122.15.156.182	permit
 123.126.78.64/29	permit
 124.108.96.24/31	permit
 124.108.96.28/31	permit
@@ -1430,6 +1403,7 @@
 128.245.248.0/21	permit
 129.41.77.70	permit
 129.41.169.249	permit
+129.77.16.0/20	permit
 129.80.5.164	permit
 129.80.64.36	permit
 129.80.67.121	permit
@@ -1466,10 +1440,6 @@
 134.170.141.64/26	permit
 134.170.143.0/24	permit
 134.170.174.0/24	permit
-135.84.80.0/24	permit
-135.84.81.0/24	permit
-135.84.82.0/24	permit
-135.84.83.0/24	permit
 135.84.216.0/22	permit
 136.143.160.0/24	permit
 136.143.161.0/24	permit
@@ -1481,6 +1451,7 @@
 136.143.184.0/24	permit
 136.143.188.0/24	permit
 136.143.190.0/23	permit
+136.146.128.0/20	permit
 136.147.128.0/20	permit
 136.147.135.0/24	permit
 136.147.176.0/20	permit
@@ -1495,7 +1466,6 @@
 139.138.46.219	permit
 139.138.57.55	permit
 139.138.58.119	permit
-139.167.79.86	permit
 139.180.17.0/24	permit
 140.238.148.191	permit
 141.148.159.229	permit
@@ -1552,9 +1522,6 @@
 155.248.220.138	permit
 155.248.234.149	permit
 155.248.237.141	permit
-157.55.0.192/26	permit
-157.55.1.128/26	permit
-157.55.2.0/25	permit
 157.55.9.128/25	permit
 157.55.11.0/25	permit
 157.55.49.0/25	permit
@@ -1618,9 +1585,6 @@
 164.152.23.32	permit
 164.152.25.241	permit
 164.177.132.168/30	permit
-165.173.128.0/24	permit
-165.173.180.250/31	permit
-165.173.182.250/31	permit
 166.78.68.0/22	permit
 166.78.68.221	permit
 166.78.69.169	permit
@@ -1650,29 +1614,16 @@
 168.245.12.252	permit
 168.245.46.9	permit
 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.142.33	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.32.0/20	permit
-172.253.56.0/21	permit
-172.253.112.0/20	permit
 173.0.84.0/29	permit
 173.0.84.224/27	permit
 173.0.94.244/30	permit
 173.194.0.0/16	permit
+173.194.0.0/17	permit
 173.203.79.182	permit
 173.203.81.39	permit
 173.224.161.128/25	permit
@@ -1812,6 +1763,7 @@
 194.97.212.12	permit
 194.106.220.0/23	permit
 194.113.24.0/22	permit
+194.113.42.0/26	permit
 194.154.193.192/27	permit
 195.4.92.0/23	permit
 195.54.172.0/23	permit
@@ -1825,6 +1777,7 @@
 198.61.254.21	permit
 198.61.254.231	permit
 198.178.234.57	permit
+198.202.211.1	permit
 198.244.48.0/20	permit
 198.244.56.107	permit
 198.244.56.108	permit
@@ -1846,16 +1799,7 @@
 199.16.156.0/22	permit
 199.33.145.1	permit
 199.33.145.32	permit
-199.34.22.36	permit
 199.59.148.0/22	permit
-199.67.80.2	permit
-199.67.80.20	permit
-199.67.82.2	permit
-199.67.82.20	permit
-199.67.84.0/24	permit
-199.67.86.0/24	permit
-199.67.88.0/24	permit
-199.67.90.0/24	permit
 199.101.161.130	permit
 199.101.162.0/25	permit
 199.122.120.0/21	permit
@@ -1912,8 +1856,6 @@
 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
@@ -1946,7 +1888,6 @@
 207.46.52.79	permit
 207.46.58.128/25	permit
 207.46.116.128/29	permit
-207.46.117.0/24	permit
 207.46.132.128/27	permit
 207.46.198.0/25	permit
 207.46.200.0/27	permit
@@ -2052,19 +1993,11 @@
 212.82.111.228/31	permit
 212.82.111.230	permit
 212.123.28.40	permit
-212.227.15.3	permit
-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
 212.227.15.19	permit
-212.227.15.25	permit
-212.227.15.26	permit
-212.227.15.29	permit
 212.227.15.44	permit
 212.227.15.45	permit
 212.227.15.46	permit
@@ -2072,17 +2005,11 @@
 212.227.15.50	permit
 212.227.15.52	permit
 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
@@ -2167,8 +2094,6 @@
 216.205.24.0/24	permit
 216.221.160.0/19	permit
 216.239.32.0/19	permit
-217.72.192.77	permit
-217.72.192.78	permit
 217.77.141.52	permit
 217.77.141.59	permit
 217.175.194.0/24	permit
@@ -2201,9 +2126,6 @@
 2603:1030:20e:3::23c	permit
 2603:1030:b:3::152	permit
 2603:1030:c02:8::14	permit
-2607:13c0:0001:0000:0000:0000:0000:7000/116	permit
-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

+ 6 - 0
data/conf/sogo/sogo.conf

@@ -86,6 +86,12 @@
     SOGoMaximumFailedLoginInterval = 900;
     SOGoFailedLoginBlockInterval = 900;
 
+    // Enable SOGo URL Description for GDPR compliance, this may cause some issues with calendars and contacts. Also uncomment the encryption key below to use it.
+    //SOGoURLEncryptionEnabled = NO;
+
+    // Set a 16 character encryption key for SOGo URL Description, change this to your own value
+    //SOGoURLPathEncryptionKey = "SOGoSuperSecret0";
+
     GCSChannelCollectionTimer = 60;
     GCSChannelExpireAge = 60;
 

+ 27 - 10
data/web/inc/functions.mailbox.inc.php

@@ -49,6 +49,12 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
             // Default to 1 yr
             $_data["validity"] = 8760;
           }
+          if (isset($_data["permanent"]) && filter_var($_data["permanent"], FILTER_VALIDATE_BOOL)) {
+            $permanent = 1;
+          }
+          else {
+            $permanent = 0;
+          }
           $domain = $_data['domain'];
           $description = $_data['description'];
           $valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
@@ -65,13 +71,14 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
             return false;
           }
           $validity = strtotime("+" . $_data["validity"] . " hour");
-          $stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `description`, `goto`, `validity`) VALUES
-            (:address, :description, :goto, :validity)");
+          $stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `description`, `goto`, `validity`, `permanent`) VALUES
+            (:address, :description, :goto, :validity, :permanent)");
           $stmt->execute(array(
             ':address' => readable_random_string(rand(rand(3, 9), rand(3, 9))) . '.' . readable_random_string(rand(rand(3, 9), rand(3, 9))) . '@' . $domain,
             ':description' => $description,
             ':goto' => $username,
-            ':validity' => $validity
+            ':validity' => $validity,
+            ':permanent' => $permanent
           ));
           $_SESSION['return'][] = array(
             'type' => 'success',
@@ -2103,15 +2110,23 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
               );
               continue;
             }
-            if (empty($_data['validity'])) {
+            if (empty($_data['validity']) && empty($_data['permanent'])) {
               continue;
             }
-            $validity = round((int)time() + ($_data['validity'] * 3600));
-            $stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = :validity WHERE
+            if (isset($_data['permanent']) && filter_var($_data['permanent'], FILTER_VALIDATE_BOOL)) {
+              $permanent = 1;
+              $validity = 0;
+            }
+            else if (isset($_data['validity'])) {
+              $permanent = 0;
+              $validity = round((int)time() + ($_data['validity'] * 3600));
+            }
+            $stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = :validity, `permanent` = :permanent WHERE
               `address` = :address");
             $stmt->execute(array(
               ':address' => $address,
-              ':validity' => $validity
+              ':validity' => $validity,
+              ':permanent' => $permanent
             ));
             $_SESSION['return'][] = array(
               'type' => 'success',
@@ -4584,10 +4599,12 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
             `description`,
             `validity`,
             `created`,
-            `modified`
+            `modified`,
+            `permanent`
               FROM `spamalias`
                 WHERE `goto` = :username
-                  AND `validity` >= :unixnow");
+                  AND (`validity` >= :unixnow
+                    OR `permanent` != 0)");
           $stmt->execute(array(':username' => $_data, ':unixnow' => time()));
           $tladata = $stmt->fetchAll(PDO::FETCH_ASSOC);
           return $tladata;
@@ -5162,7 +5179,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
             $stmt = $pdo->prepare("SELECT COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain AND `username` != :username");
             $stmt->execute(array(':domain' => $row['domain'], ':username' => $_data));
             $MailboxUsage = $stmt->fetch(PDO::FETCH_ASSOC);
-            $stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND `validity` >= :unixnow");
+            $stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND (`validity` >= :unixnow OR `permanent` != 0)");
             $stmt->execute(array(':address' => $_data, ':unixnow' => time()));
             $SpamaliasUsage = $stmt->fetch(PDO::FETCH_ASSOC);
             $mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];

+ 3 - 2
data/web/inc/init_db.inc.php

@@ -4,7 +4,7 @@ function init_db_schema()
   try {
     global $pdo;
 
-    $db_version = "07102025_1015";
+    $db_version = "10312025_0525";
 
     $stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
     $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@@ -554,7 +554,8 @@ function init_db_schema()
           "description" => "TEXT NOT NULL",
           "created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
           "modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
-          "validity" => "INT(11)"
+          "validity" => "INT(11)",
+          "permanent" => "TINYINT(1) NOT NULL DEFAULT '0'"
         ),
         "keys" => array(
           "primary" => array(

+ 1 - 1
data/web/inc/vars.inc.php

@@ -85,7 +85,7 @@ $AVAILABLE_LANGUAGES = array(
   // 'ca-es' => 'Català (Catalan)',
   'bg-bg' => 'Български (Bulgarian)',
   'cs-cz' => 'Čeština (Czech)',
-  'da-dk' => 'Danish (Dansk)',
+  'da-dk' => 'Dansk (Danish)',
   'de-de' => 'Deutsch (German)',
   'en-gb' => 'English',
   'es-es' => 'Español (Spanish)',

+ 19 - 3
data/web/js/site/user.js

@@ -175,6 +175,10 @@ jQuery(function($){
                 '</div>';
               item.chkbox = '<input type="checkbox" class="form-check-input" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />';
               item.address = escapeHtml(item.address);
+              item.validity = {
+                value: item.validity,
+                permanent: item.permanent
+              };
             }
             else {
               item.chkbox = '<input type="checkbox" class="form-check-input" disabled />';
@@ -218,9 +222,21 @@ jQuery(function($){
           title: lang.alias_valid_until,
           data: 'validity',
           defaultContent: '',
-          createdCell: function(td, cellData) {
-            createSortableDate(td, cellData)
-          }
+          render: function (data, type) {
+            var date = new Date(data.value ? data.value * 1000 : 0);
+            switch (type) {
+              case "sort":
+                if (data.permanent) {
+                  return 0;
+                }
+                return date.getTime();
+              default:
+                if (data.permanent) {
+                  return lang.forever;
+                }
+                return date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
+            }
+          },
         },
         {
           title: lang.created_on,

+ 1 - 0
data/web/json_api.php

@@ -1992,6 +1992,7 @@ if (isset($_GET['query'])) {
         break;
         case "cors":
           process_edit_return(cors('edit', $attr));
+        break;
         case "identity-provider":
           process_edit_return(identity_provider('edit', $attr));
         break;

+ 29 - 2
data/web/lang/lang.ca-es.json

@@ -19,7 +19,16 @@
         "spam_alias": "Àlies temporals",
         "spam_score": "Puntuació de correu brossa",
         "tls_policy": "Política TLS",
-        "unlimited_quota": "Quota ilimitada per bústies de correo"
+        "unlimited_quota": "Quota ilimitada per bústies de correo",
+        "delimiter_action": "Acció delimitadora",
+        "domain_relayhost": "Canviar relayhost per un domini",
+        "extend_sender_acl": "Permetre extendre l'ACL del remitent per adreces externes",
+        "mailbox_relayhost": "Canvia el host de reenviament per una bústia",
+        "pushover": "Pushover",
+        "pw_reset": "Permetre el restabliment de la contrasenya de l'usuari mailcow",
+        "ratelimit": "Límit de peticions",
+        "smtp_ip_access": "Canvia hosts permesos per SMTP",
+        "sogo_access": "Permetre la gestió d'accés a SOGo"
     },
     "add": {
         "activate_filter_warn": "All other filters will be deactivated, when active is checked.",
@@ -73,7 +82,25 @@
         "validate": "Validar",
         "validation_success": "Validated successfully",
         "app_name": "Nom de l'aplicació",
-        "app_password": "Afegir contrasenya a l'aplicació"
+        "app_password": "Afegir contrasenya a l'aplicació",
+        "app_passwd_protocols": "Protocols autoritzats per la contrasenya de l'aplicació",
+        "bcc_dest_format": "La destinació c/o ha de ser una única adreça de correu vàlida.<br>Si necessiteu enviar una còpia a diverses adreces, creeu un àlies i utilitzeu-lo aquí.",
+        "comment_info": "Els comentaris privats no són visibles per l'usuari, mentre que els comentaris públics apareixen com una descripció emergent a la informació de l'usuari",
+        "custom_params": "Paràmetres personalitzats",
+        "custom_params_hint": "Correcte: --param=xy, incorrecte: --param xy",
+        "destination": "Destí",
+        "disable_login": "No permetre l'inici de sessió (els missatges entrants continuen sent acceptats)",
+        "domain_matches_hostname": "El domini %s coincideix amb el nom del servidor",
+        "dry": "Simular la sincronització",
+        "gal": "Llista d'adreces global",
+        "generate": "genereu",
+        "inactive": "Inactiu",
+        "internal": "Intern",
+        "internal_info": "Els àlies interns són només accessibles des del mateix domini o els àlies de dominis.",
+        "mailbox_quota_def": "Quota per defecte de la bústia",
+        "nexthop": "Següent salt",
+        "private_comment": "Comentari privat",
+        "public_comment": "Comentari púlbic"
     },
     "admin": {
         "access": "Accés",

+ 16 - 13
data/web/lang/lang.cs-cz.json

@@ -149,7 +149,7 @@
         "arrival_time": "Čas zařazení do fronty (čas na serveru)",
         "authed_user": "Přihlášený uživatel",
         "ays": "Opravdu chcete pokračovat?",
-        "ban_list_info": "Seznam blokovaných IP adres je zobrazen níže: <b>síť (zbývající čas blokování) - [akce]</b>.<br />IP adresy zařazené pro odblokování budou z aktivního seznamu odebrány během několika sekund.<br />Červeně označené položky jsou pernamentní bloky z blacklistu.",
+        "ban_list_info": "Viz seznam zablokovaných IP níže: <b>síť (zbývající doba zablokování) - [akce]</b>.<br />IP adresy zařazené pro odblokování budou z aktivního seznamu odebrány během pár sekund.<br />Červeně označeny jsou položky z trvalých seznamů.",
         "change_logo": "Změnit logo",
         "logo_normal_label": "Normální",
         "logo_dark_label": "Inverzní pro tmavý režim",
@@ -183,16 +183,16 @@
         "empty": "Žádné výsledky",
         "excludes": "Vyloučit tyto příjemce",
         "f2b_ban_time": "Doba blokování (s)",
-        "f2b_blacklist": "Sítě/hostitelé na blacklistu",
+        "f2b_blacklist": "Sítě či hostitelé na seznamu zákazů",
         "f2b_filter": "Regex filtre",
-        "f2b_list_info": "Síť nebo hostitelé na blacklistu mají vždy větší váhu než položky na whitelistu. <b>Každá úprava seznamů trvá pár sekund.</b>",
+        "f2b_list_info": "Sítě či hostitelé na seznamu zákazů mají vždy větší váhu než položky na seznamu povolení. <b>Každá úprava seznamu trvá pár sekund.</b>",
         "f2b_max_attempts": "Max. pokusů",
         "f2b_netban_ipv4": "Rozsah IPv4 podsítě k zablokování (8-32)",
         "f2b_netban_ipv6": "Rozsah IPv6 podsítě k zablokování (8-128)",
         "f2b_parameters": "Parametry automatického firewallu",
         "f2b_regex_info": "Záznamy které se berou v úvahu: SOGo, Postfix, Dovecot, PHP-FPM.",
         "f2b_retry_window": "Časový horizont pro maximum pokusů (s)",
-        "f2b_whitelist": "Sítě/hostitelé na whitelistu",
+        "f2b_whitelist": "Sítě či hostitelé na seznamu povolení",
         "filter_table": "Tabulka filtrů",
         "forwarding_hosts": "Předávající servery",
         "forwarding_hosts_add_hint": "Lze zadat IPv4/IPv6 adresy, sítě ve formátu CIDR, názvy serverů (budou převedeny na IP adresy) nebo názvy domén (budou převedeny na IP pomocí SPF záznamů, příp. MX záznamů).",
@@ -304,7 +304,7 @@
         "rspamd_com_settings": "Název nastavení se vygeneruje automaticky, viz ukázky nastavení níže. Více informací viz <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd dokumentace</a>",
         "rspamd_global_filters": "Mapa globálních filtrů",
         "rspamd_global_filters_agree": "Budu opatrný!",
-        "rspamd_global_filters_info": "Mapa globálních filtrů obsahuje jiné globální black- a whitelisty.",
+        "rspamd_global_filters_info": "Mapa globálních filtrů obsahuje různé seznamy povolených a zakázaných serverů",
         "rspamd_global_filters_regex": "Názvy stačí k vysvětlení. Položky musejí obsahovat jen platné regulární výrazy ve tvaru \"/vyraz/parametry\" (e.g. <code>/.+@domena\\.tld/i</code>).<br>\n  Každý výraz bude podroben základní kontrole, přesto je možné Rspamd 'rozbít', nebude-li syntax zcela korektní.<br>\n  Rspamd se pokusí po každé změně načíst mapu znovu. V případě potíží <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">restartujte Rspamd</a>, aby se konfigurace načetla explicitně.",
         "rspamd_settings_map": "Nastavení Rspamd",
         "sal_level": "Úroveň 'Moo'",
@@ -733,7 +733,7 @@
         "sogo_visible_info": "Tato volba určuje objekty, jež lze zobrazit v SOGo (sdílené nebo nesdílené aliasy, jež ukazuje alespoň na jednu schránku).",
         "spam_alias": "Vytvořit nebo změnit dočasné aliasy",
         "spam_filter": "Spam filtr",
-        "spam_policy": "Přidat nebo odebrat položky whitelistu/blacklistu",
+        "spam_policy": "Přidat nebo odebrat položky seznamu",
         "spam_score": "Nastavte vlastní skóre spamu",
         "subfolder2": "Synchronizace do podsložky v cílovém umístění<br><small>(prázdné = nepoužívat podsložku)</small>",
         "syncjob": "Upravit synchronizační úlohu",
@@ -883,7 +883,7 @@
         "bcc": "BCC",
         "bcc_destination": "Cíl kopie",
         "bcc_destinations": "Cíl kopií",
-        "bcc_info": "<br/>Skrytá kopie (mapa BCC) se používá pro tiché předávání kopií všech zpráv na jinou adresu. Mapa příjemců se použije, funguje-li je místní cíl jako adresát zprávy. Totéž platí pro mapy odesílatelů.<br/>\n  Místní cíl se nedozví, selže-li doručení na cíl BCC.",
+        "bcc_info": "Skrytá kopie (mapa BCC) se používá pro tiché předávání kopií všech zpráv na jinou adresu. Mapa příjemců se použije, funguje-li je místní cíl jako adresát zprávy. Totéž platí pro mapy odesílatelů.<br/>\n  Místní cíl se nedozví, selže-li doručení na cíl BCC.",
         "bcc_local_dest": "Týká se",
         "bcc_map": "Skrytá kopie",
         "bcc_map_type": "Typ skryté kopie",
@@ -1060,7 +1060,7 @@
         "notified": "Oznámeno",
         "qhandler_success": "Požadavek úspěšně přijat. Můžete nyní zavřít okno.",
         "qid": "Rspamd QID",
-        "qinfo": "Karanténní systém uloží odmítnutou poštu do databáze (odesílatel se <em>nedozví</em>, že pošta byla doručena) jakož i pošta, která bude jako kopie doručena do složky Nevyžádaná pošta. \r\n<br>\"Naučit jako spam a smazat\" naučí zprávu jako spam přes Bayesian theorem a současně vypočítá fuzzy hashes pro odmítnutí podobných zpráv v budoucnosti. \r\n<br> Prosím, berte na vědomí, že naučení více zpráv může být - záleží na vašem systému - časově náročné . <br> Položky na černé listině jsou z karantény vyloučeny.",
+        "qinfo": "Karanténa uloží do databáze odmítnutou poštu  (odesílatel se <em>nedozví</em>, že pošta byla doručena) jakož i poštu, jež se jako kopie doručuje do složky Nevyžádaná pošta.\n  <br>\"Naučit jako spam a smazat\" předá zprávu systému k naučení bayesiánskou analýzou jako spam a současně stanoví fuzzy hashe pro odmítání podobných zpráv v budoucnosti.\n  <br> Vezměte na vědomí, že učení více zpráv může být podle výkonnosti systému zabrat více času. <br> Položky na seznamu zákazů jsou z karantény vyloučeny.",
         "qitem": "Položka v karanténě",
         "quarantine": "Karanténa",
         "quick_actions": "Akce",
@@ -1347,12 +1347,12 @@
         "sogo_profile_reset": "Resetovat profil SOGo",
         "sogo_profile_reset_help": "Tato volba odstraní uživatelský profil SOGo a <b>nenávratně vymaže všechna data</b>.",
         "sogo_profile_reset_now": "Resetovat profil",
-        "spam_aliases": "Dočasné e-mailové aliasy",
+        "spam_aliases": "Spam aliasy",
         "spam_score_reset": "Obnovit výchozí nastavení serveru",
         "spamfilter": "Filtr spamu",
         "spamfilter_behavior": "Hodnocení",
-        "spamfilter_bl": "Seznam zakázaných adres (blacklist)",
-        "spamfilter_bl_desc": "Zakázané emailové adresy budou <b>vždy</b> klasifikovány jako spam a odmítnuty. Odmítnutá pošta <b>nebude</b> uložena do karantény. Lze použít zástupné znaky (*). Filtr se použije pouze na přímé aliasy (s jednou cílovou poštovní schránkou), s výjimkou doménových košů a samotné poštovní schránky.",
+        "spamfilter_bl": "Seznam zákazů",
+        "spamfilter_bl_desc": "Zakázané emailové adresy budou <b>vždy</b> klasifikovány jako spam a odmítnuty. Odmítnutá pošta <b>se neukládá</b> do karantény. Lze použít zástupné znaky (*). Filtr se použije pouze na přímé aliasy (s jednou cílovou poštovní schránkou), s výjimkou doménových košů a samotné poštovní schránky.",
         "spamfilter_default_score": "Výchozí hodnoty",
         "spamfilter_green": "Zelená: tato zpráva není spam",
         "spamfilter_hint": "První hodnota představuje \"nízké spam skóre\" a druhá \"vysoké spam skóre\".",
@@ -1363,7 +1363,7 @@
         "spamfilter_table_empty": "Žádná data k zobrazení",
         "spamfilter_table_remove": "smazat",
         "spamfilter_table_rule": "Pravidlo",
-        "spamfilter_wl": "Seznam povolených adres (whitelist)",
+        "spamfilter_wl": "Seznam povolení",
         "spamfilter_wl_desc": "Povolené emailové adresy <b>nebudou nikdy klasifikovány jako spam</b>. Lze použít zástupné znaky (*). Filtr se použije pouze na přímé aliasy (s jednou cílovou mailovou schránkou), s výjimkou doménových košů a samotné mailové schránky.",
         "spamfilter_yellow": "Žlutá: tato zpráva může být spam, bude označena jako spam a přesunuta do složky nevyžádané pošty",
         "status": "Stav",
@@ -1407,7 +1407,10 @@
         "authentication": "Autentifikace",
         "overview": "Přehled",
         "protocols": "Protokoly",
-        "value": "Hodnota"
+        "value": "Hodnota",
+        "expire_never": "Nikdy nevyprší",
+        "forever": "Navždy",
+        "spam_aliases_info": "Spam alias je dočasná adresa, již lze použít k ochraně skutečných adres. <br>Případně lze nastavit také dobu platnosti, po níž je alias automaticky deaktivován, čímž se řeší případy zneužitých či odcizených adres."
     },
     "warning": {
         "cannot_delete_self": "Nelze smazat právě přihlášeného uživatele",

+ 5 - 2
data/web/lang/lang.de-de.json

@@ -987,7 +987,7 @@
         "sogo_visible": "Alias Sichtbarkeit in SOGo",
         "sogo_visible_n": "Alias in SOGo verbergen",
         "sogo_visible_y": "Alias in SOGo anzeigen",
-        "spam_aliases": "Temp. Alias",
+        "spam_aliases": "Spam-Alias",
         "stats": "Statistik",
         "status": "Status",
         "sync_jobs": "Synchronisationen",
@@ -1281,7 +1281,9 @@
         "encryption": "Verschlüsselung",
         "excludes": "Ausschlüsse",
         "expire_in": "Ungültig in",
+        "expire_never": "Niemals ungültig",
         "fido2_webauthn": "FIDO2/WebAuthn",
+        "forever": "Für immer",
         "force_pw_update": "Das Passwort für diesen Benutzer <b>muss</b> geändert werden, damit die Zugriffssperre auf die Groupware-Komponenten wieder freigeschaltet wird.",
         "from": "von",
         "generate": "generieren",
@@ -1346,7 +1348,8 @@
         "sogo_profile_reset": "SOGo-Profil zurücksetzen",
         "sogo_profile_reset_help": "Das Profil wird inklusive <b>aller</b> Kalender- und Kontaktdaten <b>unwiederbringlich gelöscht</b>.",
         "sogo_profile_reset_now": "Profil jetzt zurücksetzen",
-        "spam_aliases": "Temporäre E-Mail-Aliasse",
+        "spam_aliases": "Spam E-Mail-Aliasse",
+        "spam_aliases_info": "Ein Spam-Alias ist eine temporäre E-Mailadresse, die benutzt werden kann, um eine echte E-Mail Adressen zu schützen. <br>Optional kann eine Ablaufzeit gesetzt werden, sodass der Alias nach dem definierten Zeitraum automatisch deaktiviert wird, was missbrauchte oder geleakte Adressen effektiv entsorgt.",
         "spam_score_reset": "Auf Server-Standard zurücksetzen",
         "spamfilter": "Spamfilter",
         "spamfilter_behavior": "Bewertung",

+ 4 - 1
data/web/lang/lang.en-gb.json

@@ -1288,7 +1288,9 @@
         "encryption": "Encryption",
         "excludes": "Excludes",
         "expire_in": "Expire in",
+        "expire_never": "Never Expire",
         "fido2_webauthn": "FIDO2/WebAuthn",
+        "forever": "Forever",
         "force_pw_update": "You <b>must</b> set a new password to be able to access groupware related services.",
         "from": "from",
         "generate": "generate",
@@ -1355,7 +1357,8 @@
         "sogo_profile_reset": "Reset SOGo profile",
         "sogo_profile_reset_help": "This will destroy a user's SOGo profile and <b>delete all contact and calendar data irretrievable</b>.",
         "sogo_profile_reset_now": "Reset profile now",
-        "spam_aliases": "Temporary email aliases",
+        "spam_aliases": "Spam email aliases",
+        "spam_aliases_info": "A spam alias is a temporary email address that can be used to protect real email addresses. <br>Optionally, an expiration time can be set so that the alias is automatically deactivated after the defined period, effectively disposing of abused or leaked addresses.",
         "spam_score_reset": "Reset to server default",
         "spamfilter": "Spam filter",
         "spamfilter_behavior": "Rating",

+ 6 - 1
data/web/lang/lang.es-es.json

@@ -1084,6 +1084,7 @@
         "aliases_send_as_all": "No verificar permisos del remitente para los siguientes dominios (y sus aliases)",
         "change_password": "Cambiar contraseña",
         "create_syncjob": "Crear nuevo trabajo de sincronización",
+        "created_on": "Creado",
         "daily": "Cada día",
         "day": "Día",
         "description": "Descripción",
@@ -1095,6 +1096,9 @@
         "edit": "Editar",
         "encryption": "Cifrado",
         "excludes": "Excluye",
+        "expire_in": "Expirará en",
+        "expire_never": "Nunca expirará",
+        "forever": "Siempre",
         "hour": "Hora",
         "hourly": "Cada hora",
         "hours": "Horas",
@@ -1115,7 +1119,8 @@
         "shared_aliases": "Alias compartidos",
         "shared_aliases_desc": "Los alias compartidos no se ven afectados por la configuración específica del usuario, como el filtro de correo no deseado o la política de cifrado. Los filtros de spam correspondientes solo pueden ser realizados por un administrador como una política de dominio.",
         "sogo_profile_reset": "Resetear perfil SOGo",
-        "spam_aliases": "Alias de email temporales",
+        "spam_aliases": "Alias de email de spam",
+        "spam_aliases_info": "Un alias de spam es una dirección de correo electrónico temporal que se puede usar para proteger direcciones de correo electrónico reales. <br>Opcionalmente, se puede establecer un tiempo de expiración para que el alias se desactive automáticamente después del período definido, eliminando efectivamente las direcciones abusadas o filtradas.",
         "spamfilter": "Filtro anti-spam",
         "spamfilter_behavior": "Clasificación",
         "spamfilter_bl": "Lista negra",

+ 40 - 12
data/web/lang/lang.fr-fr.json

@@ -16,7 +16,7 @@
         "quarantine_notification": "Modifier la notification de quarantaine",
         "quarantine_category": "Modifier la catégorie de la notification de quarantaine",
         "ratelimit": "Limite d'envoi",
-        "recipient_maps": "Cartes destinataire",
+        "recipient_maps": "Cartes des destinataires",
         "smtp_ip_access": "Changer les hôtes autorisés pour SMTP",
         "sogo_access": "Autoriser la gestion des accès à SOGo",
         "sogo_profile_reset": "Réinitialiser le profil SOGo",
@@ -109,7 +109,9 @@
         "bcc_dest_format": "La destination Cci doit être une seule adresse de courriel valide.<br>Si vous avez besoin d'envoyer une copie à plusieurs adresses, créez un alias et utilisez-le ici.",
         "tags": "Etiquettes",
         "app_passwd_protocols": "Protocoles autorisés pour le mot de passe de l'application",
-        "dry": "Simuler la synchronisation"
+        "dry": "Simuler la synchronisation",
+        "internal": "Interne",
+        "internal_info": "Les alias internes sont accessibles uniquement depuis le domaine ou les alias du domaine."
     },
     "admin": {
         "access": "Accès",
@@ -407,7 +409,9 @@
         "iam_host": "Hôte",
         "iam_host_info": "Saisissez un ou plusieurs hôtes LDAP, séparés par des virgules.",
         "iam_import_users": "Importer des utilisateurs",
-        "filter": "Filtrer"
+        "filter": "Filtrer",
+        "needs_restart": "nécessite un redémarrage",
+        "iam": "Fournisseur d'identité"
     },
     "danger": {
         "access_denied": "Accès refusé ou données de formulaire non valides",
@@ -441,7 +445,7 @@
         "global_filter_write_error": "Impossible d’écrire le fichier de filtre : %s",
         "global_map_invalid": "ID de carte globale %s non valide",
         "global_map_write_error": "Impossible d’écrire l’ID de la carte globale %s : %s",
-        "goto_empty": "Une adresse alias doit contenir au moins une adresse 'goto'valide",
+        "goto_empty": "Une adresse alias doit contenir au moins une adresse 'goto' valide",
         "goto_invalid": "Adresse Goto %s non valide",
         "ham_learn_error": "Erreur d'apprentissage Ham : %s",
         "imagick_exception": "Erreur : Exception Imagick lors de la lecture de l’image",
@@ -548,7 +552,11 @@
         "generic_server_error": "Une erreur de serveur inattendue s'est produite. Veuillez contacter votre administrateur.",
         "authsource_in_use": "Le fournisseur d'identité ne peut pas être modifié ou supprimé car il est actuellement utilisé par un ou plusieurs utilisateurs.",
         "iam_test_connection": "Échec de la connexion",
-        "required_data_missing": "La donnée requise %s est manquante"
+        "required_data_missing": "La donnée requise %s est manquante",
+        "max_age_invalid": "L'âge maximum %s est invalide",
+        "mode_invalid": "Le mode %s est invalide",
+        "mx_invalid": "L'enregistrement MX %s est invalide",
+        "version_invalid": "La version %s est invalide"
     },
     "debug": {
         "chart_this_server": "Graphique (ce serveur)",
@@ -693,7 +701,7 @@
         "spam_score": "Définir un score spam personnalisé",
         "subfolder2": "Synchronisation dans le sous-dossier sur la destination<br><small>(vide = ne pas utiliser de sous-dossier)</small>",
         "syncjob": "Modifier la tâche de synchronisation",
-        "target_address": "Adresse(s) Goto<small>(séparé(s) par des virgules)</small>",
+        "target_address": "Adresse(s) Goto <small>(séparé(s) par des virgules)</small>",
         "target_domain": "Domaine cible",
         "timeout1": "Délai de connexion à l’hôte distant",
         "timeout2": "Délai de connexion à l’hôte local",
@@ -734,7 +742,20 @@
         "mailbox_rename_alias": "Créer un alias automatiquement",
         "sogo_access": "Redirection directe vers SOGo",
         "pushover": "Pushover",
-        "pushover_sound": "Son"
+        "pushover_sound": "Son",
+        "internal": "Interne",
+        "internal_info": "Les alias internes sont accessibles uniquement depuis le domaine ou les alias du domaine.",
+        "mta_sts": "MTA-STS",
+        "mta_sts_version": "Version",
+        "mta_sts_version_info": "Défini la version du standard MTA-STS – actuellement seul <code>STSv1</code> est valide.",
+        "mta_sts_mode": "Mode",
+        "mta_sts_max_age": "Âge maximum",
+        "mta_sts_mx": "Serveur MX",
+        "mta_sts_mx_notice": "Plusieurs serveurs MX peuvent être spécifiés (séparés par des virgules).",
+        "mta_sts_info": "<a href='https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_MTA_Strict_Transport_Security' target='_blank'>MTA-STS</a> est un standard qui oblige la délivrance des courriels entre les serveurs de courriels à utiliser TLS avec des certificats valides. <br>Il est utilisé quand <a target='_blank' href='https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities'>DANE</a> n'est pas possible à cause d'un manque ou d'un non support de DNSSEC.<br><b>Note</b> : Si le domaine du destinataire supporte DANE avec DNSSEC, DANE est <b>toujours</b> préféré – MTA-STS sert seulement en secours.",
+        "mta_sts_mode_info": "Il y a trois modes parmi lesquels choisir :<ul><li><em>testing</em> – la politique est seulement surveillée, les violations n'ont pas d'impact.</li><li><em>enforce</em> – la politique est appliquée strictement, les connexions sans TLS valide sont rejetées.</li><li><em>none</em> – la politique est publiée mais non appliquée.</li></ul>",
+        "mta_sts_max_age_info": "Durée en secondes pendant laquelle les serveurs de courriel peuvent mettre en cache cette politique avant de revérifier.",
+        "mta_sts_mx_info": "Autoriser l'envoi uniquement aux noms d'hôtes des serveurs de courriels indiqués explicitement ; le MTA émetteur vérifie si le nom d'hôte DNS du MX correspond à la liste de la politique, et autorise la délivrance seulement avec un certificat TLS valide (protège contre le MITM)."
     },
     "footer": {
         "cancel": "Annuler",
@@ -789,7 +810,8 @@
         "login_linkstext": "L'identifiant n'est pas correct ?",
         "login_usertext": "Se connecter en tant qu'utilisateur",
         "login_domainadmintext": "Se connecter en tant qu'administrateur du domaine",
-        "login_admintext": "Se connecter en tant qu'administrateur"
+        "login_admintext": "Se connecter en tant qu'administrateur",
+        "email": "Adresse de courriel"
     },
     "mailbox": {
         "action": "Action",
@@ -896,7 +918,7 @@
         "recipient_map_new_info": "La destination de la carte du destinataire doit être une adresse de courriel valide ou un nom de domaine.",
         "recipient_map_old": "Destinataire original",
         "recipient_map_old_info": "La destination originale des cartes des destinataires doit être une adresse de courriel valide ou un nom de domaine.",
-        "recipient_maps": "Cartes des bénéficiaires",
+        "recipient_maps": "Cartes des destinataires",
         "relay_all": "Relayer tous les destinataires",
         "remove": "Supprimer",
         "resources": "Ressources",
@@ -965,7 +987,8 @@
         "syncjob_check_log": "Vérifier le journal",
         "recipient": "Destinataire",
         "open_logs": "Afficher les journaux",
-        "iam": "Fournisseur d'identité"
+        "iam": "Fournisseur d'identité",
+        "internal": "Interne"
     },
     "oauth2": {
         "access_denied": "Veuillez vous connecter en tant que propriétaire de la boîte de réception pour accorder l’accès via Oauth2.",
@@ -1222,7 +1245,7 @@
         "email_and_dav": "Courriel, calendriers et contacts",
         "encryption": "Chiffrement",
         "excludes": "Exclus",
-        "expire_in": "Expire dans",
+        "expire_in": "Expirer dans",
         "force_pw_update": "Vous <b>devez</b> définir un nouveau mot de passe pour pouvoir accéder aux services liés aux logiciels de groupe.",
         "generate": "générer",
         "hour": "heure",
@@ -1350,7 +1373,12 @@
         "mailbox_general": "Général",
         "mailbox_settings": "Paramètres",
         "tfa_info": "L'authentification à deux facteurs permet de protéger votre compte. Si vous l'activez, vous aurez besoin de mots de passe d'application pour vous connecter à des applications ou des services qui ne prennent pas en charge l'authentification à deux facteurs (par exemple les clients e-mails).",
-        "overview": "Vue d'ensemble"
+        "overview": "Vue d'ensemble",
+        "expire_never": "Ne jamais expirer",
+        "forever": "Pour toujours",
+        "spam_aliases_info": "Un alias de spam est une adresse de courriel temporaire qui peut être utilisée pour protéger les véritables adresses de courriel. <br> De manière optionnelle, une durée d'expiration peut être définie afin que l'alias soit automatiquement désactivé après la période définie, éliminant ainsi les adresses étant abusées ou ayant fuité.",
+        "authentication": "Authentification",
+        "protocols": "Protocoles"
     },
     "warning": {
         "cannot_delete_self": "Impossible de supprimer l’utilisateur connecté",

+ 167 - 1
data/web/lang/lang.gr-gr.json

@@ -6,7 +6,8 @@
         "weeks": "Εβδομάδες",
         "with_app_password": "με κωδικό εφαρμογής",
         "year": "χρόνος",
-        "years": "χρόνια"
+        "years": "χρόνια",
+        "value": "Τιμή"
     },
     "warning": {
         "cannot_delete_self": "Αδυναμία διαγραφής συνδεδεμένου χρήστη",
@@ -16,5 +17,170 @@
         "hash_not_found": "Η κατακερματισμένη τιμή (hash value) δεν βρέθηκε ή έχει είδη διαγραφεί.",
         "ip_invalid": "Παραλείφθηκε μη έγκυρη διεύθυνση IP: %s",
         "is_not_primary_alias": "Παραλείφθηκε μη πρωτεύον ψευδώνυμο %s"
+    },
+    "acl": {
+        "alias_domains": "Προσθήκη ψευδωνύμων τομέων",
+        "app_passwds": "Διαχείριση κωδικών εφαρμογής",
+        "bcc_maps": "χαρτογράφηση BCC",
+        "delimiter_action": "Ενέργεια οριοθέτη",
+        "domain_desc": "Αλλαγή περιγραφής τομέα",
+        "domain_relayhost": "Αλλαγή του διακομιστή αναμετάδοσης για ένα τομέα",
+        "eas_reset": "Επαναφορά συσκευών EAS",
+        "extend_sender_acl": "Να επιτρέπεται η επέκταση ACL του αποστολέα με εξωτερικές διευθύνσεις",
+        "filters": "Φίλτρα",
+        "login_as": "Είσοδος ως χρήστης e-mail",
+        "mailbox_relayhost": "Αλλαγή διακομιστή αναμετάδοσης για ένα γραμματοκιβώτιο",
+        "prohibited": "Απαγορεύεται από την ACL",
+        "protocol_access": "Αλλαγή πρόσβασης πρωτοκόλλου",
+        "pushover": "Pushover",
+        "pw_reset": "Επιτρέψτε την επαναφορά κωδικού πρόσβασης του χρήστη",
+        "quarantine": "Ενέργειες καραντίνας",
+        "quarantine_attachments": "Συνημμένα καραντίνας",
+        "quarantine_category": "Αλλαγή κατηγορίας ειδοποιήσεων καραντίνας",
+        "quarantine_notification": "Αλλαγή ειδοποιήσεων καραντίνας",
+        "ratelimit": "Όριο τιμής",
+        "recipient_maps": "Χάρτες παραληπτών",
+        "smtp_ip_access": "Αλλαγή επιτρεπόμενων διακομιστών SMTP",
+        "sogo_access": "Επιτρέψτε τη διαχείριση της πρόσβασης στο SOGo",
+        "sogo_profile_reset": "Επαναφορά του προφίλ SOGo",
+        "spam_alias": "Προσωρινά ψευδώνυμα",
+        "spam_policy": "Λίστα απορρίψεων/Λίστα επιτρεπόμενων",
+        "spam_score": "Βαθμολογία ανεπιθύμητης αλληλογραφίας",
+        "syncjobs": "Εργασίες συγχρονισμού",
+        "tls_policy": "Πολιτική TLS",
+        "unlimited_quota": "Απεριόριστο όριο για γραμματοκιβώτια"
+    },
+    "add": {
+        "activate_filter_warn": "Όλα τα άλλα φίλτρα θα απενεργοποιηθούν, όταν επιλεγεί η επιλογή \"ενεργό\".",
+        "active": "Ενεργό",
+        "add": "Προσθήκη",
+        "add_domain_only": "Προσθήκη μόνο του τομέα",
+        "add_domain_restart": "Προσθήκη του τομέα και επανεκκίνηση του SOGo",
+        "alias_address": "Διευθύνσεις ψευδωνύμων",
+        "alias_address_info": "<small>Πλήρης διεύθυνση(εις)  e-mail ή @example.com, για να λαμβάνετε ΟΛΑ τα μηνύματα ενός τομέα (χωρισμένα με κόμα). <b>μόνο τομείς του mailcow</b>.</small>",
+        "alias_domain": "Ψευδώνυμο τομέα",
+        "alias_domain_info": "<small>Μόνο έγκυρα ονόματα τομέα (χωρισμένα με κόμα).</small>",
+        "app_name": "Όνομα εφαρμογής",
+        "app_password": "Προσθήκη κωδικού εφαρμογής",
+        "app_passwd_protocols": "Επιτρεπόμενα πρωτόκολλα για κωδικούς εφαρμογών",
+        "automap": "Αυτόματη αντιστοίχηση φακέλων (\"Απεσταλμένα μηνύματα\", \"Απεσταλμένα\" => \"Στάλθηκαν\" κ.τ.λ.)",
+        "backup_mx_options": "Επιλογές αναμετάδοσης",
+        "bcc_dest_format": "Η BCC διεύθυνση πρέπει να είναι μία και έγκυρη διεύθυνση e-mail.<br>Αν θέλετε να στείλετε αντίγραφα σε πολλούς παραλήπτες, δημιουργήστε ένα ψευδόνυμο για όλους και χρησιμοποιήστε το εδώ.",
+        "comment_info": "Τα προσωπικά σχόλια δεν είναι ορατά στον χρήστη. Τα δημόσια σχόλια εμφανίζονται ως tooltips.",
+        "custom_params": "Προσαρμοσμένες παράμετροι",
+        "custom_params_hint": "Σωστή σύνταξη: --param=xy, λάθος σύνταξη: --param xy",
+        "delete1": "Διαγραφή όταν ολοκληρωθεί",
+        "delete2": "Διαγραφή μηνυμάτων στον προορισμό που δεν βρίσκονται στην πηγή",
+        "delete2duplicates": "Διαγραφή διπλότυπων στον προορισμό",
+        "description": "Περιγραφή",
+        "destination": "Προορισμός",
+        "disable_login": "Απαγόρευση εισόδου (η εισερχόμενη αλληλογραφία εξακολουθεί να γίνεται δεκτή)",
+        "domain": "Τομέας",
+        "domain_matches_hostname": "Ο τομέας %s είναι ο ίδιος με το όνομα του διακομιστή",
+        "domain_quota_m": "Συνολικό όριο τομέα (MiB)",
+        "dry": "Προσομοίωση συγχρονισμού",
+        "enc_method": "Μέθοδος κρυπτογράφησης",
+        "exclude": "Εξαίρεση αντικειμένων (regex)",
+        "full_name": "Πλήρες όνομα",
+        "gal": "Κοινόχρηστη λίστα διευθύνσεων"
+    },
+    "danger": {
+        "unknown": "Παρουσιάστηκε κάποιο άγωνστο σφάλμα",
+        "unknown_tfa_method": "Άγνωστη μέθοδος TFA",
+        "unlimited_quota_acl": "Το απεριόριστο όριο απαγορεύεται από την ACL",
+        "username_invalid": "Το όνομα χρήστη %s δεν μπορεί να χρησιμοποιηθεί",
+        "validity_missing": "Παρακαλώ ορίστε μία περίοδο εγκυρότητας",
+        "value_missing": "Παρακαλώ συμπληρώστε όλα τα δεδομένα",
+        "version_invalid": "Η έκδοση %s δεν είναι έγκυρη",
+        "yotp_verification_failed": "Η επαλήθευση μέσω Yubico OTP απέτυχε: %s"
+    },
+    "datatables": {
+        "collapse_all": "Σύμπτυξη όλων",
+        "decimal": ".",
+        "emptyTable": "Δεν υπάρχουν εγγραφές",
+        "expand_all": "Επέκταση όλων",
+        "info": "Εμφανίζονται _START_ εώς _END_ από _TOTAL_ εγγραφές",
+        "infoEmpty": "Εμφανίζονται 0 εώς 0 από 0 εγγραφές",
+        "infoFiltered": "(φιλτραρισμένες από _MAX_ συνολικές εγγραφές)",
+        "thousands": ",",
+        "lengthMenu": "Εμφάνιση _MENU_ εγγραφών",
+        "loadingRecords": "Γίνεται φόρτωση...",
+        "processing": "Παρακαλώ περιμένετε...",
+        "search": "Αναζήτηση:",
+        "zeroRecords": "Δε βρέθηκαν εγγραφές",
+        "paginate": {
+            "first": "Πρώτη",
+            "last": "Τελευταία",
+            "next": "Επόμενη",
+            "previous": "Προηγούμενη"
+        },
+        "aria": {
+            "sortAscending": ": ενεργοποίηση αύξουσας ταξινόμησης",
+            "sortDescending": ": ενεργοποίηση φθίνουσας ταξινόμησης"
+        }
+    },
+    "debug": {
+        "architecture": "Αρχιτεκτονική",
+        "chart_this_server": "Γράφημα (αυτός ο διακομιστής)",
+        "containers_info": "Πληροφορίες για τον container",
+        "container_running": "Εκτελείται",
+        "container_disabled": "Ο container έχει σταματήσει ή απενεργοποιηθεί",
+        "container_stopped": "Σταματημένος",
+        "cores": "Πυρήνες",
+        "current_time": "Ώρα συστήματος",
+        "disk_usage": "Χρήση αποθ. χώρου",
+        "docs": "Έγγραφα",
+        "error_show_ip": "Δεν είναι δυνατή η επίλυση της δημόσιας IP διεύθυνσης",
+        "external_logs": "Εξωτερικά αρχεία καταγραφής",
+        "history_all_servers": "Ιστορικό (Όλοι οι διακομιστές)",
+        "in_memory_logs": "Αρχεία καταγραφής στη μνήμη",
+        "last_modified": "Τελευταία τροποποίηση",
+        "log_info": "<p>mailcow <b>in-memory logs</b> are collected in Redis lists and trimmed to LOG_LINES (%d) every minute to reduce hammering.\n  <br>In-memory logs are not meant to be persistent. All applications that log in-memory, also log to the Docker daemon and therefore to the default logging driver.\n  <br>The in-memory log type should be used for debugging minor issues with containers.</p>\n  <p><b>External logs</b> are collected via API of the given application.</p>\n  <p><b>Static logs</b> are mostly activity logs, that are not logged to the Dockerd but still need to be persistent (except for API logs).</p>",
+        "login_time": "Ώρα",
+        "logs": "Αρχεία καταγραφής",
+        "memory": "Μνήμη",
+        "online_users": "Συνδεδεμένοι χρήστες",
+        "restart_container": "Επανεκκίνηση",
+        "service": "Υπηρεσία",
+        "show_ip": "Εμφάνιση δημόσιας IP",
+        "size": "Μέγεθος",
+        "started_at": "Ξεκίνησε στις",
+        "started_on": "Ξεκίνησε στις",
+        "static_logs": "Στατικά αρχεία καταγραφής",
+        "success": "Επιτυχία",
+        "system_containers": "Σύστημα και Containers",
+        "timezone": "Ζώνη ώρας",
+        "uptime": "Χρόνος λειτουργίας",
+        "update_available": "Υπάρχει διαθέσιμη ενημέρωση",
+        "no_update_available": "Έχετε τη τελευταία έκδοση του συστήματος",
+        "update_failed": "Δεν ήταν δυνατός ο έλεγχος για ενημερώσεις",
+        "username": "Όνομα χρήστη",
+        "wip": "Currently Work in Progress"
+    },
+    "diagnostics": {
+        "cname_from_a": "Value derived from A/AAAA record. This is supported as long as the record points to the correct resource.",
+        "dns_records": "Εγγραφές DNS",
+        "dns_records_24hours": "Παρακαλώ σημειώστε ότι οι αλλαγές στο DNS μπορεί να χρειαστούν μέχρι 24 ώρες για να ενημερωθούν σωστά και να εμφανιστούν σε αυτή τη σελίδα. Ο σκοπός της είναι να δείτε πως μπορείτε να ρυθμίσετε σωστά τις εγγραφές DNS και να ελέγξετε αν είναι σωστές.",
+        "dns_records_data": "Σωστά δεδομένα",
+        "dns_records_docs": "Παρακαλώ συμβουλευτείτε επίσης <a target=\"_blank\" href=\"https://docs.mailcow.email/getstarted/prerequisite-dns\">την τεκμηρίωση</a>.",
+        "dns_records_name": "Όνομα",
+        "dns_records_status": "Τρέχουσα κατάσταση",
+        "dns_records_type": "Τύπος",
+        "optional": "Αυτή η εγγραφή είναι προαιρετική."
+    },
+    "edit": {
+        "acl": "ACL (Δικαίωμα)",
+        "active": "Ενεργό",
+        "admin": "Επεξεργασία διαχειριστή",
+        "advanced_settings": "Ρυθμίσεις για προχωρημένους",
+        "alias": "Επεξεργασία ψευδώνυμου",
+        "allow_from_smtp": "Επέτρεψε μόνο σε αυτές τις IPs να χρησιμοποιήσουν το <b>SMTP</b>",
+        "allow_from_smtp_info": "Αφήστε το κενό για να επιτρέψετε όλους τους αποστολείς.<br>IPv4/IPv6 διευθύνσεις και δίκτυα.",
+        "allowed_protocols": "Επιτρεπόμενα πρωτόκολλα για απ' ευθείας πρόσβαση από τους χρήστες (δεν επηρεάζει τα πρωτόκολλα κωδικών πρόσβασης εφαρμογής)",
+        "app_name": "Όνομα εφαρμογής",
+        "app_passwd": "Κωδικός πρόσβασης εφαρμογής",
+        "app_passwd_protocols": "Επιτρέπομενα πρωτόκολλα για τον κωδικό εφαρμογής",
+        "automap": "Αυτόματη αντιστοίχηση φακέλων (\"Απεσταλμένα μηνύματα\", \"Απεσταλμένα\" => \"Στάλθηκαν\" κ.τ.λ.)",
+        "backup_mx_options": "Επιλογές αναμετάδοσης"
     }
 }

+ 3 - 0
data/web/lang/lang.ja-jp.json

@@ -1187,6 +1187,7 @@
         "created_on": "作成日",
         "daily": "毎日",
         "day": "日",
+        "description": "説明",
         "delete_ays": "削除プロセスを確認してください。",
         "direct_aliases": "直接エイリアスアドレス",
         "direct_aliases_desc": "直接エイリアスアドレスは、スパムフィルターおよびTLSポリシー設定の影響を受けます。",
@@ -1201,7 +1202,9 @@
         "encryption": "暗号化",
         "excludes": "除外",
         "expire_in": "有効期限まで",
+        "expire_never": "有効期限なし",
         "fido2_webauthn": "FIDO2/WebAuthn",
+        "forever": "有効期限なし",
         "force_pw_update": "グループウェア関連サービスにアクセスするには、新しいパスワードを<b>必ず</b>設定する必要があります。",
         "from": "送信元",
         "generate": "生成",

+ 3 - 2
data/web/lang/lang.nb-no.json

@@ -185,11 +185,12 @@
         "protocol_access": "Endre protokolltilgang",
         "pushover": "Pushover",
         "quarantine": "Karantenehandlinger",
-        "quarantine_attachments": "Sett vedlegg i karantene",
+        "quarantine_attachments": "Se vedlegg i karantene",
         "quarantine_category": "Endre varslingskategori for karantene",
         "quarantine_notification": "Endre karantenevarslinger",
         "domain_desc": "Endre domenebeskrivelse",
-        "extend_sender_acl": "Tillat utvidelse av sender-ACL fra eksterne adresser"
+        "extend_sender_acl": "Tillat utvidelse av sender-ACL fra eksterne adresser",
+        "pw_reset": "Tillat endring av brukerpassord"
     },
     "add": {
         "app_passwd_protocols": "Tillatte protokoller for app-passord",

+ 924 - 69
data/web/lang/lang.pl-pl.json

@@ -1,50 +1,117 @@
 {
     "acl": {
-        "sogo_profile_reset": "Usuń profil SOGo (webmail)",
-        "syncjobs": "Polecenie synchronizacji",
-        "alias_domains": "Dodaj aliasy domen",
-        "delimiter_action": "Akcja oparta na separatorze"
+        "sogo_profile_reset": "Zresetuj profil SOGo",
+        "syncjobs": "Zadania doryczące synchronizacji kont",
+        "alias_domains": "Dodaj domeny aliasowe",
+        "delimiter_action": "Akcja oparta na separatorze",
+        "app_passwds": "Zarządzaj hasłami do aplikacji",
+        "bcc_maps": "Mapy BCC",
+        "domain_desc": "Zmień opis dotyczący domeny",
+        "domain_relayhost": "Zmień serwer przekazujący dla tej domeny",
+        "eas_reset": "Resetuj urządzenia EAS",
+        "extend_sender_acl": "Zezwalaj na rozszerzenie listy kontroli dostępu nadawców(ACL) o adresy zewnętrzne",
+        "filters": "Dostępne filtry",
+        "login_as": "Zaloguj się jako użytkownik poczty",
+        "mailbox_relayhost": "Zmień serwer pocztowy(relayhost) dla skrzynki pocztowej",
+        "prohibited": "Zakazane przez liste kontroli dostępu(ACL)",
+        "protocol_access": "Zmień dostęp do protokołów",
+        "pushover": "Pushover(powiadomienia push w czasie rzeczywistym)",
+        "pw_reset": "Zezwalaj na resetowanie hasła użytkownika mailcow",
+        "quarantine": "Akcje kwarantanny",
+        "quarantine_attachments": "Załączniki do kwarantanny",
+        "quarantine_category": "Zmień kategorię dotyczącą powiadomień o kwarantannie",
+        "quarantine_notification": "Zmień powiadomienia o kwarantannie",
+        "ratelimit": "Ograniczenie liczby zapytań",
+        "recipient_maps": "Mapy odbiorców",
+        "smtp_ip_access": "Zmiana dozwolonych hostów SMTP",
+        "sogo_access": "Zezwól na zarządzanie dostępem SOGo",
+        "spam_alias": "Tymczasowe aliasy",
+        "spam_policy": "Zablokowane adresy/Dozwolone adresy",
+        "spam_score": "Wskaźnik spam",
+        "tls_policy": "Polityka TLS",
+        "unlimited_quota": "Nieograniczony limit dla skrzynek pocztowych"
     },
     "add": {
         "active": "Aktywny",
         "add": "Dodaj",
-        "alias_address": "Alias/y:",
+        "alias_address": "Alias/y",
         "alias_address_info": "<small>Pełny/e adres/y email lub @example.com, aby przejąć wszystkie wiadomości dla domeny (oddzielone przecinkami). <b>tylko domeny mailcow</b>.</small>",
         "alias_domain": "Alias domeny",
         "alias_domain_info": "<small>Tylko prawidłowe nazwy domen (oddzielone przecinkami).</small>",
-        "backup_mx_options": "Opcje Backup MX:",
+        "backup_mx_options": "Opcje Backup MX",
         "delete1": "Usuń ze źródła po zakończeniu",
         "delete2duplicates": "Usuń duplikaty w miejscu docelowym",
-        "description": "Opis:",
+        "description": "Opis",
         "domain": "Domena",
-        "domain_quota_m": "Łączny limit domeny (MiB):",
+        "domain_quota_m": "Łączny limit domeny (MiB)",
         "enc_method": "Metoda szyfrowania",
         "exclude": "Wyklucz obiekty (regex)",
-        "full_name": "Pełna nazwa:",
+        "full_name": "Pełna nazwa",
         "hostname": "Nazwa hosta",
         "kind": "Rodzaj",
-        "mailbox_quota_m": "Maks. wielkość skrzynki (MiB):",
-        "mailbox_username": "Nazwa użytkownika (lewa strona adresu email):",
-        "max_aliases": "Maks. liczba aliasów:",
-        "max_mailboxes": "Maks. liczba skrzynek:",
+        "mailbox_quota_m": "Maks. wielkość skrzynki (MiB)",
+        "mailbox_username": "Nazwa użytkownika (lewa strona adresu email)",
+        "max_aliases": "Maks. liczba aliasów",
+        "max_mailboxes": "Maks. liczba skrzynek",
         "mins_interval": "Zakres pobierania (minuty)",
         "multiple_bookings": "Wielokrotne rejestracje",
-        "password": "Hasło:",
-        "password_repeat": "Potwierdź hasło(powtórz):",
+        "password": "Hasło",
+        "password_repeat": "Potwierdź hasło(powtórz)",
         "port": "Port",
-        "post_domain_add": "Po dodaniu nowej domeny będziesz musiał ponownie uruchomić kontener serwisowy SOGo!",
-        "quota_mb": "Limit wielkości (MiB):",
+        "post_domain_add": "Kontener SOGo, \"sogo-mailcow\", musi zostać ponownie uruchomiony po dodaniu nowej domeny!<br><br>Dodatkowo należy przejrzeć konfigurację DNS domeny. Po zatwierdzeniu konfiguracji DNS uruchom ponownie \"acme-mailcow\", aby automatycznie wygenerować certyfikaty dla nowej domeny (autoconfig.&lt;domain&gt;, autodiscover.&lt;domain&gt;).<br>Ten krok jest opcjonalny i będzie ponownie wykonywany co 24 godziny.",
+        "quota_mb": "Limit wielkości (MiB)",
         "relay_all": "Przekaż wszystkim odbiorcom",
-        "relay_all_info": "<small>Jeśli decydujesz się <b>nie</b> przekazywać wszystkim odbiorcom, musisz dodać (\"ślepą\")skrzynkę dla każdego poszczególnego odbiorcy, któremu należy przekazać.</small>",
+        "relay_all_info": "↪Jeśli wybierzesz <b>not</b>, aby przekazać wszystkich odbiorców, musisz dodać (\"ślepą\") skrzynkę pocztową dla każdego pojedynczego odbiorcy, która powinna być przekazywana.",
         "relay_domain": "Domena przekaźnikowa",
         "select": "Proszę wybrać...",
         "select_domain": "Proszę najpierw wybrać domenę",
         "syncjob": "Dodaj polecenie synchronizacji",
         "syncjob_hint": "Pamiętaj, że hasła należy zapisywać w zwykłym tekście!",
-        "target_address": "Adresy Idź do:",
+        "target_address": "Adresy Idź do",
         "target_address_info": "<small> Pełny/e adres/y email (oddzielone przecinkami).</small>",
-        "target_domain": "Domena docelowa:",
-        "username": "Nazwa użytkownika"
+        "target_domain": "Domena docelowa",
+        "username": "Nazwa użytkownika",
+        "activate_filter_warn": "Wszystkie pozostałe filtry zostaną wyłączone, gdy opcja active zostanie zaznaczona.",
+        "add_domain_only": "Dodaj wyłącznie domene",
+        "add_domain_restart": "Dodaj domenę i uruchom ponownie SOGo",
+        "app_name": "Nazwa aplikacji",
+        "app_password": "Dodaj hasło do aplikacji",
+        "app_passwd_protocols": "Dozwolone protokoły dla hasła aplikacji",
+        "automap": "Spróbuj automatycznie mapować foldery (\"Wysłane elementy\", \"Wysłane\" => \"Wysłane\" itp.)",
+        "bcc_dest_format": "Miejscem docelowym BCC musi być jeden prawidłowy adres e-mail.<br>Jeśli chcesz wysłać kopię do wielu adresów, utwórz alias i użyj go tutaj.",
+        "comment_info": "Prywatny komentarz nie jest widoczny dla użytkownika, podczas gdy publiczny komentarz jest wyświetlany jako podpowiedź, które pojawia się, gdy użytkownik najedzie myszką nad elementem",
+        "custom_params": "Niestandardowe parametry",
+        "custom_params_hint": "Właściwa: --param=xy, błędna: --param xy",
+        "delete2": "Usuń wiadomości w miejscu docelowym, które nie znajdują się w źródle",
+        "destination": "Miejsce docelowe",
+        "disable_login": "Nie pozwalaj na logowanie(poczta przychodząca jest nadal akceptowana)",
+        "domain_matches_hostname": "Domena pasuje do nazwy hosta",
+        "dry": "Symulacja synchronizacji",
+        "gal": "Globalna lista adresów",
+        "gal_info": "GAL zawiera wszystkie obiekty domeny i nie może być edytowany przez żadnego użytkownika. Wolne/zajęte logi w SOGo bedą nidostępne, jeśli są wyłączone! <b>Uruchom ponownie SOGo, aby zastosować zmiany.</b>",
+        "generate": "generuj",
+        "goto_ham": "Ucz się jako <span class=\"text-success\"><b>ham</b></span>",
+        "goto_null": "Odrzucaj pocztę \"po cichu\"",
+        "goto_spam": "Ucz się jako <span class=\"text-danger\"><b>spam</b></span>",
+        "inactive": "Nieaktywny",
+        "internal": "Wewnętrzny",
+        "internal_info": "Aliasy wewnętrzne są dostępne tylko z domeny własnej lub domeny aliasów.",
+        "mailbox_quota_def": "Domyślny przydział skrzynki pocztowej",
+        "nexthop": "Następny hop",
+        "private_comment": "Prywatny komentarz",
+        "public_comment": "Komentarz publiczny",
+        "relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div>Możesz transports maps dla niestandardowego miejsca docelowego dla tej domeny. Jeśli nie jest ustawiony, zostanie aktywowany lookup MX.",
+        "relay_unknown_only": "Przekaż tylko nieistniejące skrzynki pocztowe. Istniejące skrzynki pocztowe będą dostarczane lokalnie.",
+        "relayhost_wrapped_tls_info": "Proszę <b>nie</b> używać portów owiniętych TLS (głównie używanych na porcie 465).<br>\nUżyj dowolnego portu niezawiniętego i uruchom STARTTLS. Polityka TLS w celu egzekwowania TLS może być utworzona w \"mapie zasad TLS\".",
+        "sieve_desc": "Krótki opis",
+        "sieve_type": "Typ filtra",
+        "skipcrossduplicates": "Pomiń duplikaty wiadomości w folderach (na zasadzie kolejności zgłoszeń)",
+        "subscribeall": "Subskrybuj wszystkie foldery",
+        "tags": "Tagi",
+        "timeout1": "Limit czasu połączenia z hostem zdalnym",
+        "timeout2": "Limit czasu połączenia dla lokalnego hosta",
+        "validate": "Zatwierdź",
+        "validation_success": "Zatwierdzone z powodzeniem"
     },
     "admin": {
         "access": "Dostęp",
@@ -72,7 +139,7 @@
         "f2b_max_attempts": "Max. ilość prób",
         "f2b_parameters": "Parametry Fail2ban",
         "f2b_retry_window": "Spróbuj ponownie (s) dla max. ilości prób",
-        "f2b_whitelist": "Biała lista sieci/hosty",
+        "f2b_whitelist": "Dozwolone sieci/hosty",
         "filter_table": "Tabela filtru",
         "forwarding_hosts": "Hosty przekazujące",
         "forwarding_hosts_add_hint": "Możesz albo wyszczególnić adresy IPv4/IPv6, sieci w notacji CIDR, nazwy hostów (które zostaną rozłożone na adresy IP), albo nazwy domen (które zostaną rozłożone na adresy IP poprzez sprawdzanie rekordów SPF lub, w razie ich braku, rekordów MX).",
@@ -100,30 +167,274 @@
         "spamfilter": "Filtr spamu",
         "time": "Czas",
         "unchanged_if_empty": "W przypadku braku zmian, nie wypełniaj",
-        "username": "Nazwa użytkownika"
+        "username": "Nazwa użytkownika",
+        "activate_api": "Aktywuj API",
+        "activate_send": "Aktywuj przycisk wysyłania",
+        "active_rspamd_settings_map": "Aktywne ustawienia mapy",
+        "add_admin": "Dodaj administratora",
+        "add_relayhost": "Dodaj transport zależny od nadawcy",
+        "add_relayhost_hint": "Miej na uwadze, że dane uwierzytelniające, jeśli takie istnieją, będą przechowywane w postaci zwykłego tekstu.",
+        "add_row": "Dodaj wiersz",
+        "add_settings_rule": "Dodaj regułę ustawień",
+        "add_transport": "Dodaj transport",
+        "add_transports_hint": "Należy pamiętać, że dane uwierzytelniające, jeśli takie istnieją, będą przechowywane jako zwykły tekst.",
+        "additional_rows": " Dodano kolejne rzędy",
+        "admins": "Administratorzy",
+        "admins_ldap": "Administratorzy LDAP",
+        "admin_quicklink": "Ukryj szybki link do strony logowania administratora",
+        "advanced_settings": "Ustawienia zaawansowane",
+        "allowed_methods": "Dostęp-kontrola-zezwolenie-metody",
+        "allowed_origins": "Dostęp-Kontrola-Zezwolenia-Pochodzenie",
+        "api_allow_from": "Zezwalaj na dostęp API z tych notacji sieciowych IP/CIDR",
+        "api_info": "API jest w trakcie prac. Dokumentację można znaleźć pod adresem <a href=\"/api\">/api</a>",
+        "api_key": "klucz API",
+        "api_read_only": "Dostęp tylko do odczytu",
+        "api_read_write": "Dostęp tylko do odczytu",
+        "api_skip_ip_check": "Pomiń sprawdzenie IP dla API",
+        "app_hide": "Ukryj dla logowania",
+        "app_links": "Linki aplikacji",
+        "app_name": "Nazwa aplikacji",
+        "apps_name": "Nazwa \"aplikacji mailcow\"",
+        "arrival_time": "Czas serwera",
+        "authed_user": "Autoryzowany użytkownik",
+        "ays": "Jesteś pewien, że chcesz kontynuować?",
+        "ban_list_info": "Zobacz listę zakazanych adresów IP poniżej: <b>network (pozostały czas zakazu) - [działania]</b>.<br/>IP kolejkowane do odbanowania zostaną usunięte z listy aktywnych zakazów w ciągu kilku sekund.<br/>Czerwone etykiety wskazują aktywny stałe zakazy poprzez odmowę wpisu.",
+        "change_logo": "Zmień logo",
+        "logo_normal_label": "Normalna",
+        "logo_dark_label": "Odwrócony dla trybu ciemnego",
+        "convert_html_to_text": "Konwertuj HTML na zwykły tekst",
+        "copy_to_clipboard": "Tekst skopiowany do schowka!",
+        "cors_settings": "Ustawienia CORS",
+        "credentials_transport_warning": "<b>Ostrzeżenie</b>: Dodanie nowego wpisu mapy transportu spowoduje aktualizację danych uwierzytelniających dla wszystkich wpisów z pasującą kolumną hop.",
+        "customer_id": "Identyfikator klienta",
+        "customize": "Dostosuj",
+        "login_page": "Strona logowania",
+        "destination": "Miejsce docelowe",
+        "dkim_domains_selector": "Selektor",
+        "dkim_domains_wo_keys": "Wybierz domeny z brakującymi kluczami",
+        "dkim_from": "Od",
+        "dkim_from_title": "Domena źródłowa do kopiowania danych z",
+        "dkim_overwrite_key": "Nadpisanie istniejącego klucza DKIM",
+        "dkim_to": "Do",
+        "dkim_to_title": "Domeny docelowe - zostaną nadpisane",
+        "domain_admin": "Administrator domeny",
+        "domainadmin_quicklink": "Ukryj szybki link do strony logowania administratora domeny",
+        "domain_s": "Domena/y",
+        "duplicate": "Duplikat",
+        "duplicate_dkim": "Duplikat rekordu DKIM",
+        "excludes": "Wyklucza tych odbiorców",
+        "f2b_ban_time_increment": "Czas zakazu jest zwiększany z każdym zakazem",
+        "f2b_blacklist": "Lista odrzuconych sieci/hostów",
+        "f2b_filter": "Filtry Regex",
+        "f2b_list_info": "Odrzucony host lub sieć zawsze będzie przewyższać jednostkę zezwalającą.<b>Zastosowanie aktualizacji listy zajmie kilka sekund.</b>",
+        "f2b_manage_external": "Zarządzaj Fail2Ban zewnętrznie",
+        "f2b_manage_external_info": "Fail2ban nadal będzie utrzymywać listę banów, ale nie będzie aktywnie ustalać zasad blokowania ruchu. Użyj wygenerowane listy banów poniżej, aby zewnętrznie zablokować ruch.",
+        "f2b_max_ban_time": "Max. czas bana (s)",
+        "f2b_netban_ipv4": "Rozmiar podsieci IPv4 do zastosowania zakazu (8-32)",
+        "f2b_netban_ipv6": "Rozmiar podsieci IPv6 do zastosowania zakazu (8-128)",
+        "f2b_regex_info": "Logi brane pod uwagę: SOGo, Postfix, Dovecot, PHP-FPM.",
+        "filter": "Filtr",
+        "force_sso_text": "Jeśli skonfigurowany jest zewnętrzny dostawca OIDC, ta opcja ukrywa domyślne formularze logowania mailcow i pokazuje tylko przycisk logowania pojedynczego",
+        "force_sso": "Wyłącz logowanie mailcow i pokaż tylko pojedyncze logowanie",
+        "from": "Od",
+        "generate": "Generuj",
+        "guid": "GUID - unikalny identyfikator instancji",
+        "guid_and_license": "GUID & licencja",
+        "hash_remove_info": "Usunięcie hasha z limitem współczynnika (jeśli nadal istnieje) spowoduje całkowite zresetowanie jego licznika.<br>\n\n\n\n    Każdy hash jest oznaczony indywidualnym kolorem.",
+        "help_text": "Zastąp tekst pomocy poniżej maski logowania (dozwolone HTML)",
+        "html": "HTML",
+        "iam": "Dostawca tożsamości",
+        "iam_attribute_field": "Pole atrybutów",
+        "iam_authorize_url": "Punkt końcowy autoryzacji",
+        "iam_auth_flow": "Przepływ uwierzytelniania",
+        "iam_auth_flow_info": "Oprócz przepływu kodu autoryzacyjnego (Standardowy przepływ w Keycloak), który służy do logowania jednokrotnego logowania, mailcow obsługuje również przepływ uwierzytelniania z bezpośrednimi poświadczeniami. Mailpassword Flow próbuje zweryfikować dane uwierzytelniające użytkownika za pomocą Keycloak Admin REST API. mailcow pobiera hashowane hasło z atrybutu <code>mailcow_password</code>, który jest mapowany w Keycloak.",
+        "iam_basedn": "Baza DN",
+        "iam_client_id": "ID klienta",
+        "iam_client_secret": "Sekret klienta",
+        "iam_client_scopes": "Zakresy klientów",
+        "iam_default_template": "Domyślny szablon",
+        "iam_default_template_description": "Jeśli użytkownikowi nie zostanie przypisany żaden szablon, domyślny szablon zostanie użyty do utworzenia skrzynki pocztowej, ale nie do aktualizacji skrzynki pocztowej.",
+        "iam_description": "Skonfiguruj zewnętrznego dostawce uwierzytelniania<br>Skrzynki pocztowe użytkownika zostaną automatycznie utworzone przy pierwszym logowaniu, pod warunkiem, że zostało ustawione mapowanie atrybutów.",
+        "iam_extra_permission": "Aby następujące ustawienia działały, klient mailcow w Keycloak potrzebuje <code>konta serwisowego</code> oraz uprawnień do <code>podgląd-użytkowników</code>.",
+        "iam_host": "Host",
+        "iam_host_info": "Wprowadź jeden lub więcej hostów LDAP, oddzielonych przecinkami.",
+        "iam_import_users": "Zaimportuj użytkowników",
+        "iam_login_provisioning": "Automatyczne tworzenie użytkowników przy logowaniu",
+        "iam_mapping": "Mapowanie atrybutów",
+        "iam_bindpass": "Powiąż hasło",
+        "iam_periodic_full_sync": "Okresowa pełna synchronizacja",
+        "iam_port": "Port",
+        "iam_realm": "Realm",
+        "iam_redirect_url": "Przekierowanie Url",
+        "iam_rest_flow": "Procedura uwierzytelniania hasła pocztowego",
+        "iam_server_url": "Adres URL serwera",
+        "iam_sso": "Pojedyncze logowanie",
+        "iam_sync_interval": "Interwał synchronizacji / importu (min)",
+        "iam_test_connection": "Test połączenia",
+        "iam_token_url": "Tokenowy punkt końcowy",
+        "iam_userinfo_url": "Endpoint informacji o użytkowniku",
+        "iam_username_field": "Pole nazwy użytkownika",
+        "iam_binddn": "Powiąź DN",
+        "iam_use_ssl": "Używaj SSL",
+        "iam_use_ssl_info": "Jeśli włączysz SSL, a port zostanie ustawiony na 389, zostanie automatycznie nadpisany, aby użyć 636.",
+        "iam_use_tls": "Używaj StartTLS",
+        "iam_use_tls_info": "Jeśli włączono TLS, należy użyć domyślnego portu dla serwera LDAP (389). Nie można używać portów SSL.",
+        "iam_version": "Wersja",
+        "ignore_ssl_error": "Ignoruj błędy SSL",
+        "in_use_by": "W użyciu przez",
+        "include_exclude": "Uwzględnij/Nie uwzględniaj",
+        "include_exclude_info": "Domyślnie - bez zaznaczenia - <b>wszystkie skrzynki pocztowe</b> są adresowane",
+        "includes": "Uwzględnij tych odbiorców",
+        "ip_check": "Sprawdź IP",
+        "ip_check_disabled": "Sprawdzenie IP jest wyłączone. Możesz go włączyć w obszarze <br> <strong>System > Konfiguracja > Opcje > Dostosuj</strong>",
+        "ip_check_opt_in": "Opt-In korzystania z usług stron trzecich <strong>ipv4.mailcow.email</strong> i <strong>ipv6.mailcow.email</strong> w celu rozwiązania zewnętrznych adresów IP.",
+        "is_mx_based": "Bazuje na MX",
+        "last_applied": "ostatnio zastosowany",
+        "license_info": "Licencja nie jest wymagana, ale pomaga w dalszym rozwoju.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">Zarejestruj swój GUID tutaj</a> lub <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Zamówienie wsparcia\">kup wsparcie dla instalacji mailcow.</a>",
+        "link": "Link",
+        "login_time": "Cześć logowania",
+        "logo_info": "Twój obraz zostanie przeskalowany do wysokości 40px dla górnego paska nawigacyjnego i max. szerokości 250px dla strony startowej. Zalecana jest skalowalna grafika.",
+        "recipients": "Odbiorcy",
+        "send": "Wyślij",
+        "sender": "Nadawca",
+        "lookup_mx": "Destynacja jest regularnym wyrażeniem, które pasuje do nazwy MX (<code>.*\\\\.google\\.com</code>, aby przekierować całą pocztę skierowaną do MX kończącego się na google.com w tym hopie)",
+        "main_name": "Nazwa \"mailcow UI\"",
+        "merged_vars_hint": "Wyszarzone wiersze zostały połączone z <code>vars. (local.) inc.php</code> i nie można ich modyfikować.",
+        "message_size": "Rozmiar wiadomości",
+        "nexthop": "Następny hop",
+        "needs_restart": "potrzebny restart",
+        "no": "&#10005;",
+        "no_active_bans": "Brak aktywnych banów",
+        "no_new_rows": "Brak dostępnych kolejnych wierszy",
+        "oauth2_apps": "Aplikacje OAuth2",
+        "oauth2_add_client": "Dodaj klienta OAuth2",
+        "oauth2_client_id": "ID klienta",
+        "oauth2_client_secret": "Sekret klienta",
+        "oauth2_info": "Implementacja OAuth2 obsługuje typ grantu \"Kod autoryzacji\" i wydaje tokeny odświeżania.<br>\nSerwer automatycznie wydaje również nowe tokeny odświeżania, po użyciu tokena odświeżania.<br><br>\n&#8226; Domyślnym zakresem jest <i>profil</i>. Tylko użytkownicy skrzynek pocztowych mogą być uwierzytelniani w OAuth2. Jeśli parametr zakresu zostanie pominięty, wraca do <i>profil</i>.<br>\n\nParametr <i>state</i> musi zostać wysłany przez klienta w ramach żądania autoryzacji.<br><br>>\nŚcieżki zapytań do API OAuth2: <br>\n<ul>\nPunkt końcowy autoryzacji\n<code>/oauth/authorize</code></li> <li>Token endpoint: <code>/oauth/token</code></li> <li>Resource page: <code>/oauth/profile</code></li>\n</ul>\nRegeneracja tajemnicy klienta nie spowoduje wygaśnięcia istniejących kodów autoryzacyjnych, ale nie odnowi ich tokena.<br><br>\nOdwołanie tokenów klienta spowoduje natychmiastowe zakończenie wszystkich aktywnych sesji. Wszyscy klienci muszą się ponownie uwierzytelnić.",
+        "oauth2_redirect_uri": "Przekieruj URI",
+        "oauth2_renew_secret": "Wygeneruj sekret nowego klienta",
+        "oauth2_revoke_tokens": "Unieważnij wszystkie tokeny klienta",
+        "optional": "Opcjonalny",
+        "options": "Opcje",
+        "password_length": "Długość hasła",
+        "password_policy": "Polityka haseł",
+        "password_policy_chars": "Musi zawierać co najmniej jeden znak alfabetyczny",
+        "password_policy_length": "Minimalna długość hasła to %d",
+        "password_policy_lowerupper": "Musi zawierać małe i duże litery",
+        "password_policy_numbers": "Musi zawierać co najmniej jeden numer",
+        "password_policy_special_chars": "Musi zawierać znaki specjalne",
+        "password_reset_info": "Jeśli nie jest udostępniony e-mail zapasowy, ta funkcja nie może być używana.",
+        "password_reset_settings": "Ustawienia odzyskiwania haseł",
+        "password_reset_tmpl_html": "Szablon HTML",
+        "password_reset_tmpl_text": "Szablon tekstu",
+        "password_settings": "Ustawienia hasła",
+        "quarantine_bcc": "Wyślij kopię wszystkich powiadomień (BCC) do tego odbiorcy: <br><small>Pozostaw pustą aby wyłączyć. <b>Niepodpisana, niezaznaczona poczta. Powinna być dostarczana tylko wewnętrznie.</b></small>",
+        "quarantine_exclude_domains": "Wyklucz domeny i domeny aliasowe",
+        "quarantine_max_age": "Maksymalny wiek w dniach <br><small>Wartość musi być równa lub większa niż 1 dzień.</small>",
+        "quarantine_max_score": "Odrzuć powiadomienie, jeśli wskaźnik spamu wiadomości jest wyższy niż ta wartość: <br><small>Domyślne do 9999.0</small>",
+        "quarantine_max_size": "Maksymalny rozmiar w MiB (większe elementy są odrzucane):<br><small>0 oznacza, że <b>nie</b> oznacza nieograniczony.</small>",
+        "quarantine_notification_html": "Szablon wiadomości e-mail z powiadomieniem:<br><small> Pozostaw puste, aby przywrócić szablon domyślny.</small>",
+        "quarantine_notification_sender": "Powiadomienie nadawcy wiadomości e-mail",
+        "quarantine_notification_subject": "Powiadomienie E-mail Temat",
+        "quarantine_redirect": "<b>Przekieruj wszystkie powiadomienia </b> do tego odbiorcy:<br><small> Pozostaw pusty aby wyłączyć. <b>Niepodpisana, niezaznaczona poczta. Powinny być dostarczane tylko wewnętrznie.</b></small>",
+        "quarantine_release_format": "Format zwolnionych przedmiotów",
+        "quarantine_release_format_att": "Jako załącznik",
+        "quarantine_release_format_raw": "Niezmodyfikowany oryginał",
+        "quarantine_retention_size": "Retencje na skrzynkę pocztową: <br><small>0 oznacza <b>nieaktywne</b>.</small>",
+        "quicklink_text": "Pokaż lub ukryj szybkie linki do innych stron logowania pod formularzem logowania",
+        "quota_notification_html": "Szablon wiadomości e-mail z powiadomieniem:<br><small> Pozostaw puste, aby przywrócić szablon domyślny.</small>",
+        "quota_notification_sender": "Powiadomienie nadawcy wiadomości e-mail",
+        "quota_notification_subject": "Temat powiadomienia e-mail",
+        "quota_notifications": "Powiadomienia o limitach",
+        "quota_notifications_info": "Powiadomienia o limktach są wysyłane do użytkowników raz przy przekroczaniu 80% i raz przy przekraczaniu 95% zużycia.",
+        "quota_notifications_vars": "{{percent}} równa się aktualnemu limitowi użytkownika<br>{{username}} jest nazwą skrzynki pocztowej",
+        "queue_unban": "Zdejmij bana",
+        "rate_name": "Nazwa oceny",
+        "regen_api_key": "Regeneruj klucz API",
+        "regex_maps": "Mapy Regex",
+        "relay_from": "\"Od:\" adres",
+        "relay_rcpt": "\"Do:\"Adres",
+        "relay_run": "Uruchom test",
+        "relayhosts": "Transporty zależne od nadawcy",
+        "relayhosts_hint": "Zdefiniuj transporty zależne od nadawcy, aby móc wybrać je w oknie dialogowym konfiguracji domeny.<br>\nUsługa transportu jest zawsze \"smtp:\" i dlatego uruchomj TLS, gdy będzie oferowana. Owinięty TLS (SMTPS) nie jest obsługiwany. Pod uwagę brane jest indywidualne ustawienie polityki wychodzącej TLS użytkownika.<br>\nDotyczy wybranych domen, w tym domen aliasowych.",
+        "remove_row": "Usuń wiersz",
+        "reset_default": "Zresetuj do ustawień domyślnych",
+        "reset_limit": "Usuń hash",
+        "reset_password_vars": "<code>{{link}}</code> Wygenerowany link do resetu hasła <br><code>{{username}}</code> Nazwa skrzynki pocztowej użytkownika, który poprosił o zresetowanie hasła<br><code>{{username2}}</code> Nazwa skrzynki pocztowej do odzyskiwania <br><code>{{date}}</code> Data złożenia żądania resetowania hasła<br><code>{{token_lifetime}}</code>Żywotność tokena w minutach<br><code>{{hostname}}</code> Nazwa hosta mailcow",
+        "restore_template": "Pozostaw puste, aby przywrócić szablon domyślny.",
+        "routing": "Routowanie",
+        "rsetting_add_rule": "Dodaj regułę",
+        "rsetting_content": "Zawartość reguły",
+        "rsetting_desc": "Krótki opis",
+        "rsetting_no_selection": "Proszę zaznaczyć regułę",
+        "rsetting_none": "Brak dostępnych reguł",
+        "rsettings_insert_preset": "Wstaw przykładowy preset",
+        "rsettings_preset_1": "Wyłącz wszystkie z wyjątkiem DKIM i limitu stawek dla uwierzytelnionych użytkowników",
+        "rsettings_preset_2": "Administratorzy poczty pozwalają na spam",
+        "rsettings_preset_3": "Zezwalaj tylko określonym nadawcom na skrzynkę pocztową (tj. używaj tylko jako wewnętrznej skrzynki pocztowej)",
+        "rsettings_preset_4": "Wyłącz Rspamd dla domeny",
+        "rspamd_com_settings": "Nazwa ustawienia zostanie automatycznie wygenerowana, zobacz przykładowe ustawienia wstępne poniżej. Aby uzyskać więcej informacji, zobacz <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd docs</a>",
+        "rspamd_global_filters": "Globalne mapy filtrów",
+        "rspamd_global_filters_agree": "Będę ostrożny!",
+        "rspamd_global_filters_info": "Globalne mapy filtrów zawierają różne rodzaje globalnych list dozwolonych i zablokowanych adresów.",
+        "rspamd_global_filters_regex": "Ich imiona wyjaśniają ich cel. Cała zawartość musi zawierać ważne wyrażenie regularne w formacie \"/pattern/options\" (e.g. <code>/.+@domain\\.tld/i</code>).<br>\nChociaż podstawowe kontrole są wykonywane na każdej linii regex, funkcja Rspamd może zostać złamana, jeśli nie odczyta poprawnie składni.<br>>\nRspamd po zmianie spróbuje odczytać zawartość mapy. Jeśli wystąpią problemy, <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">restart Rspamd</a>, aby wymusić ponowne ładowanie mapy.<br> Elementy z listy odrzuconych są wyłączone z kwarantanny.",
+        "rspamd_settings_map": "Mapa ustawień Rspamd",
+        "sal_level": "Poziom Moo",
+        "service": "Usługa",
+        "service_id": "Id usługi",
+        "subject": "Temat",
+        "success": "Sukces",
+        "sys_mails": "Maile systemowe",
+        "task": "Zadanie",
+        "text": "Tekst",
+        "title": "Tytuł",
+        "title_name": "Tytuł strony internetowej \"mailcow UI\"",
+        "to_top": "Powrót na górę",
+        "transport_dest_format": "Regex lub syntax: example.org, .example.org, *, box@example.org(wiele wartości można rozdzielić przecinkami)",
+        "transport_maps": "Mapy transportu",
+        "transport_test_rcpt_info": "&#8226; Użyj null@hosted.mailcow.de aby przetestować przekazywanie do nieznanego miejsca docelowego.",
+        "transports_hint": "&#8226; Wpis mapy transportowej <b>overrules</b> mapa transportowa zależna od nadawcy</b>.<br>\nNajlepiej stosować transporty oparte na MX &#8226;.<br>\nUstawienia zasad Outbound TLS dotyczące użytkownika są ignorowane i mogą być egzekwowane tylko przez wpisy mapy zasad TLS\n&#8226; Usługa transportu dla zdefiniowanych transportów jest zawsze \"smtp:\" i dlatego uruchomi TLS, gdy będzie oferowana. Wrapped TLS (SMTPS) nie jest obsługiwany.<br>\nAdresy pasujące do \"/localhost$/\" będą zawsze transportowane przez \"lokalne:\", dlatego miejsce docelowe \"*\" nie będzie miało zastosowania do tych adresów.<br>\n&#8226; Aby określić poświadczenia dla przykładowego następnego hopa \"[host]:25\", Postfix <b>zawsze</b> kolejkuje zapytania o \"host\" przed wyszukaniem \"[host]:25\". Takie zachowanie uniemożliwia jednoczesne użycie \"host\" i \"[host]:25.",
+        "ui_footer": "Stopka (dozwolone HTML)",
+        "ui_header_announcement": "Ogłoszenia",
+        "ui_header_announcement_active": "Ustaw ogłoszenie jako aktywne",
+        "ui_header_announcement_content": "Tekst (dozwolony HTML)",
+        "ui_header_announcement_help": "Ogłoszenie jest widoczne dla wszystkich zalogowanych użytkowników oraz na ekranie logowania interfejsu użytkownika.",
+        "ui_header_announcement_select": "Wybierz typ ogłoszenia",
+        "ui_header_announcement_type": "Typ",
+        "ui_header_announcement_type_danger": "Bardzo ważne",
+        "ui_header_announcement_type_info": "Info",
+        "ui_header_announcement_type_warning": "Ważne",
+        "ui_texts": "Etykiety i teksty UI",
+        "unban_pending": "oczekuje na odblokowanie",
+        "upload": "Prześlij",
+        "user_link": "Link użytkownika",
+        "user_quicklink": "Ukryj Quicklink do strony logowania użytkownika",
+        "validate_license_now": "Sprawdź identyfikator GUID względem serwera licencji",
+        "verify": "Zweryfikuj",
+        "yes": "&#10003;"
     },
     "danger": {
         "access_denied": "Odmowa dostępu lub nieprawidłowe dane w formularzu",
         "alias_domain_invalid": "Alias domeny nieprawidłowy",
         "alias_empty": "Alias nie może być pusty",
         "alias_goto_identical": "Alias i Idź do nie mogą być identyczne",
-        "alias_invalid": "Alias nieprawidłowy",
+        "alias_invalid": "Adres aliasu jest nieprawidłowy",
         "aliasd_targetd_identical": "Alias domeny nie może być identyczny z domeną docelową",
         "aliases_in_use": "Maks. liczba aliasów musi być większa od lub równa %d",
         "description_invalid": "Nieprawidłowy opis źródła",
         "dkim_domain_or_sel_invalid": "Nieprawidłowa domena lub selektor DKIM",
-        "domain_exists": "Domena %s już istnieje",
-        "domain_invalid": "Błędna nazwa domeny",
+        "domain_exists": "Domena już istnieje",
+        "domain_invalid": "Nazwa domeny jest pusta lub nieprawidłowa",
         "domain_not_empty": "Nie można usunąć niepustej domeny",
-        "domain_not_found": "Nie znaleziono domeny %s",
-        "domain_quota_m_in_use": "Limit domeny %s MiB",
-        "goto_empty": "Adres Idź do nie może być pusty",
+        "domain_not_found": "Nie znaleziono domeny",
+        "domain_quota_m_in_use": "Limit domeny musi być większy lub równy do MiB",
+        "goto_empty": "Adres alias musi zawierać co najmniej jeden prawidłowy adres goto",
         "goto_invalid": "Adres Idź do jest nieprawidłowy",
-        "is_alias": "%s został już podany jako alias",
-        "is_alias_or_mailbox": "%s podano wcześniej jako alias lub skrzynkę",
-        "is_spam_alias": "%s podano wcześniej jako alias dla spam",
-        "last_key": "Nie można usunąć ostatniego klucza",
-        "login_failed": "Niepowodzenie logowania",
+        "is_alias": "został już podany jako alias",
+        "is_alias_or_mailbox": "jest już znany jako alias, skrzynka pocztowa lub adres aliasu rozwinięty z domeny aliasu.",
+        "is_spam_alias": "jest już znany jako tymczasowy adres aliasu (adres aliasu antyspamowego)",
+        "last_key": "Nie można usunąć ostatniego klucza, zamiast tego należy wyłączyć TFA.",
+        "login_failed": "Logowanie nie powiodło się",
         "mailbox_invalid": "Nieprawidłowa nazwa skrzynki",
         "mailbox_quota_exceeded": "Wielkość przekracza limit domeny (maks. %d MiB)",
         "mailbox_quota_exceeds_domain_quota": "Maksymalna wielkość przekracza limit domeny",
@@ -145,8 +456,107 @@
         "sender_acl_invalid": "ACL Nadawcy jest nieprawidłowy",
         "target_domain_invalid": "Domena Idź do jest nieprawidłowa",
         "targetd_not_found": "Nie znaleziono domeny docelowej",
-        "username_invalid": "Nie można użyć nazwy użytkownika",
-        "validity_missing": "Proszę wyznaczyć termin ważności"
+        "username_invalid": "Nie można użyć tej nazwy użytkownika",
+        "validity_missing": "Proszę wyznaczyć termin ważności",
+        "to_invalid": "Pole odbiorca nie może być puste",
+        "app_name_empty": "Nazwa aplikacji nie może być pusta",
+        "app_passwd_id_invalid": "Identyfikator hasła aplikacji jest niepoprawny",
+        "authsource_in_use": "Nie można zmienić ani usunąć dostawcy tożsamości, ponieważ jest używany przez co najmniej jednego użytkownika.",
+        "bcc_empty": "Miejsce docelowe BCC nie może być puste",
+        "bcc_exists": "Mapa BCC istnieje już dla tego typu",
+        "bcc_must_be_email": "Miejsce docelowe BCC nie jest prawidłowym adresem e-mail",
+        "comment_too_long": "Komentarz zbyt długi, maksymalnie 160 dozwolonych znaków",
+        "cors_invalid_method": "Podano nieprawidłową metodę Allow-Method",
+        "cors_invalid_origin": "Podano nieprawidłową wartość Allow-Origin",
+        "defquota_empty": "Domyślny limit skrzynki pocztowej nie może wynosić 0.",
+        "demo_mode_enabled": "Tryb demo jest włączony",
+        "dkim_domain_or_sel_exists": "Klucz DKIM już istnieje i nie zostanie nadpisany",
+        "domain_cannot_match_hostname": "Domena nie może być taka sama jak nazwa hosta",
+        "extended_sender_acl_denied": "brak ACL do ustawiania adresów nadawcy zewnętrznego",
+        "extra_acl_invalid": "Adres nadawcy zewnętrznego jest nieprawidłowy",
+        "extra_acl_invalid_domain": "Nadawca zewnętrzny używa nieprawidłowej domeny",
+        "fido2_verification_failed": "Weryfikacja FIDO2 nie powiodła się",
+        "file_open_error": "Nie można otworzyć pliku do zapisu",
+        "filter_type": "Niewłaściwy typ filtra",
+        "from_invalid": "Nadawca nie może być pusty",
+        "generic_server_error": "Wystąpił nieoczekiwany błąd serwera. Skontaktuj się z administratorem.",
+        "global_filter_write_error": "Nie można zapisać pliku filtra",
+        "global_map_invalid": "Id mapy globalnej nieprawidłowe",
+        "global_map_write_error": "Nie można zapisać globalnej mapy ID",
+        "ham_learn_error": "Błąd uczenia ham",
+        "iam_test_connection": "Połączenie nie powiodło się",
+        "imagick_exception": "Błąd: wyjątek Imagick podczas odczytu obrazu",
+        "img_dimensions_exceeded": "Obraz przekracza maksymalny rozmiar obrazu",
+        "img_invalid": "Nie można zweryfikować pliku obrazu",
+        "img_size_exceeded": "Obraz przekracza maksymalny rozmiar pliku",
+        "img_tmp_missing": "Nie można zweryfikować pliku obrazu: Nie znaleziono pliku tymczasowego",
+        "invalid_bcc_map_type": "Nieprawidłowy typ mapy BCC",
+        "invalid_destination": "Format docelowy jest nieprawidłowy",
+        "invalid_filter_type": "Nieprawidłowy typ filtra",
+        "invalid_host": "Nieprawidłowy określony host",
+        "invalid_mime_type": "Niepoprawny typ mime",
+        "invalid_nexthop": "Następny format hop jest nieprawidłowy",
+        "invalid_nexthop_authenticated": "Następny hop już istnieje z innymi danymi logowania, zaktualizuj najpierw istniejące dane uwierzytelniające dla tego hopa.",
+        "invalid_recipient_map_new": "Określony nieprawidłowy nowy odbiorca",
+        "invalid_recipient_map_old": "Określony nieprawidłowy pierwotny odbiorca",
+        "invalid_reset_token": "Nieprawidłowy token resetu",
+        "ip_list_empty": "Lista dozwolonych adresów IP nie może być pusta",
+        "mailbox_defquota_exceeds_mailbox_maxquota": "Domyślny limit skrzynki pocztowej przekracza maksymalny dozwolony limit",
+        "malformed_username": "Nieprawidłowy format nazwy użytkownika",
+        "map_content_empty": "Zawartość mapy nie może być pusta",
+        "max_age_invalid": "Nieprawidłowa wartość maksymalnego wieku: %s",
+        "mode_invalid": "Tryb %s jest nieprawidłowy",
+        "mx_invalid": "Rekord MX %s jest nieprawidłowy",
+        "mysql_error": "Błąd MySQL: %s",
+        "network_host_invalid": "Nieprawidłowa sieć lub host: %s",
+        "next_hop_interferes": "%s powoduje konflikt z nexthopem %s",
+        "next_hop_interferes_any": "Istniejący next hop koliduje z %s.”",
+        "nginx_reload_failed": "Nie udało się przeładować Nginx: %s",
+        "no_user_defined": "Brak zdefiniowanego użytkownika",
+        "password_reset_invalid_user": "Skrzynka pocztowa nie została znaleziona lub nie ustawiono adresu e-mail do odzyskiwania",
+        "password_reset_na": "Odzyskiwanie hasła jest obecnie niedostępne. Skontaktuj się ze swoim administratorem.",
+        "private_key_error": "Błąd klucza prywatnego: %s",
+        "pushover_credentials_missing": "Brak tokena i/lub klucza Pushover",
+        "pushover_key": "Klucz Pushover ma niewłaściwy format",
+        "pushover_token": "Token Pushover ma zły format",
+        "recipient_map_entry_exists": "Istnieje wpis mapy odbiorcy \"%s",
+        "recovery_email_failed": "Nie można wysłać e-maila odzyskiwania. Skontaktuj się ze swoim administratorem.",
+        "redis_error": "Błąd Redis: %s",
+        "relayhost_invalid": "Wpis mapy %s jest niepoprawny",
+        "release_send_failed": "Nie udało się zwolnić wiadomości: %s",
+        "required_data_missing": "Brakuje wymaganych danych %s",
+        "reset_f2b_regex": "Filtr Regex nie mógł zostać zresetowany na czas, spróbuj ponownie lub poczekaj jeszcze kilka sekund i przeładuj stronę.",
+        "reset_token_limit_exceeded": "Limit tokenów Reset został przekroczony. Spróbuj ponownie później.",
+        "rl_timeframe": "Nieprawidłowo ustawiony przedział czasu limitu",
+        "rspamd_ui_pw_length": "Hasło do Rspamd UI powinno mieć co najmniej 6 znaków długości",
+        "script_empty": "Skrypt nie może być pusty",
+        "set_acl_failed": "Nie udało się ustawić ACL",
+        "settings_map_invalid": "Ustawienia id mapy %s są nieprawidłowe",
+        "sieve_error": "Błąd podczas analizy skryptu Sieve: %s",
+        "spam_learn_error": "Błąd uczenia spamu: %s",
+        "subject_empty": "Temat nie może być pusty",
+        "targetd_relay_domain": "Domena docelowa %s jest skonfigurowana jako domena przekazująca relay",
+        "template_exists": "Szablon %s już istnieje",
+        "template_id_invalid": "Identyfikator szablonu %s niepoprawny",
+        "template_name_invalid": "Nazwa szablonu niepoprawna",
+        "temp_error": "Tymczasowy błąd",
+        "text_empty": "Pole tekstowe nie może być puste",
+        "tfa_token_invalid": "Niepoprawny token TFA",
+        "tls_policy_map_dest_invalid": "Podano błędne lub nieobsługiwane miejsce docelowe dla tej polityki",
+        "tls_policy_map_entry_exists": "Istnieje mapa polityki TLS \"%s",
+        "tls_policy_map_parameter_invalid": "Parametr polityki jest nieprawidłowy",
+        "totp_verification_failed": "Weryfikacja TOTP nie powiodła się",
+        "transport_dest_exists": "Miejsce docelowe transportu „%s” już istnieje",
+        "webauthn_verification_failed": "Weryfikacja WebAuthn nie powiodła się: %s",
+        "webauthn_authenticator_failed": "Wybrany autoryzator nie został odnaleziony",
+        "webauthn_publickey_failed": "Nie przechowywano klucza publicznego dla wybranego uwierzytelniacza",
+        "webauthn_username_failed": "Wybrany autoryzator należy do innego konta",
+        "unknown": "Wystąpił nieznany błąd",
+        "unknown_tfa_method": "Nieznana metodą TFA",
+        "unlimited_quota_acl": "Ustawienie nieograniczonego limitu przestrzeni jest zabronione przez reguły ACL",
+        "value_missing": "Proszę o podanie wszystkich wartości",
+        "version_invalid": "Wersja %s jest niepoprawna",
+        "yotp_verification_failed": "Weryfikacja OTP Yubico nie powiodła się: %s"
     },
     "edit": {
         "active": "Aktywny",
@@ -179,7 +589,7 @@
         "previous": "Poprzednia strona",
         "quota_mb": "Limit wielkośći (MiB)",
         "relay_all": "Przekaż wszystkim odbiorcom",
-        "relay_all_info": "<small>Jeśli decydujesz się <b>nie</b> przekazywać wszystkim odbiorcom, musisz dodać (\"ślepą\")skrzynkę dla każdego poszczególnego odbiorcy, któremu należy przekazać.</small>",
+        "relay_all_info": "↪ Jeśli zdecydujesz się <b>nie</b> przekazywać wszystkim odbiorcom, musisz dodać (\"ślepą\")skrzynkę dla każdego poszczególnego odbiorcy, któremu należy przekazać.",
         "relay_domain": "Domena przekaźnikowa",
         "remove": "Usuń",
         "resource": "Zasób",
@@ -191,15 +601,104 @@
         "target_domain": "Domena docelowa",
         "title": "Edytuj obiekt",
         "unchanged_if_empty": "Jeżli bez zmian, nie wypełniaj",
-        "username": "Nazwa użytkownika"
+        "username": "Nazwa użytkownika",
+        "delete_ays": "Proszę o potwierdzenie procesu usuwania.",
+        "acl": "ACL (Pozwolenie)",
+        "admin": "Edytyj administratora",
+        "advanced_settings": "Ustawienia zaawansowane",
+        "allow_from_smtp": "Zezwalaj tylko tym adresom IP na używanie <b>SMTP</b>",
+        "allow_from_smtp_info": "Pozostaw puste, aby zezwolić na wszystkich nadawców.<br>adresy IPv4/IPv6 i sieci.",
+        "allowed_protocols": "Dozwolone protokoły dla bezpośredniego dostępu użytkownika (nie wpływa na protokoły haseł aplikacji)",
+        "app_name": "Nazwa aplikacji",
+        "app_passwd": "Hasło do aplikacji",
+        "app_passwd_protocols": "Dozwolone protokoły dla hasła aplikacji",
+        "automap": "Spróbuj automatycznie mapować foldery (np. „Sent items”, „Sent” ⇒ „Sent” itp.)",
+        "bcc_dest_format": "Miejscem docelowym BCC musi być jeden prawidłowy adres e-mail.<br>Jeśli chcesz wysłać kopię na wiele adresów, utwórz alias i użyj go tutaj.",
+        "client_id": "Id klienta",
+        "client_secret": "Tajny klucz klienta(sekret)",
+        "comment_info": "Komentarz prywatny nie jest widoczny dla użytkownika, natomiast komentarz publiczny jest wyświetlany jako podpowiedź po najechaniu kursorem w widoku użytkownika",
+        "created_on": "Stworzony na",
+        "custom_attributes": "Niestandardowe atrybuty",
+        "delete2": "Usuń wiadomości na koncie docelowym, które nie występują na koncie źródłowym",
+        "disable_login": "Zablokuj logowanie (przychodząca poczta nadal będzie przyjmowana)",
+        "domain_footer": "Stopka dla całej domeny",
+        "domain_footer_html": "Stopka HTML",
+        "domain_footer_info": "Stopki dla całej domeny są dodawane do wszystkich wychodzących wiadomości e-mail powiązanych z adresami w tej domenie.<br>W stopce można użyć następujących zmiennych:",
+        "domain_footer_info_vars": {
+            "auth_user": "{= auth_user =} - Uwierzytelniona nazwa użytkownika określona przez MTA",
+            "from_user": "{= from_user =} – część użytkownika (local-part) adresu nadawcy; np. dla „moo@mailcow.tld\n” zwróci „moo”",
+            "from_name": "{= from_name =} – nazwa nadawcy (From name) z nagłówka wiadomości; np. dla \"Mailcow &lt;moo@mailcow.tld&gt;\" zwróci \"Mailcow\"",
+            "from_addr": "{= from_addr =} – pełny adres nadawcy (z części envelope)",
+            "from_domain": "{= from_domain =} – część domenowa adresu nadawcy (z envelope)",
+            "custom": "{= foo =}         - jeśli skrzynka pocztowa ma niestandardowy atrybut „foo” o wartości „bar”, zwraca „bar”"
+        },
+        "domain_footer_plain": "Stopka w formacie tekstowym(PLAIN)",
+        "domain_footer_skip_replies": "Nie dodawaj stopki do odpowiedzi na e-maile",
+        "extended_sender_acl": "Adresy nadawców zewnętrznych",
+        "extended_sender_acl_info": "Klucz DKIM dla domeny powinien zostać zaimportowany, jeśli jest dostępny.\nPamiętaj, aby dodać ten serwer do odpowiadającego rekordu SPF typu TXT.\nKiedy domena lub domena aliasu zostanie dodana do tego serwera i pokrywa się z zewnętrznym adresem, zewnętrzny adres zostanie usunięty.",
+        "force_pw_update": "Wymuszenie aktualizacji hasła przy następnym logowaniu",
+        "force_pw_update_info": "Ten użytkownik będzie mógł logować się wyłącznie tutaj %s. Hasła aplikacyjne pozostają aktywne.",
+        "footer_exclude": "Wyklucz ze stopki",
+        "gal": "Globalna lista adresowa",
+        "gal_info": "GAL zawiera wszystkie obiekty domeny i nie może być edytowana przez żadnego użytkownika. Informacje o dostępności (free/busy) w SOGo są niedostępne, jeśli funkcja jest wyłączona!<b>Uruchom ponownie SOGo, aby zastosować zmiany.</b>",
+        "generate": "generuj",
+        "grant_types": "Rodzaje grantów(Typy przyznawania dostępu)",
+        "internal": "Wewnętrzny",
+        "internal_info": "Aliasów wewnętrznych można używać tylko w obrębie własnej domeny lub domen aliasów.",
+        "last_modified": "Ostatnio modyfikowany",
+        "lookup_mx": "Destination to wyrażenie regularne dopasowujące nazwę serwera MX (np. <code>.*.google.com</code> — aby kierować całą pocztę wysyłaną do MX kończących się na google.com przez ten hop)",
+        "pushover_title": "Tytuł powiadomienia",
+        "pushover_sound": "Dźwięk powiadomienia",
+        "pushover_vars": "Gdy nie zdefiniowano żadnego filtra nadawcy, brane będą pod uwagę wszystkie wiadomości. Filtry oparte na wyrażeniach regularnych (regex) oraz dokładne dopasowania nadawców można definiować indywidualnie — będą one przetwarzane kolejno, niezależnie od siebie. Dostępne zmienne do użycia w treści i tytule (należy pamiętać o zasadach ochrony danych osobowych).",
+        "pushover_verify": "Zweryfikuj dane logowania",
+        "quota_warning_bcc": "Ukryta kopia ostrzeżenia o przekroczeniu limitu",
+        "quota_warning_bcc_info": "Ostrzeżenia będą wysyłane jako osobne kopie do poniższych odbiorców. Temat wiadomości zostanie rozszerzony o nazwę użytkownika w nawiasach, na przykład: <code>Ostrzeżenie o limicie (user@example.com\n)</code>.",
+        "ratelimit": "Limit wysyłania",
+        "redirect_uri": "Adres przekierowania / adres zwrotny (Redirect/Callback URL)",
+        "relay_transport_info": "<div class=\"badge fs-6 bg-info\">Informacja</div> **Możesz zdefiniować mapy transportu (transport maps) dla niestandardowego miejsca docelowego tej domeny.** Jeśli nie zostanie to ustawione, zostanie wykonane wyszukiwanie",
+        "relay_unknown_only": "Przekazuj (relay) tylko nieistniejące skrzynki pocztowe. Istniejące skrzynki będą dostarczane lokalnie.",
+        "relayhost": "Transporty przypisane do nadawcy",
+        "scope": "Zakres",
+        "sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Sprawdzanie nadawcy jest wyłączone</span>",
+        "sender_acl_info": "Jeżeli użytkownik skrzynki pocztowej A ma pozwolenie na wysyłkę jako użytkownik skrzynki B, adres nadawcy nie jest automatycznie wyświetlany jako opcja w polu „Od” w SOGo.<br>\nUżytkownik skrzynki B musi utworzyć delegację w SOGo, aby użytkownik A mógł wybrać ich adres jako nadawcę. Aby zdelegować skrzynkę w SOGo, użyj menu (trzy kropki) po prawej stronie nazwy skrzynki w lewym górnym rogu, będąc w widoku poczty. To zachowanie nie dotyczy adresów aliasów.",
+        "sieve_desc": "Krótki opis",
+        "sieve_type": "Typ filtra",
+        "skipcrossduplicates": "Pomijaj duplikaty wiadomości w różnych folderach (pierwsza napotkana wiadomość zostaje zachowana).",
+        "sogo_access": "Bezpośrednie przekazywanie do SOGo",
+        "sogo_access_info": "Po zalogowaniu użytkownik jest automatycznie przekierowywany do SOGo.",
+        "sogo_visible": "Alias jest widoczny w SOGO",
+        "sogo_visible_info": "Ta opcja dotyczy tylko obiektów, które mogą być wyświetlane w SOGo (aliasy współdzielone lub nie współdzielone, wskazujące przynajmniej na jedną lokalną skrzynkę).\nJeśli obiekt zostanie ukryty, alias nie będzie dostępny jako wybieralny nadawca w SOGo.",
+        "spam_alias": "Tworzenie lub zmiana ograniczonych czasowo adresów aliasów",
+        "spam_filter": "Filtr spam",
+        "spam_policy": "Dodaj lub usuń elementy z listy dozwolonych / zablokowanych",
+        "spam_score": "Ustaw własny poziom punktacji spamu",
+        "timeout1": "Limit czasu połączenia z serwerem zdalnym",
+        "timeout2": "Limit czasu połączenia z serwerem lokalnym",
+        "validate_save": "Zatwierdź i zapisz",
+        "pushover_info": "Ustawienia powiadomień push będą miały zastosowanie do wszystkich czystych (niespamowych) wiadomości dostarczanych do <b>%s</b>, w tym aliasów (współdzielonych, niewspółdzielonych, oznaczonych)",
+        "mailbox_quota_def": "Domyślny limit skrzynki pocztowej",
+        "mailbox_relayhost_info": "Dotyczy wyłącznie skrzynki pocztowej i bezpośrednich aliasów, nadpisuje ustawienie serwera pośredniczącego (relayhost) dla domeny.",
+        "maxbytespersecond": "Max. Ilość bajtów na sekundę <br><small>(0 = unlimited)</small>",
+        "mailbox_rename": "Zmień nazwę skrzynki pocztowej",
+        "mailbox_rename_agree": "Stworzyłem kopię zapasową.",
+        "mailbox_rename_warning": "WAŻNE! Utwórz kopię zapasową przed zmianą nazwy skrzynki pocztowej.",
+        "mailbox_rename_alias": "Tworzenie aliasów automatycznie",
+        "mailbox_rename_title": "Nowa nazwa lokalnej skrzynki pocztowej"
     },
     "footer": {
         "cancel": "Anuluj",
         "confirm_delete": "Potwierdź usunięcie",
         "delete_now": "Usuń teraz",
-        "delete_these_items": "Czy jesteś pewien, że chcesz usunąć następujące elementy?",
+        "delete_these_items": "Proszę potwierdzić zmiany w poniższym identyfikatorze obiektu",
         "loading": "Proszę czekać...",
-        "restart_now": "Uruchom ponownie teraz"
+        "restart_now": "Uruchom ponownie teraz",
+        "hibp_check": "Sprawdź w stosunku do haveibeenpwned.com",
+        "hibp_nok": "Dopasowano! To potencjalnie niebezpieczne hasło!",
+        "hibp_ok": "Nie znaleziono żadnego dopasowania.",
+        "nothing_selected": "Nic wybranego",
+        "restart_container": "Zresetuj kontener",
+        "restart_container_info": "<b>Ważne:</b> Łagodne ponowne uruchomienie może zająć trochę czasu — proszę poczekać na jego zakończenie.",
+        "restarting_container": "Ponowne uruchomienie kontenera, może to zająć trochę czasu"
     },
     "header": {
         "administration": "Administrowanie",
@@ -207,16 +706,40 @@
         "mailcow_config": "Konfiguracja",
         "quarantine": "Kwarantanna",
         "restart_sogo": "Uruchom ponownie SOGo",
-        "user_settings": "Ustawienia użytkownika"
+        "user_settings": "Ustawienia użytkownika",
+        "apps": "Aplikacje",
+        "debug": "Informacja",
+        "mailcow_system": "System",
+        "restart_netfilter": "Uruchom ponownie netfilter"
     },
     "info": {
-        "no_action": "Żadne działanie nie ma zastosowania"
+        "no_action": "Żadne działanie nie ma zastosowania",
+        "awaiting_tfa_confirmation": "Oczekiwanie na potwierdzenie TFA",
+        "session_expires": "Twoja sesja wygaśnie za około 15 sekund"
     },
     "login": {
         "delayed": "Logowanie zostało opóźnione o %s sekund.",
         "login": "Zaloguj się",
         "password": "Hasło",
-        "username": "Nazwa użytkownika"
+        "username": "Nazwa użytkownika",
+        "forgot_password": "Zapomniałeś hasła?",
+        "login_linkstext": "Login nieprawidłowy?",
+        "login_usertext": "Zaloguj się jako użytkownik",
+        "login_domainadmintext": "Zaloguj się jako administrator domeny",
+        "login_admintext": "Zaloguj się jako admin",
+        "other_logins": "lub zaloguj za pomocą",
+        "email": "Adres e-mail",
+        "back_to_mailcow": "Wróć do mailcow",
+        "fido2_webauthn": "Logowanie FIDO2/WebAuthn",
+        "invalid_pass_reset_token": "Token resetowania hasła jest nieprawidłowy lub wygasł.<br>Proszę poprosić o nowy link do resetowania hasła.",
+        "login_user": "Logowanie użytkownika",
+        "login_dadmin": "Logowanie administratora domeny",
+        "login_admin": "Login Administratora",
+        "mobileconfig_info": "Zaloguj się jako użytkownik skrzynki pocztowej, aby pobrać żądany profil połączenia Apple.",
+        "new_password": "Nowe hasło",
+        "new_password_confirm": "Potwierdź nowe hasło",
+        "reset_password": "Zresetuj hasło",
+        "request_reset_password": "Poproś o zmianę hasła"
     },
     "mailbox": {
         "action": "Działanie",
@@ -276,7 +799,48 @@
         "tls_enforce_out": "Uruchom TLS wychodzące",
         "toggle_all": "Zaznacz wszystkie",
         "username": "Nazwa użytkownika",
-        "weekly": "Co tydzień"
+        "weekly": "Co tydzień",
+        "add_alias_expand": "Rozszerz alias na domeny alias",
+        "add_bcc_entry": "Dodaj mapę BCC",
+        "add_filter": "Dodaj filtr",
+        "recipient_map_old_info": "Mapa odbiorcy (pierwotne miejsce docelowe) musi być prawidłowym adresem e-mail lub nazwą domeny.",
+        "recipient_maps": "Mapy odbiorców",
+        "relay_unknown": "Przekazuj nieznane skrzynki pocztowe",
+        "running": "Uruchomione",
+        "sender": "Nadawca",
+        "set_postfilter": "Oznacz jako postfilter",
+        "set_prefilter": "Oznacz jako prefilter",
+        "sieve_info": "Możesz przechowywać wiele filtrów dla każdego użytkownika, jednak w danym momencie aktywny może być tylko jeden prefilter i jeden postfilter<br>\nKażdy filtr będzie przetwarzany w opisanej kolejności. Ani błędny skrypt, ani polecenie „keep;” nie zatrzymają przetwarzania kolejnych skryptów.\nZmiany w globalnych skryptach Sieve spowodują ponowne uruchomienie usługi Dovecot.<br><br>\nGlobalny prefiltr Sieve • Prefilter • Skrypty użytkownika • Postfilter • Globalny postfilter Sieve",
+        "sieve_preset_1": "Odrzuć pocztę z prawdopodobnymi niebezpiecznymi typami plików",
+        "sieve_preset_2": "Zawsze zaznaczaj e-mail konkretnego nadawcy jako odczytane",
+        "sieve_preset_3": "Odrzuć po cichu, zatrzymaj cały proces sieve",
+        "sieve_preset_4": "Plik do INBOX, pomiń dalszy proces przez filtry sieve",
+        "sieve_preset_5": "Automatyczna odpowiedź (urlopowa)",
+        "sieve_preset_6": "Odrzuć pocztę z odpowiedzią",
+        "sieve_preset_7": "Przekierowanie wiadomości z możliwością zachowania lub usunięcia kopii",
+        "sieve_preset_8": "Przekieruj wiadomość e-mail od określonego nadawcy, oznacz jako odczytaną i posortuj do podfoldera",
+        "sieve_preset_header": "Zbacz przykładowe ustawienia poniżej. Więcej szczegółów znajdziesz w <a href=\"https://en.wikipedia.org/wiki/Sieve_(mail_filtering_language)\" target=\"_blank\">Wikipedii</a>.",
+        "sogo_visible": "Alias jest widoczny w SOGo",
+        "sogo_visible_n": "Ukryj alias w SOGo",
+        "sogo_visible_y": "Pokaż alias w SOGo",
+        "stats": "Statystyki",
+        "status": "Status",
+        "syncjob_check_log": "Sprawdź log",
+        "syncjob_last_run_result": "Wynik ostatniego uruchomienia",
+        "syncjob_EX_OK": "Sukces",
+        "syncjob_EXIT_CONNECTION_FAILURE": "Problem z połączeniem",
+        "syncjob_EXIT_TLS_FAILURE": "Problem z szyfrowanym połączeniem",
+        "syncjob_EXIT_AUTHENTICATION_FAILURE": "Problem uwierzytelniania",
+        "syncjob_EXIT_OVERQUOTA": "Docelowa skrzynka pocztowa przekroczyła limit pojemności",
+        "syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Nie można połączyć się ze zdalnym serwerem",
+        "syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Niewłaściwa nazwa użytkownika lub hasło",
+        "table_size": "Rozmiar tabeli",
+        "table_size_show_n": "Pokaż %s elementy",
+        "templates": "Szablony",
+        "template": "Szablon",
+        "tls_map_dest": "Miejsce docelowe",
+        "tls_map_dest_info": "Przykłady: example.org, .example.org, [mail.example.org]:25",
+        "tls_map_parameters": "Parametry"
     },
     "quarantine": {
         "action": "Działanie",
@@ -284,10 +848,40 @@
         "quarantine": "Kwarantanna",
         "quick_actions": "Szybkie działania",
         "remove": "Usuń",
-        "toggle_all": "Zaznacz wszystkie"
+        "toggle_all": "Zaznacz wszystkie",
+        "confirm_delete": "Potwierdź usunięcie tego elementu.",
+        "learn_spam_delete": "Zapamiętaj jako spam i usuwaj w przyszłości",
+        "quick_delete_link": "Otwórz szybki link do usuwania",
+        "refresh": "Odśwież",
+        "rejected": "Odrzucony",
+        "release": "Zwolnij",
+        "release_body": "Dołączyliśmy Twoją wiadomość jako plik eml do tej wiadomości.",
+        "release_subject": "Potencjalnie szkodliwa pozycja kwarantanny %s",
+        "show_item": "Pokaż element",
+        "spam": "Spam",
+        "spam_score": "Wskaźnik",
+        "subj": "Temat",
+        "table_size": "Rozmiar tabeli",
+        "table_size_show_n": "Pokaż %s elementy",
+        "text_from_html_content": "Zawartość (przekonwertowany HTML)",
+        "text_plain_content": "Zawartość (tekst zwykły)",
+        "type": "Typ"
     },
     "queue": {
-        "queue_manager": "Queue Manager"
+        "queue_manager": "Menedżer kolejki",
+        "delete": "Usuń wszystko",
+        "ays": "Potwierdź, że chcesz usunąć wszystkie elementy z bieżącej kolejki.",
+        "flush": "Opróżnij kolejkę wiadomości",
+        "info": "Kolejka poczty zawiera wszystkie wiadomości e-mail oczekujące na dostarczenie.\nJeśli wiadomość e-mail pozostaje w kolejce przez dłuższy czas, system automatycznie ją usuwa.<br>\nKomunikat błędu dla danej wiadomości zawiera informacje o przyczynie, dla której nie mogła zostać dostarczona.",
+        "legend": "Funkcje zarządzania kolejką poczty:",
+        "deliver_mail": "Dostarcz",
+        "deliver_mail_legend": "Próby ponownego dostarczenia wybranych wiadomości.",
+        "hold_mail": "Wstrzymane",
+        "hold_mail_legend": "Wstrzymuję wybrane maile. (Zapobiega dalszym próbom dostarczenia)",
+        "show_message": "Pokaż wiadomość",
+        "unban": "Usuń zablokowanie w kolejce",
+        "unhold_mail": "Zwolnij wiadomość",
+        "unhold_mail_legend": "Zwalnia wybrane wiadomości do dostarczenia (wymaga wcześniejszego wstrzymania)."
     },
     "start": {
         "help": "Pokaż/Ukryj panel pomocy",
@@ -298,7 +892,7 @@
         "alias_added": "Alias/y został/y dodany/e",
         "alias_domain_removed": "Usunięto alias domeny %s",
         "alias_modified": "Zapisano zmiany w aliasie/ach %s",
-        "alias_removed": "Usunięto alias %s ",
+        "alias_removed": "Usunięto alias %s",
         "aliasd_added": "Dodano alias domeny %s",
         "aliasd_modified": "Zapisano zmiany w aliasie domeny %s",
         "dkim_added": "Klucz DKIM został zapisany",
@@ -313,24 +907,85 @@
         "f2b_modified": "Zmiany w Fail2ban zostały zapisane",
         "forwarding_host_added": "Dodano hosta przekazującego %s",
         "forwarding_host_removed": "Usunięto hosta przekazującego %s",
-        "item_deleted": "",
-        "items_deleted": "Item %s successfully deleted",
+        "item_deleted": "Element %s skutecznie usunięte",
+        "items_deleted": "Elementy %s skutecznie usunięte",
         "mailbox_added": "Dodano skrzynkę %s",
         "mailbox_modified": "Zapisano zmiany w skrzynce %s",
         "mailbox_removed": "Usunięto skrzynkę %s",
         "object_modified": "Zapisano zmiany w obiekcie %s",
         "resource_added": "Dodano śródło %s",
         "resource_modified": "Zapisano zmiany w skrzynce %s",
-        "resource_removed": "Usunięto zasób %s"
+        "resource_removed": "Usunięto zasób %s",
+        "template_removed": "Szablon o identyfikatorze %s został usunięty.",
+        "tls_policy_map_entry_deleted": "Mapa polityki TLS o identyfikatorze %s została usunięta",
+        "tls_policy_map_entry_saved": "Wpis mapy polityki TLS \"%s\" został zapisany",
+        "ui_texts": "Zapisane zmiany w tekstach UI",
+        "upload_success": "Plik przesłany pomyślnie",
+        "verified_fido2_login": "Zweryfikowany login FIDO2",
+        "verified_totp_login": "Zweryfikowany login TOTP",
+        "verified_webauthn_login": "Zweryfikowany login WebAuthn",
+        "verified_yotp_login": "Zweryfikowany login Yubico OTP",
+        "acl_saved": "ACL dla obiektu %s zapisany",
+        "admin_added": "Administrator %s został dodany",
+        "admin_api_modified": "Zmiany w API zostały zapisane",
+        "admin_removed": "Administrator %s został usunięty",
+        "app_links": "Zapisane zmiany w linkach aplikacji",
+        "app_passwd_added": "Dodano nowe hasło aplikacji",
+        "app_passwd_removed": "Usunięto ID hasła aplikacji %s",
+        "bcc_deleted": "Wpisy map BCC usunięte: %s",
+        "bcc_edited": "Wpis mapy BCC %s edytowany",
+        "bcc_saved": "Wpis mapy BCC zapisany",
+        "cors_headers_edited": "Ustawienia CORS zostały zapisane",
+        "custom_login_modified": "Dostosowanie logowania zostało pomyślnie zapisane",
+        "db_init_complete": "Inicjalizacja bazy danych zakończona",
+        "delete_filter": "Filtry %s ID usunięte",
+        "delete_filters": "Usunięte filtry: %s",
+        "deleted_syncjob": "Usunięte syncjob ID %s",
+        "deleted_syncjobs": "Usunięte syncjobs: %s”.",
+        "domain_add_dkim_available": "Klucz DKIM już istniał",
+        "dkim_duplicated": "Klucz DKIM dla domeny %s został skopiowany do %s",
+        "domain_footer_modified": "Zmiany w stopce domeny %s zostały zapisane",
+        "dovecot_restart_success": "Dovecot został pomyślnie zrestartowany",
+        "f2b_banlist_refreshed": "ID listy banów został pomyślnie odświeżony.",
+        "global_filter_written": "Filtr został pomyślnie zapisany do pliku",
+        "hash_deleted": "Hash usunięty",
+        "iam_test_connection": "Połączenie powiodło się",
+        "ip_check_opt_in_modified": "Sprawdzenie adresu IP zostało pomyślnie zapisane",
+        "item_released": "Pozycja %s zwolniona",
+        "items_released": "Wybrane elementy zostały zwolnione",
+        "learned_ham": "Pomyślnie nauczono ID %s jako ham",
+        "license_modified": "Zmiany w licencji zostały zapisane",
+        "logged_in_as": "Zalogowany jako %s",
+        "mailbox_renamed": "Nazwa skrzynki pocztowej została zmieniona z %s na %s",
+        "nginx_reloaded": "Nginx został przeładowany",
+        "password_policy_saved": "Polityka haseł została pomyślnie zapisana",
+        "password_changed_success": "Hasło zostało pomyślnie zmienione",
+        "pushover_settings_edited": "Ustawienia Pushover pomyślnie ustawione, proszę zweryfikować dane uwierzytelniające.",
+        "qlearn_spam": "Identyfikator wiadomości %s został nauczony jako spam i usunięty",
+        "queue_command_success": "Polecenie kolejki zostało pomyślnie wykonane",
+        "recipient_map_entry_deleted": "Id mapy odbiorcy %s został usunięty",
+        "recipient_map_entry_saved": "Wpis mapy odbiorcy \"%s\" został zapisany",
+        "recovery_email_sent": "E-mail do odzyskiwania wysłany do %s",
+        "relayhost_added": "Wpis mapy %s został dodany",
+        "relayhost_removed": "Wpis mapy %s został usunięty",
+        "reset_main_logo": "Reset do domyślnego logo",
+        "rl_saved": "Limit szybkości dla obiektu %s został zapisany",
+        "rspamd_ui_pw_set": "Hasło do Rspamd UI pomyślnie ustawione",
+        "saved_settings": "Zapisane ustawienia",
+        "settings_map_added": "Dodano ustawienia (wpis mapy)",
+        "settings_map_removed": "Usunięte ustawienia mapy ID %s",
+        "sogo_profile_reset": "Profil SOGo dla użytkownika/ów został zresetowany",
+        "template_added": "Dodano szablon",
+        "template_modified": "Zmiany w szablonie/ach zostały zapisane"
     },
     "tfa": {
-        "api_register": "%s używa Yubico Cloud API. Proszę pobrać klucz API dla Twojego klucza <a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">here</a>",
+        "api_register": "%s używa Yubico Cloud API. Proszę pobrać klucz API dla Twojego klucza <a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">tutaj</a>",
         "confirm": "Potwierdź",
         "confirm_totp_token": "Potwierdź zmiany przez wprowadzenie wygenerowanego tokenu",
         "delete_tfa": "Wyłącz TFA",
         "disable_tfa": "Wyłącz TFA do kolejnego udanego logowania",
         "enter_qr_code": "Twój kod TOTP, jeśli Twoje urządzenie nie skanuje kodów QR.",
-        "key_id": "Identyfikator dla Twojego YubiKey",
+        "key_id": "Identyfikator dla twojego urządzenia",
         "key_id_totp": "Identyfikator dla Twojego klucza",
         "none": "Deaktywuj",
         "scan_qr_code": "Zeskanuj następujący kod aplikacją uwierzytelniającą lub wprowadź kod ręcznie.",
@@ -340,8 +995,16 @@
         "totp": "Time-based OTP (Google Authenticator itd.)",
         "webauthn": "Uwierzytelnianie WebAuthn",
         "waiting_usb_auth": "<i>Czekam na urządzenie USB...</i><br><br>Wciśnij teraz przycisk na urządzeniu WebAuthn USB.",
-        "waiting_usb_register": "<i> Czekam na urządzenie USB...</i><br><br>Wprowadź swoje  hasło powyżej i potwierdź rejestrację WebAuthn przez naciśnięcie przycisku na urządzeniu WebAuthn USB.",
-        "yubi_otp": "Uwierzytelnianie Yubico OTP"
+        "waiting_usb_register": "<i> Czekam na urządzenie USB...</i><br><br>Wprowadź swoje hasło powyżej i potwierdź rejestrację przez naciśnięcie przycisku na urządzeniu USB.",
+        "yubi_otp": "Uwierzytelnianie Yubico OTP",
+        "authenticators": "Uwierzytelniacze",
+        "error_code": "Kod błędu",
+        "init_webauthn": "Inicjalizacja, proszę czekać...",
+        "reload_retry": "- (przeładuj przeglądarkę, jeśli błąd nadal występuje)",
+        "start_webauthn_validation": "Rozpocznij walidację",
+        "tfa_token_invalid": "Token TFA nieprawidłowy",
+        "u2f_deprecated": "Wygląda na to, że Twój klucz został zarejestrowany przy użyciu przestarzałej metody U2F. Dezaktywujemy dla Ciebie uwierzytelnianie dwuskładnikowe i usuniemy Twój klucz.",
+        "u2f_deprecated_important": "Zarejestruj swój klucz w panelu administracyjnym za pomocą nowej metody WebAuthn."
     },
     "user": {
         "action": "Działanie",
@@ -371,7 +1034,7 @@
         "edit": "Edytuj",
         "encryption": "Szyfrowanie",
         "excludes": "Wyłączenia",
-        "force_pw_update": "<b>Musisz</b> zmienić hasło, aby używać webmaila.",
+        "force_pw_update": "<b>Musisz</b> ustawić nowe hasło, aby mieć dostęp do usług groupware.",
         "hour": "Godzina",
         "hourly": "Co godzinę",
         "hours": "Godziny",
@@ -379,7 +1042,7 @@
         "interval": "Zakres",
         "is_catch_all": "Funkcja catch-all dla domen/y",
         "last_run": "Ostatnie uruchomienie",
-        "mailbox_details": " Szczegóły skrzynki",
+        "mailbox_details": "Szczegóły",
         "messages": "wiadomości",
         "never": "Nigdy",
         "new_password": "Nowe hasło",
@@ -391,17 +1054,17 @@
         "remove": "Usuń",
         "save_changes": "Zapisz zmiany",
         "shared_aliases": "Aliasy współdzielone",
-        "shared_aliases_desc": "Na aliasy współdzielone nie wpływają filtry spamu i ustawienia TLS.",
-        "show_sieve_filters": "Twój filtr sieve",
-        "sogo_profile_reset": "Usuń profil SOGo (webmail)",
-        "sogo_profile_reset_help": "To usunie ustawienia SOGo <b>bezpowrotnie</b>.",
-        "sogo_profile_reset_now": "Usuń profil teraz",
-        "spam_aliases": "Tymczasowy alias email",
+        "shared_aliases_desc": "Współdzielone aliasy nie są objęte ustawieniami specyficznymi dla użytkownika, takimi jak filtr antyspamowy czy polityka szyfrowania.\nOdpowiadające im filtry antyspamowe mogą być tworzone wyłącznie przez administratora — jako polityki obowiązujące dla całej domeny.",
+        "show_sieve_filters": "Pokaż filtr sieve aktywnego użytkownika",
+        "sogo_profile_reset": "Zresetuj profil SOGo",
+        "sogo_profile_reset_help": "Spowoduje to usunięcie profilu użytkownika SOGo oraz bezpowrotne <b>usunięcie wszystkich danych kontaktów i kalendarza.</b>",
+        "sogo_profile_reset_now": "Zresetuj profil teraz",
+        "spam_aliases": "Tymczasowe aliasy email",
         "spamfilter": "Filtr spamu",
-        "spamfilter_behavior": "Rating",
+        "spamfilter_behavior": "Ocena",
         "spamfilter_bl": "Czarna lista",
-        "spamfilter_bl_desc": "Adresy email z czarnej listy <b>zawsze</b> klasyfikuj jako spam i odrzucaj. Można użyć wildcards.",
-        "spamfilter_default_score": "Wartości domyślne:",
+        "spamfilter_bl_desc": "Adresy e-mail znajdujące się na liście zablokowanych (denylist) są <b>zawsze</b>klasyfikowane jako spam i odrzucane.\nOdrzucone wiadomości <b>nie są</b>kopiowane do kwarantanny.\nMożna używać symboli wieloznacznych (wildcardów).\nFiltr jest stosowany wyłącznie do bezpośrednich aliasów (aliasów kierujących do jednej skrzynki pocztowej), z wyłączeniem aliasów typu „catch-all” oraz samej skrzynki.",
+        "spamfilter_default_score": "Wartości domyślne",
         "spamfilter_green": "Zielony: ta wiadomość nie jest spamem",
         "spamfilter_hint": "Pierwsza wartość oznacza \"niską punktację spam\", druga wartość oznacza \"wysoką punktację spam\".",
         "spamfilter_red": "Czerwony: ta wiadomość jest spamem i zostanie odrzucona przez serwer",
@@ -412,13 +1075,13 @@
         "spamfilter_table_remove": "Usuń",
         "spamfilter_table_rule": "Zasada",
         "spamfilter_wl": "Biała lista",
-        "spamfilter_wl_desc": "Adresy email z białej listy <b>nigdy</b> nie klasyfikuj jako spam. Można użyć wildcards.",
+        "spamfilter_wl_desc": "Adresy e-mail znajdujące się na liście dozwolonych (allowlist) są zaprogramowane tak, aby <b> nigdy nie </b> były klasyfikowane jako spam.\nMożna używać symboli wieloznacznych (wildcardów).\nFiltr jest stosowany wyłącznie do bezpośrednich aliasów (aliasów wskazujących na jedną skrzynkę pocztową), z wyłączeniem aliasów typu „catch-all” oraz samej skrzynki pocztowej",
         "spamfilter_yellow": "Żółty: ta wiadomość może być spamem, zostanie oznaczona jako spam i przeniesiona do folderu spam",
-        "sync_jobs": "Polecenie synchronizacji",
+        "sync_jobs": "Zadania synchronizacji",
         "tag_handling": "Ustaw obsługę znaczników pocztowych",
         "tag_help_example": "Przykład adresu email z etykietą: ja<b>+Facebook</b>@example.org",
         "tag_help_explain": "W podfolderze: tworzy nowy podfolder z nazwą taką jak etykieta, który zostanie umieszczony pod Skrzynką odbiorczą (\"Skrzynka odbiorcza/Facebook\").<br>\r\nW temacie: nazwy etykiet zostaną dodane na początku tematów wiadomości, np.: \"[Facebook] Moje wiadomości\".",
-        "tag_in_none": "Nic nie robić",
+        "tag_in_none": "Nie wykonuj żadnej akcji",
         "tag_in_subfolder": "W podfolderze",
         "tag_in_subject": "W temacie",
         "tls_enforce_in": "Uruchom TLS przychodzące",
@@ -429,6 +1092,198 @@
         "username": "Nazwa użytkownika",
         "week": "Tydzień",
         "weekly": "Co tydzień",
-        "weeks": "Tygodnie"
+        "weeks": "Tygodnie",
+        "q_add_header": "Spam",
+        "advanced_settings": "Ustawienia zaawansowane",
+        "app_hint": "Hasła aplikacji są alternatywnymi hasłami dla logowania IMAP, SMTP, CalDAV, CardDAV i EAS. Nazwa użytkownika pozostaje niezmieniona. Webmail SOGo nie jest dostępny za pośrednictwem haseł aplikacji.",
+        "allowed_protocols": "Dozwolone protokoły",
+        "app_name": "Nazwa aplikacji",
+        "app_passwds": "Hasła do aplikacji",
+        "apple_connection_profile": "Profil połączenia Apple",
+        "apple_connection_profile_complete": "Ten profil połączenia obejmuje parametry IMAP i SMTP, a także ścieżki CalDAV (kalendarze) i CardDAV (kontakty) dla urządzenia Apple.",
+        "apple_connection_profile_mailonly": "Ten profil połączenia zawiera parametry konfiguracji IMAP i SMTP dla urządzenia Apple.",
+        "apple_connection_profile_with_app_password": "Nowe hasło aplikacji jest generowane i dodawane do profilu, dzięki czemu nie trzeba wprowadzać hasła podczas konfigurowania urządzenia. Proszę nie udostępniaj tego pliku, ponieważ zapewnia on pełny dostęp do skrzynki pocztowej.",
+        "attribute": "Atrybut",
+        "authentication": "Uwierzytelnianie",
+        "change_password_hint_app_passwords": "Twoje konto ma %d hasła aplikacji, które nie zostaną zmienione. Aby nimi zarządzać, przejdź do zakładki Hasła aplikacji.",
+        "clear_recent_successful_connections": "Wyczyść udane połączenia",
+        "create_app_passwd": "Stwórz hasło do aplikacji",
+        "created_on": "Stworzony na",
+        "delete_ays": "Proszę o potwierdzenie procesu usuwania.",
+        "direct_protocol_access": "Ten użytkownik skrzynki pocztowej ma <b>bezpośredni, zewnętrzny dostęp</b> do następujących protokołów i aplikacji. To ustawienie jest kontrolowane przez administratora. Można tworzyć hasła aplikacji, aby przyznać dostęp do poszczególnych protokołów i aplikacji.Przycisk „Webmail” umożliwia jednokrotne logowanie (SSO) do SOGo i jest zawsze dostępny.",
+        "email": "Email",
+        "email_and_dav": "E-maile, kalendarze i kontakty",
+        "empty": "Brak wyników",
+        "expire_in": "wygasa w",
+        "fido2_webauthn": "FIDO2/WebAuthn (standard uwierzytelniania)",
+        "from": "od",
+        "generate": "generuj",
+        "last_mail_login": "Ostatni login na skrzynkę pocztową",
+        "last_pw_change": "Ostatnia zmiana hasła",
+        "last_ui_login": "Ostatni login UI",
+        "loading": "Ładowanie...",
+        "login_history": "Historia logowania",
+        "mailbox": "Skrzynka pocztowa",
+        "mailbox_general": "Ogólne ustawienia skrzynki",
+        "mailbox_settings": "Ustawienia",
+        "month": "miesiąc",
+        "months": "miesiące",
+        "no_last_login": "Brak ostatnich danych logowania do interfejsu użytkownika",
+        "open_logs": "Otwórz logi użytkownika",
+        "open_webmail_sso": "­Webmail",
+        "overview": "Przegląd",
+        "password": "Hasło",
+        "password_repeat": "Hasło (powtórz)",
+        "password_reset_info": "Jeśli nie ma wiadomości e-mail do odzyskiwania hasła, ta funkcja nie może być używana.",
+        "protocols": "Protokoły",
+        "pushover_evaluate_x_prio": "Eskaluj wiadomości o wysokim priorytecie [<code>X-Priority: 1</code>]",
+        "pushover_info": "Ustawienia powiadomień push będą stosowane do wszystkich czystych (niebędących spamem) wiadomości dostarczonych do <b>%s</b>, w tym aliasów (współdzielonych, niewspółdzielonych i oznaczonych).",
+        "pushover_only_x_prio": "Uwzględniaj tylko wiadomości o wysokim priorytecie [<code>X-Priority: 1</code>]",
+        "pushover_sender_array": "Uwzględnij następujące adresy e-mail nadawców <small>(oddzielone przecinkami)</small>",
+        "pushover_sender_regex": "Dopasuj nadawców według następującego regexu",
+        "pushover_text": "Tekst powiadomienia",
+        "pushover_title": "Tytuł powiadomienia",
+        "pushover_sound": "Dźwięk powiadomienia",
+        "pushover_vars": "Jeśli nie zdefiniowano filtra nadawcy, wszystkie wiadomości będą brane pod uwagę.<br>Filtry regex oraz dokładne sprawdzanie nadawców można definiować indywidualnie – są one przetwarzane kolejno i nie zależą od siebie.</br>Dostępne zmienne dla treści i tytułu (prosimy pamiętać o zasadach ochrony danych osobowych).",
+        "pushover_verify": "Zweryfikuj dane logowania",
+        "pw_recovery_email": "E-mail do odzyskiwania hasła",
+        "q_all": "Wszystkie kategorie",
+        "q_reject": "Odrzucono",
+        "quarantine_category": "Kategoria powiadomień o kwarantannie",
+        "quarantine_category_info": "Kategoria powiadomień „Odrzucone” obejmuje wiadomości, które zostały odrzucone, natomiast „Folder spam” powiadamia użytkownika o wiadomościach umieszczonych w folderze spam.",
+        "quarantine_notification_info": "Po wysłaniu powiadomienia elementy zostaną oznaczone jako „powiadomione” i żadne kolejne powiadomienia nie zostaną wysłane dla danego elementu.",
+        "recent_successful_connections": "Zarejestrowano udane połączenia",
+        "running": "Uruchomiony",
+        "save": "Zapisz zmiany",
+        "sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Sprawdzenie nadawcy jest wyłączone</span>",
+        "spam_score_reset": "Przywróć domyślne ustawienia serwera",
+        "status": "Status",
+        "syncjob_check_log": "Sprawdź log",
+        "syncjob_last_run_result": "Wynik ostatniego uruchomienia",
+        "syncjob_EX_OK": "Sukces",
+        "syncjob_EXIT_CONNECTION_FAILURE": "Problem z połączeniem",
+        "syncjob_EXIT_TLS_FAILURE": "Problem z szyfrowanym połączeniem",
+        "syncjob_EXIT_AUTHENTICATION_FAILURE": "Problem uwierzytelniania",
+        "syncjob_EXIT_OVERQUOTA": "Docelowa skrzynka pocztowa przekroczyła limit pojemności",
+        "syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Nie można połączyć się ze zdalnym serwerem",
+        "syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Niewłaściwa nazwa użytkownika lub hasło",
+        "text": "Tekst",
+        "tfa_info": "Uwierzytelnianie dwuskładnikowe pomaga chronić Twoje konto. Jeśli je włączysz, będziesz potrzebować haseł aplikacji, aby logować się do programów lub usług, które nie obsługują uwierzytelniania dwuskładnikowego (np. klientów poczty).",
+        "title": "Tytuł",
+        "value": "Wartość",
+        "verify": "Zweryfikuj",
+        "waiting": "Oczekuje",
+        "with_app_password": "z hasłem aplikacji",
+        "year": "rok",
+        "years": "lata"
+    },
+    "warning": {
+        "session_ua": "Nieprawidłowy token formularza: Błąd walidacji User-Agent",
+        "cannot_delete_self": "Nie można usunąć zalogowanego użytkownika",
+        "domain_added_sogo_failed": "Dodano domenę, ale nie udało się ponownie uruchomić SOGo, sprawdź logi serwera.",
+        "dovecot_restart_failed": "Nie udało się ponownie uruchomić Dovecota, sprawdź logi",
+        "fuzzy_learn_error": "Błąd uczenia fuzzy hash: %s",
+        "hash_not_found": "Hash nie został odnaleziony lub został już usunięty",
+        "ip_invalid": "Pominięto nieprawidłowe IP: %s",
+        "is_not_primary_alias": "Pominięto alias niebędący głównym: %s",
+        "no_active_admin": "Nie można dezaktywować ostatniego aktywnego administratora",
+        "quota_exceeded_scope": "Przekroczono limit pojemności domeny: w tym zakresie domeny można tworzyć tylko skrzynki o nieograniczonej pojemności.",
+        "session_token": "Nieprawidłowy token formularza: niedopasowanie tokenów"
+    },
+    "datatables": {
+        "collapse_all": "Zwiń wszystko",
+        "decimal": ".",
+        "emptyTable": "Brak danych w tabeli",
+        "expand_all": "Rozszerz wszystko",
+        "info": "Wyświetlanie od START do END z TOTAL wpisów",
+        "infoEmpty": "Wyświetlanie od 0 do 0 z 0 wpisów",
+        "infoFiltered": "(filtrowane z _MAX_ suma wpisów)",
+        "thousands": ",",
+        "lengthMenu": "Pokaż wpisy _MENU_",
+        "loadingRecords": "Ładowanie...",
+        "processing": "Proszę czekać...",
+        "search": "Szukaj:",
+        "zeroRecords": "Nie znaleziono pasujących rekordów",
+        "paginate": {
+            "first": "Pierwszy",
+            "last": "Ostatni",
+            "next": "Następny",
+            "previous": "Poprzedni"
+        },
+        "aria": {
+            "sortAscending": "Aktywuj, aby posortować kolumnę rosnąco",
+            "sortDescending": "Aktywuj, aby posortować kolumnę malejąco"
+        }
+    },
+    "debug": {
+        "architecture": "Architektura",
+        "chart_this_server": "Wykres (ten serwer)",
+        "containers_info": "Informacje o kontenerze",
+        "container_running": "uruchomiony",
+        "container_disabled": "Kontener zatrzymany lub wyłączony",
+        "container_stopped": "Zatrzymany",
+        "cores": "rdzenie",
+        "current_time": "Czas systemowy",
+        "disk_usage": "Użycie dysku",
+        "docs": "Dokumentacja",
+        "error_show_ip": "Nie można ustalić publicznych adresów IP",
+        "external_logs": "Logi zewnętrzne",
+        "history_all_servers": "Historia (wszystkie serwery)",
+        "in_memory_logs": "Logi w pamięci",
+        "last_modified": "Ostatnia modyfikacja",
+        "log_info": "<p>mailcow <b>logi w pamięci</b> są gromadzone na listach Redis i przycinane do wartości <code>LOG_LINES</code> (%d) co minutę, aby ograniczyć nadmierne obciążenie systemu.</p> <p>Logi w pamięci nie są przeznaczone do trwałego przechowywania. Wszystkie aplikacje, które zapisują logi w pamięci, wysyłają je również do daemon Dockera, a więc do domyślnego sterownika logowania.</p> <p>Ten typ logów należy wykorzystywać do <b>debugowania drobnych problemów z kontenerami</b>.</p> <p><b>Logi zewnętrzne</b> są zbierane za pośrednictwem API danej aplikacji.</p> <p><b>Logi statyczne</b> to głównie dzienniki aktywności, które nie są zapisywane przez Dockerd, ale powinny być trwałe (z wyjątkiem logów API).</p>",
+        "login_time": "Czas",
+        "logs": "Logi",
+        "memory": "Pamięć",
+        "online_users": "Użytkownik online",
+        "restart_container": "Restart",
+        "service": "Usługa",
+        "show_ip": "Pokaż publiczne IP",
+        "size": "Rozmiar",
+        "started_at": "Zaczęło się od",
+        "started_on": "Zaczęło się od",
+        "static_logs": "Logi statyczne",
+        "success": "Sukces",
+        "system_containers": "System i kontenery",
+        "timezone": "Strefa czasowa",
+        "uptime": "Czas pracy",
+        "update_available": "Dostępna jest aktualizacja",
+        "no_update_available": "System jest w najnowszej wersji",
+        "update_failed": "Nie można było sprawdzić aktualizacji",
+        "username": "Nazwa użytkownika",
+        "wip": "Obecnie praca w toku"
+    },
+    "diagnostics": {
+        "cname_from_a": "Wartość pochodzi z rekordu A/AAAA. Obsługiwane, o ile rekord wskazuje na prawidłowy zasób.",
+        "dns_records": "Rekordy DNS",
+        "dns_records_24hours": "Pamiętaj, że zmiany wprowadzone w DNS mogą zająć nawet do 24 godzin, zanim ich aktualny stan zostanie poprawnie odzwierciedlony na tej stronie.\nTa sekcja ma na celu ułatwienie Ci konfiguracji rekordów DNS oraz sprawdzenie, czy wszystkie rekordy zostały prawidłowo zapisane w DNS.",
+        "dns_records_data": "Poprawne dane",
+        "dns_records_docs": "Proszę skonsultuj również <a target=\"_blank\" href=\"https://docs.mailcow.email/getstarted/prerequisite-dns\">dokumnetację</a>.",
+        "dns_records_name": "Nazwa",
+        "dns_records_status": "Aktualny stan",
+        "dns_records_type": "Typ",
+        "optional": "Ten rekord jest opcjonalny."
+    },
+    "fido2": {
+        "confirm": "Potwierdź",
+        "fido2_auth": "Logowanie za pomocą FIDO2",
+        "fido2_success": "Urządzenie pomyślnie zarejestrowane",
+        "fido2_validation_failed": "Walidacja nie powiodła się",
+        "fn": "Przyjazna nazwa FIDO",
+        "known_ids": "Znane Id",
+        "none": "Wyłączony",
+        "register_status": "Status rejestracji",
+        "rename": "Zmień nazwę",
+        "set_fido2": "Zarejestruj urządzenie FIDO2",
+        "set_fido2_touchid": "Zarejestruj Touch ID w Apple M1",
+        "set_fn": "Ustaw przyjazną nazwę w FIDO",
+        "start_fido2_validation": "Rozpocznij walidację FIDO2"
+    },
+    "ratelimit": {
+        "disabled": "Wyłączone",
+        "second": "wiadomości / sekundę",
+        "minute": "wiadomości / minutę",
+        "hour": "wiadomości / godzinę",
+        "day": "wiadomości/ dzień"
     }
 }

+ 31 - 7
data/web/lang/lang.ru-ru.json

@@ -109,7 +109,9 @@
         "timeout2": "Тайм-аут для подключения к локальному хосту",
         "username": "Имя пользователя",
         "validate": "Проверить",
-        "validation_success": "Проверка прошла успешно"
+        "validation_success": "Проверка прошла успешно",
+        "internal": "Внутренний",
+        "internal_info": "Внутренние псевдонимы доступны только из самого домена или доменов-псевдонимов."
     },
     "admin": {
         "access": "Настройки доступа",
@@ -550,7 +552,11 @@
         "generic_server_error": "На сервере произошла непредвиденная ошибка. Пожалуйста, свяжитесь с вашим администратором.",
         "authsource_in_use": "Поставщик идентификационных данных не может быть изменен или удален, так как в данный момент он используется одним или несколькими пользователями.",
         "iam_test_connection": "Ошибка соединения",
-        "required_data_missing": "Отсутствуют необходимые данные %s"
+        "required_data_missing": "Отсутствуют необходимые данные %s",
+        "max_age_invalid": "Максимальный возраст %s недействителен",
+        "mode_invalid": "Режим %s недействителен",
+        "mx_invalid": "Запись MX %s недействительна",
+        "version_invalid": "Версия %s недействительна"
     },
     "datatables": {
         "collapse_all": "Свернуть все",
@@ -762,7 +768,20 @@
         "title": "Изменение объекта",
         "unchanged_if_empty": "Если без изменений - оставьте пустым",
         "username": "Имя пользователя",
-        "validate_save": "Подтвердить и сохранить"
+        "validate_save": "Подтвердить и сохранить",
+        "internal": "Внутренний",
+        "internal_info": "Внутренние псевдонимы доступны только из самого домена или доменов-псевдонимов.",
+        "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> — это стандарт, который обязывает почтовые серверы использовать TLS с подлинными сертификатами для доставки электронной почты.<br>Он используется, когда <a target='_blank' href='https://ru.wikipedia.org/wiki/DANE'>DANE</a> невозможен из-за неиспользуемого или неподдерживаемого DNSSEC.<br><b>Примечание</b>: если принимающий домен поддерживает DANE с DNSSEC, <b>всегда</b> предпочитается DANE — MTA-STS действует только как резервный вариант.",
+        "mta_sts_version": "Версия",
+        "mta_sts_version_info": "Определяет версию стандарта MTA-STS – на данный момент существует только <code>STSv1</code>.",
+        "mta_sts_mode": "Режим",
+        "mta_sts_mode_info": "Есть три режима на выбор:<ul><li><em>testing</em> – политика только наблюдается, нарушения не имеют последствий.</li><li><em>enforce</em> – политика соблюдается строго, соединения без подлинного TLS отклоняются.</li><li><em>none</em> – политика опубликована, но не применяется.</li></ul>",
+        "mta_sts_max_age": "Максимальный возраст",
+        "mta_sts_max_age_info": "Время в секундах, в течение которого принимающие почтовые серверы могут кэшировать эту политику перед повторной загрузкой.",
+        "mta_sts_mx": "Сервер MX",
+        "mta_sts_mx_info": "Разрешает отправку только на явно указанные имена хостов почтовых серверов; отправляющий MTA проверяет, соответствует ли DNS-имя MX-хоста списку политик, и разрешает доставку только с подлинным TLS-сертификатом (защита от MITM).",
+        "mta_sts_mx_notice": "Можно указать несколько MX-серверов (через запятую)."
     },
     "fido2": {
         "confirm": "Подтвердить",
@@ -832,7 +851,8 @@
         "login_admintext": "Войти как администратор",
         "login_user": "Вход для пользователей",
         "login_dadmin": "Вход для администраторов домена",
-        "login_admin": "Вход для администраторов"
+        "login_admin": "Вход для администраторов",
+        "email": "Email-адрес"
     },
     "mailbox": {
         "action": "Действия",
@@ -1008,7 +1028,8 @@
         "waiting": "В ожидании",
         "weekly": "Раз в неделю",
         "yes": "&#10003;",
-        "iam": "Поставщик идентификационных данных"
+        "iam": "Поставщик идентификационных данных",
+        "internal": "Внутренний"
     },
     "oauth2": {
         "access_denied": "Пожалуйста, войдите в систему как владелец почтового аккаунта, чтобы получить доступ через OAuth2.",
@@ -1331,7 +1352,7 @@
         "sogo_profile_reset": "Сбросить профиль SOGo",
         "sogo_profile_reset_help": "<b>Внимание:</b> это удалит настройки профиля SOGo вместе с <b>всеми контактами, календарями и фильтрами безвозвратно</b>.",
         "sogo_profile_reset_now": "Сбросить профиль сейчас",
-        "spam_aliases": "Временные псевдонимы электронной почты",
+        "spam_aliases": "Псевдонимы для спама",
         "spam_score_reset": "Сброс на настройки по умолчанию",
         "spamfilter": "Спам фильтр",
         "spamfilter_behavior": "Фильтрация спама",
@@ -1387,7 +1408,10 @@
         "authentication": "Аутентификация",
         "tfa_info": "Двухфакторная аутентификация помогает защитить вашу учетную запись. Если вы включите эту функцию, вам понадобятся пароли приложений для входа в приложения или службы, которые не поддерживают двухфакторную аутентификацию (например, почтовые клиенты).",
         "protocols": "Протоколы",
-        "overview": "Обзор"
+        "overview": "Обзор",
+        "expire_never": "Никогда не истекает",
+        "forever": "Навсегда",
+        "spam_aliases_info": "Псевдоним для спама — это временный адрес электронной почты, который можно использовать для защиты реальных адресов.<br>При желании можно установить срок действия, по истечении которого псевдоним будет автоматически деактивирован, что позволяет эффективно избавляться от адресов, которые были использованы не по назначению или стали доступны посторонним лицам."
     },
     "warning": {
         "cannot_delete_self": "Вы не можете удалить сами себя",

+ 8 - 5
data/web/lang/lang.si-si.json

@@ -297,7 +297,7 @@
         "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 listo sivih. Prejeta neželena pošta s teh gostiteljev ni nikoli zavrnjena, 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.",
         "license_info": "Licenca ni zahtevana, a pomaga pri nadaljnjem razvoju. <br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"Naročilo SAL\">Registrirajte svoj GUID tukaj</a> ali <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Naročilo podpore\">Kupite podporo za svojo namestitev Mailcow.</a>",
-        "lookup_mx": "Cilj je regularni izraz, ki se ujema z imenom MX (<code>.*\\.google\\.com</code> za usmerjanje vse pošte, usmerjene na MX, ki se konča na google.com, prek tega skoka).",
+        "lookup_mx": "Cilj je regularni izraz, ki se ujema z imenom MX (<code>.*\\.google\\.com</code> za usmerjanje vse pošte, usmerjene na MX, ki se konča na google.com, prek tega skoka)",
         "main_name": "Naziv \"mailcow UI\"",
         "merged_vars_hint": "Sive vrstice so združene iz <code>vars.(local.)inc.php</code> in jih ni mogoče spremeniti.",
         "oauth2_info": "Implementacija OAuth2 podpira vrsto odobritve »Avtorizacijska koda« in izda osvežilne žetone.<br>\nStrežnik samodejno izda tudi nove osvežilne žetone, ko je žeton za osvežitev uporabljen.<br><br>\n&#8226; Privzeti obseg je <i>profile</i>. Prek OAuth2 je mogoče overiti samo uporabnike poštnega predala. Če parameter obsega izpustite, se vrne na <i>profile</i>.<br>\n&#8226; Parameter <i>state</i> mora odjemalec poslati kot del zahteve za avtorizacijo.<br><br>\nPoti za zahteve do API-ja OAuth2: <br>\n<ul>\n<li>Končna točka avtorizacije: <code>/oauth/authorize</code></li>\n<li>Končna točka žetona: <code>/oauth/token</code></li>\n<li>Stran z viri: <code>/oauth/profile</code></li>\n</ul>\nPonovno ustvarjanje skrivnosti odjemalca ne bo poteklo obstoječih kod za avtorizacijo, vendar ne bo obnovilo žetona.<br><br>\nPreklic žetonov odjemalca bo povzročil takojšnjo prekinitev vseh aktivnih sej. Vse stranke se morajo ponovno overiti.",
@@ -414,7 +414,7 @@
         "needs_restart": "potreben je ponovni zagon"
     },
     "danger": {
-        "alias_goto_identical": "Vzdevek in ciljni naslov se ne smeta ujemati.",
+        "alias_goto_identical": "Vzdevek in ciljni naslov se ne smeta ujemati",
         "aliasd_targetd_identical": "Vzdevek domene ne sme biti enak ciljni domeni: %s",
         "bcc_exists": "Za tip %s obstaja BCC preslikava %s",
         "dkim_domain_or_sel_exists": "DKIM ključ za \"%s\" obstaja in ne bo prepisan",
@@ -651,7 +651,7 @@
         "pushover_title": "Naslov obvestila",
         "domains": "Domene",
         "extended_sender_acl_info": "Uvoziti je treba ključ domene DKIM, če je na voljo.<br>\n  Ne pozabite dodati tega strežnika v ustrezni zapis SPF TXT.<br>\n  Kadar koli je temu strežniku dodana domena ali vzdevek domene, ki se prekriva z zunanjim naslovom, se zunanji naslov odstrani.<br>\n  Uporabite @domain.tld, da omogočite pošiljanje kot *@domain.tld.",
-        "lookup_mx": "Cilj je regularni izraz, ki se ujema z imenom MX (<code>.*\\.google\\.com</code> za usmerjanje vse pošte, usmerjene na MX, ki se konča na google.com, prek tega skoka).",
+        "lookup_mx": "Cilj je regularni izraz, ki se ujema z imenom MX (<code>.*\\.google\\.com</code> za usmerjanje vse pošte, usmerjene na MX, ki se konča na google.com, prek tega skoka)",
         "maxbytespersecond": "Največ bajtov na sekundo <br><small>(0 = neomejeno)</small>",
         "pushover_sender_array": "Upoštevaj samo sledeče e-poštne naslove pošiljateljev <small>(ločeni z vejico)</small>",
         "mbox_rl_info": "Ta omejitev se uporabi za prijavno ime SASL in se ujema z naslovom \"od\", ki ga uporablja prijavljeni uporabnik. Omejitev poštnega nabiralnika preglasi omejitev za celotno domeno.",
@@ -1359,7 +1359,7 @@
         "sogo_profile_reset": "Ponastavi profil SOGo",
         "sogo_profile_reset_help": "S tem boste uničili uporabnikov profil SOGo in <b>nepovratno izbrisali vse stike in podatke koledarja</b>.",
         "sogo_profile_reset_now": "Ponastavi profil zdaj",
-        "spam_aliases": "Začasni vzdevki e-pošte",
+        "spam_aliases": "Vzdevki neželene e-pošte",
         "spam_score_reset": "Ponastavi na privzete nastavitve strežnika",
         "spamfilter": "Filter neželene pošte",
         "spamfilter_behavior": "Ocena",
@@ -1407,7 +1407,10 @@
         "years": "leta",
         "waiting": "Čakanje",
         "q_all": "Vse kategorije",
-        "syncjob_EX_OK": "Uspeh"
+        "syncjob_EX_OK": "Uspeh",
+        "expire_never": "Nikoli ne poteče",
+        "forever": "Za vedno",
+        "spam_aliases_info": "Vzdevek za neželeno pošto je začasni e-poštni naslov, ki ga je mogoče uporabiti za zaščito pravih e-poštnih naslovov. <br>Po želji je mogoče nastaviti čas poteka veljavnosti, tako da se vzdevek po določenem obdobju samodejno deaktivira, s čimer se učinkovito znebite zlorabljenih ali razkritih naslovov."
     },
     "warning": {
         "cannot_delete_self": "Prijavljenega uporabnika ni mogoče izbrisati",

+ 2 - 1
data/web/lang/lang.vi-vn.json

@@ -691,6 +691,7 @@
         "internal": "Nội bộ",
         "internal_info": "Bí danh nội bộ chỉ có thể truy cập từ tên miền sở hữu hoặc tên miền bí danh.",
         "kind": "Loại",
-        "last_modified": "Sửa đổi lần cuối"
+        "last_modified": "Sửa đổi lần cuối",
+        "lookup_mx": "Đích là một biểu thức chính quy để khớp với tên MX (<code>.*.google.com</code> để định tuyến tất cả thư nhắm đến MX kết thúc bằng google.com qua bước nhảy này)"
     }
 }

+ 8 - 6
data/web/templates/user/SpamAliases.twig

@@ -8,6 +8,7 @@
     </div>
     <div id="collapse-tab-SpamAliases" class="card-body collapse" data-bs-parent="#user-content">
       <div class="row">
+        <p>{{ lang.user.spam_aliases_info|raw }}</p>
         <div class="col-md-12 col-sm-12 col-12">
           <table id="tla_table" class="table table-striped dt-responsive w-100"></table>
         </div>
@@ -18,12 +19,13 @@
             <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary" id="toggle_multi_select_all" data-id="tla" href="#"><i class="bi bi-check-all"></i> {{ lang.mailbox.toggle_all }}</a>
             <a class="btn btn-sm btn-xs-half d-block d-sm-inline btn-secondary dropdown-toggle" data-bs-toggle="dropdown" href="#">{{ lang.mailbox.quick_actions }}</a>
             <ul class="dropdown-menu">
-              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"1"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.hour }}</a></li>
-              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"24"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.day }}</a></li>
-              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"168"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.week }}</a></li>
-              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"744"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.month }}</a></li>
-              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"8760"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.year }}</a></li>
-              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"87600"}' href="#">{{ lang.user.expire_in }} 10 {{ lang.user.years }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"1","permanent":"0"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.hour }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"24","permanent":"0"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.day }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"168","permanent":"0"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.week }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"744","permanent":"0"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.month }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"8760","permanent":"0"}' href="#">{{ lang.user.expire_in }} 1 {{ lang.user.year }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"validity":"87600","permanent":"0"}' href="#">{{ lang.user.expire_in }} 10 {{ lang.user.years }}</a></li>
+              <li><a class="dropdown-item" data-action="edit_selected" data-id="tla" data-api-url='edit/time_limited_alias' data-api-attr='{"permanent":"1"}' href="#">{{ lang.user.expire_never }}</a></li>
               <li><hr class="dropdown-divider"></li>
               <li><a class="dropdown-item" data-action="delete_selected" data-id="tla" data-api-url='delete/time_limited_alias' href="#">{{ lang.mailbox.remove }}</a></li>
             </ul>

+ 20 - 20
docker-compose.yml

@@ -117,7 +117,7 @@ services:
             - rspamd
 
     php-fpm-mailcow:
-      image: ghcr.io/mailcow/phpfpm:1.94
+      image: ghcr.io/mailcow/phpfpm:8.2.29
       command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
       depends_on:
         - redis-mailcow
@@ -188,10 +188,10 @@ services:
       restart: always
       labels:
         ofelia.enabled: "true"
-        ofelia.job-exec.phpfpm_keycloak_sync.schedule: "@every 1m"
+        ofelia.job-exec.phpfpm_keycloak_sync.schedule: "0 * * * * *"
         ofelia.job-exec.phpfpm_keycloak_sync.no-overlap: "true"
         ofelia.job-exec.phpfpm_keycloak_sync.command: "/bin/bash -c \"php /crons/keycloak-sync.php || exit 0\""
-        ofelia.job-exec.phpfpm_ldap_sync.schedule: "@every 1m"
+        ofelia.job-exec.phpfpm_ldap_sync.schedule: "0 * * * * *"
         ofelia.job-exec.phpfpm_ldap_sync.no-overlap: "true"
         ofelia.job-exec.phpfpm_ldap_sync.command: "/bin/bash -c \"php /crons/ldap-sync.php || exit 0\""
       networks:
@@ -200,7 +200,7 @@ services:
             - phpfpm
 
     sogo-mailcow:
-      image: ghcr.io/mailcow/sogo:1.136
+      image: ghcr.io/mailcow/sogo:5.12.4
       environment:
         - DBNAME=${DBNAME}
         - DBUSER=${DBUSER}
@@ -236,13 +236,13 @@ services:
         - sogo-userdata-backup-vol-1:/sogo_backup
       labels:
         ofelia.enabled: "true"
-        ofelia.job-exec.sogo_sessions.schedule: "@every 1m"
+        ofelia.job-exec.sogo_sessions.schedule: "0 * * * * *"
         ofelia.job-exec.sogo_sessions.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool -v expire-sessions $${SOGO_EXPIRE_SESSION} || exit 0\""
-        ofelia.job-exec.sogo_ealarms.schedule: "@every 1m"
+        ofelia.job-exec.sogo_ealarms.schedule: "0 * * * * *"
         ofelia.job-exec.sogo_ealarms.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-ealarms-notify -p /etc/sogo/cron.creds || exit 0\""
-        ofelia.job-exec.sogo_eautoreply.schedule: "@every 5m"
-        ofelia.job-exec.sogo_eautoreply.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/cron.creds || exit 0\""
-        ofelia.job-exec.sogo_backup.schedule: "@every 24h"
+        ofelia.job-exec.sogo_eautoreply.schedule: "0 */5 * * * *"
+        ofelia.job-exec.sogo_eautoreply.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/sieve.creds || exit 0\""
+        ofelia.job-exec.sogo_backup.schedule: "0 0 0 * * *"
         ofelia.job-exec.sogo_backup.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu sogo /usr/sbin/sogo-tool backup /sogo_backup ALL || exit 0\""
       restart: always
       networks:
@@ -252,7 +252,7 @@ services:
             - sogo
 
     dovecot-mailcow:
-      image: ghcr.io/mailcow/dovecot:2.35
+      image: ghcr.io/mailcow/dovecot:2.3.21.1
       depends_on:
         - mysql-mailcow
         - netfilter-mailcow
@@ -310,22 +310,22 @@ services:
       tty: true
       labels:
         ofelia.enabled: "true"
-        ofelia.job-exec.dovecot_imapsync_runner.schedule: "@every 1m"
+        ofelia.job-exec.dovecot_imapsync_runner.schedule: "0 * * * * *"
         ofelia.job-exec.dovecot_imapsync_runner.no-overlap: "true"
         ofelia.job-exec.dovecot_imapsync_runner.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu nobody /usr/local/bin/imapsync_runner.pl || exit 0\""
-        ofelia.job-exec.dovecot_trim_logs.schedule: "@every 1m"
+        ofelia.job-exec.dovecot_trim_logs.schedule: "0 * * * * *"
         ofelia.job-exec.dovecot_trim_logs.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/trim_logs.sh || exit 0\""
-        ofelia.job-exec.dovecot_quarantine.schedule: "@every 20m"
+        ofelia.job-exec.dovecot_quarantine.schedule: "0 */20 * * * *"
         ofelia.job-exec.dovecot_quarantine.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/quarantine_notify.py || exit 0\""
-        ofelia.job-exec.dovecot_clean_q_aged.schedule: "@every 24h"
+        ofelia.job-exec.dovecot_clean_q_aged.schedule: "0 0 0 * * *"
         ofelia.job-exec.dovecot_clean_q_aged.command: "/bin/bash -c \"[[ $${MASTER} == y ]] && /usr/local/bin/gosu vmail /usr/local/bin/clean_q_aged.sh || exit 0\""
-        ofelia.job-exec.dovecot_maildir_gc.schedule: "@every 30m"
+        ofelia.job-exec.dovecot_maildir_gc.schedule: "0 */30 * * * *"
         ofelia.job-exec.dovecot_maildir_gc.command: "/bin/bash -c \"source /source_env.sh ; /usr/local/bin/gosu vmail /usr/local/bin/maildir_gc.sh\""
-        ofelia.job-exec.dovecot_sarules.schedule: "@every 24h"
+        ofelia.job-exec.dovecot_sarules.schedule: "0 0 0 * * *"
         ofelia.job-exec.dovecot_sarules.command: "/bin/bash -c \"/usr/local/bin/sa-rules.sh\""
-        ofelia.job-exec.dovecot_fts.schedule: "@every 24h"
+        ofelia.job-exec.dovecot_fts.schedule: "0 0 0 * * *"
         ofelia.job-exec.dovecot_fts.command: "/bin/bash -c \"/usr/local/bin/gosu vmail /usr/local/bin/optimize-fts.sh\""
-        ofelia.job-exec.dovecot_repl_health.schedule: "@every 5m"
+        ofelia.job-exec.dovecot_repl_health.schedule: "0 */5 * * * *"
         ofelia.job-exec.dovecot_repl_health.command: "/bin/bash -c \"/usr/local/bin/gosu vmail /usr/local/bin/repl_health.sh\""
       ulimits:
         nproc: 65535
@@ -339,7 +339,7 @@ services:
             - dovecot
 
     postfix-mailcow:
-      image: ghcr.io/mailcow/postfix:1.81
+      image: ghcr.io/mailcow/postfix:3.7.11
       depends_on:
         mysql-mailcow:
           condition: service_started
@@ -382,7 +382,7 @@ services:
             - postfix
 
     postfix-tlspol-mailcow:
-      image: ghcr.io/mailcow/postfix-tlspol:1.0
+      image: ghcr.io/mailcow/postfix-tlspol:1.8.22
       depends_on:
         unbound-mailcow:
           condition: service_healthy

+ 88 - 35
helper-scripts/backup_and_restore.sh

@@ -110,32 +110,32 @@ function backup() {
       docker run --name mailcow-backup --rm \
         -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
         -v $(docker volume ls -qf name=^${CMPS_PRJ}_vmail-vol-1$):/vmail:ro,z \
-        ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_vmail.tar.gz /vmail
+        ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="zstd --rsyncable -T${THREADS}" -Pcvpf /backup/backup_vmail.tar.zst /vmail
       ;;&
     crypt|all)
       docker run --name mailcow-backup --rm \
         -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
         -v $(docker volume ls -qf name=^${CMPS_PRJ}_crypt-vol-1$):/crypt:ro,z \
-        ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_crypt.tar.gz /crypt
+        ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="zstd --rsyncable -T${THREADS}" -Pcvpf /backup/backup_crypt.tar.zst /crypt
       ;;&
     redis|all)
       docker exec $(docker ps -qf name=redis-mailcow) redis-cli -a ${REDISPASS} --no-auth-warning save
       docker run --name mailcow-backup --rm \
         -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
         -v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:ro,z \
-        ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_redis.tar.gz /redis
+        ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="zstd --rsyncable -T${THREADS}" -Pcvpf /backup/backup_redis.tar.zst /redis
       ;;&
     rspamd|all)
       docker run --name mailcow-backup --rm \
         -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
         -v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:ro,z \
-        ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_rspamd.tar.gz /rspamd
+        ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="zstd --rsyncable -T${THREADS}" -Pcvpf /backup/backup_rspamd.tar.zst /rspamd
       ;;&
     postfix|all)
       docker run --name mailcow-backup --rm \
         -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
         -v $(docker volume ls -qf name=^${CMPS_PRJ}_postfix-vol-1$):/postfix:ro,z \
-        ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_postfix.tar.gz /postfix
+        ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="zstd --rsyncable -T${THREADS}" -Pcvpf /backup/backup_postfix.tar.zst /postfix
       ;;&
     mysql|all)
       SQLIMAGE=$(grep -iEo '(mysql|mariadb)\:.+' ${COMPOSE_FILE})
@@ -154,7 +154,7 @@ function backup() {
           ${SQLIMAGE} /bin/sh -c "mariabackup --host mysql --user root --password ${DBROOT} --backup --rsync --target-dir=/backup_mariadb ; \
           mariabackup --prepare --target-dir=/backup_mariadb ; \
           chown -R 999:999 /backup_mariadb ; \
-          /bin/tar --warning='no-file-ignored' --use-compress-program='gzip --rsyncable' -Pcvpf /backup/backup_mariadb.tar.gz /backup_mariadb ;"
+          /bin/tar --warning='no-file-ignored' --use-compress-program='zstd --rsyncable' -Pcvpf /backup/backup_mariadb.tar.zst /backup_mariadb ;"
       fi
       ;;&
     --delete-days)
@@ -170,6 +170,19 @@ function backup() {
   done
 }
 
+function get_archive_info() {
+  local backup_name="$1"
+  local location="$2"
+
+  if [[ -f "${location}/${backup_name}.tar.zst" ]]; then
+    echo "${backup_name}.tar.zst|zstd -d -T${THREADS}"
+  elif [[ -f "${location}/${backup_name}.tar.gz" ]]; then
+    echo "${backup_name}.tar.gz|pigz -d -p ${THREADS}"
+  else
+    echo ""
+  fi
+}
+
 function restore() {
   for bin in docker; do
   if [[ -z $(which ${bin}) ]]; then
@@ -199,10 +212,17 @@ function restore() {
     case "$1" in
     vmail)
       docker stop $(docker ps -qf name=dovecot-mailcow)
-      docker run -i --name mailcow-backup --rm \
-        -v ${RESTORE_LOCATION}:/backup:z \
-        -v $(docker volume ls -qf name=^${CMPS_PRJ}_vmail-vol-1$):/vmail:z \
-        ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_vmail.tar.gz
+      ARCHIVE_INFO=$(get_archive_info "backup_vmail" "${RESTORE_LOCATION}")
+      if [[ -z "${ARCHIVE_INFO}" ]]; then
+        echo -e "\e[31mError: No backup file found for vmail (searched for .tar.zst and .tar.gz)\e[0m"
+      else
+        ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
+        DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
+        docker run -i --name mailcow-backup --rm \
+          -v ${RESTORE_LOCATION}:/backup:z \
+          -v $(docker volume ls -qf name=^${CMPS_PRJ}_vmail-vol-1$):/vmail:z \
+          ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
+      fi
       docker start $(docker ps -aqf name=dovecot-mailcow)
       echo
       echo "In most cases it is not required to run a full resync, you can run the command printed below at any time after testing wether the restore process broke a mailbox:"
@@ -218,31 +238,50 @@ function restore() {
       ;;
     redis)
       docker stop $(docker ps -qf name=redis-mailcow)
-      docker run -i --name mailcow-backup --rm \
-        -v ${RESTORE_LOCATION}:/backup:z \
-        -v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:z \
-        ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_redis.tar.gz
+      ARCHIVE_INFO=$(get_archive_info "backup_redis" "${RESTORE_LOCATION}")
+      if [[ -z "${ARCHIVE_INFO}" ]]; then
+        echo -e "\e[31mError: No backup file found for redis (searched for .tar.zst and .tar.gz)\e[0m"
+      else
+        ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
+        DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
+        docker run -i --name mailcow-backup --rm \
+          -v ${RESTORE_LOCATION}:/backup:z \
+          -v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:z \
+          ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
+      fi
       docker start $(docker ps -aqf name=redis-mailcow)
       ;;
     crypt)
       docker stop $(docker ps -qf name=dovecot-mailcow)
-      docker run -i --name mailcow-backup --rm \
-        -v ${RESTORE_LOCATION}:/backup:z \
-        -v $(docker volume ls -qf name=^${CMPS_PRJ}_crypt-vol-1$):/crypt:z \
-        ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_crypt.tar.gz
+      ARCHIVE_INFO=$(get_archive_info "backup_crypt" "${RESTORE_LOCATION}")
+      if [[ -z "${ARCHIVE_INFO}" ]]; then
+        echo -e "\e[31mError: No backup file found for crypt (searched for .tar.zst and .tar.gz)\e[0m"
+      else
+        ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
+        DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
+        docker run -i --name mailcow-backup --rm \
+          -v ${RESTORE_LOCATION}:/backup:z \
+          -v $(docker volume ls -qf name=^${CMPS_PRJ}_crypt-vol-1$):/crypt:z \
+          ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
+      fi
       docker start $(docker ps -aqf name=dovecot-mailcow)
       ;;
     rspamd)
-      if [[ $(find "${RESTORE_LOCATION}" \( -name '*x86*' -o -name '*aarch*' \) -exec basename {} \; | sed 's/^\.//' | sed 's/^\.//') == "" ]]; then
+      ARCHIVE_INFO=$(get_archive_info "backup_rspamd" "${RESTORE_LOCATION}")
+      if [[ -z "${ARCHIVE_INFO}" ]]; then
+        echo -e "\e[31mError: No backup file found for rspamd (searched for .tar.zst and .tar.gz)\e[0m"
+      elif [[ $(find "${RESTORE_LOCATION}" \( -name '*x86*' -o -name '*aarch*' \) -exec basename {} \; | sed 's/^\.//' | sed 's/^\.//') == "" ]]; then
         echo -e "\e[33mCould not find a architecture signature of the loaded backup... Maybe the backup was done before the multiarch update?"
         sleep 2
         echo -e "Continuing anyhow. If rspamd is crashing upon boot try remove the rspamd volume with docker volume rm ${CMPS_PRJ}_rspamd-vol-1 after you've stopped the stack.\e[0m"
         sleep 2
         docker stop $(docker ps -qf name=rspamd-mailcow)
+        ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
+        DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
         docker run -i --name mailcow-backup --rm \
           -v ${RESTORE_LOCATION}:/backup:z \
           -v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:z \
-          ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_rspamd.tar.gz
+          ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
         docker start $(docker ps -aqf name=rspamd-mailcow)
       elif [[ $ARCH != $(find "${RESTORE_LOCATION}" \( -name '*x86*' -o -name '*aarch*' \) -exec basename {} \; | sed 's/^\.//' | sed 's/^\.//') ]]; then
         echo -e "\e[31mThe Architecture of the backed up mailcow OS is different then your restoring mailcow OS..."
@@ -250,19 +289,28 @@ function restore() {
         echo -e "Skipping rspamd due to compatibility issues!\e[0m"
       else
         docker stop $(docker ps -qf name=rspamd-mailcow)
+        ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
+        DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
         docker run -i --name mailcow-backup --rm \
           -v ${RESTORE_LOCATION}:/backup:z \
           -v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:z \
-          ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_rspamd.tar.gz
+          ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
         docker start $(docker ps -aqf name=rspamd-mailcow)
       fi
       ;;
     postfix)
       docker stop $(docker ps -qf name=postfix-mailcow)
-      docker run -i --name mailcow-backup --rm \
-        -v ${RESTORE_LOCATION}:/backup:z \
-        -v $(docker volume ls -qf name=^${CMPS_PRJ}_postfix-vol-1$):/postfix:z \
-        ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_postfix.tar.gz
+      ARCHIVE_INFO=$(get_archive_info "backup_postfix" "${RESTORE_LOCATION}")
+      if [[ -z "${ARCHIVE_INFO}" ]]; then
+        echo -e "\e[31mError: No backup file found for postfix (searched for .tar.zst and .tar.gz)\e[0m"
+      else
+        ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
+        DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
+        docker run -i --name mailcow-backup --rm \
+          -v ${RESTORE_LOCATION}:/backup:z \
+          -v $(docker volume ls -qf name=^${CMPS_PRJ}_postfix-vol-1$):/postfix:z \
+          ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="${DECOMPRESS_PROG}" -Pxvf /backup/${ARCHIVE_FILE}
+      fi
       docker start $(docker ps -aqf name=postfix-mailcow)
       ;;
     mysql|mariadb)
@@ -305,14 +353,19 @@ function restore() {
           echo Restoring... && \
           gunzip < backup/backup_mysql.gz | mysql -uroot && \
           mysql -uroot -e SHUTDOWN;"
-        elif [[ -f "${RESTORE_LOCATION}/backup_mariadb.tar.gz" ]]; then
-        docker run --name mailcow-backup --rm \
-          -v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/backup_mariadb/:rw,z \
-          --entrypoint= \
-          -v ${RESTORE_LOCATION}:/backup:z \
-          ${SQLIMAGE} /bin/bash -c "shopt -s dotglob ; \
-            /bin/rm -rf /backup_mariadb/* ; \
-            /bin/tar -Pxvzf /backup/backup_mariadb.tar.gz"
+        else
+          ARCHIVE_INFO=$(get_archive_info "backup_mariadb" "${RESTORE_LOCATION}")
+          if [[ -n "${ARCHIVE_INFO}" ]]; then
+            ARCHIVE_FILE=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f1)
+            DECOMPRESS_PROG=$(echo "${ARCHIVE_INFO}" | cut -d'|' -f2)
+            docker run --name mailcow-backup --rm \
+              -v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/backup_mariadb/:rw,z \
+              --entrypoint= \
+              -v ${RESTORE_LOCATION}:/backup:z \
+              ${SQLIMAGE} /bin/bash -c "shopt -s dotglob ; \
+                /bin/rm -rf /backup_mariadb/* ; \
+                /bin/tar --use-compress-program='${DECOMPRESS_PROG}' -Pxvf /backup/${ARCHIVE_FILE}"
+          fi
         fi
         echo "Modifying mailcow.conf..."
         source ${RESTORE_LOCATION}/mailcow.conf
@@ -363,8 +416,8 @@ elif [[ ${1} == "restore" ]]; then
   fi
 
   echo "[ 0 ] - all"
-  # find all files in folder with *.gz extension, print their base names, remove backup_, remove .tar (if present), remove .gz
-  FILE_SELECTION[0]=$(find "${FOLDER_SELECTION[${input_sel}]}" -maxdepth 1 \( -type d -o -type f \) \( -name '*.gz' -o -name 'mysql' \) -printf '%f\n' | sed 's/backup_*//' | sed 's/\.[^.]*$//' | sed 's/\.[^.]*$//')
+  # find all files in folder with *.zst or *.gz extension, print their base names, remove backup_, remove .tar (if present), remove .zst/.gz
+  FILE_SELECTION[0]=$(find "${FOLDER_SELECTION[${input_sel}]}" -maxdepth 1 \( -type d -o -type f \) \( -name '*.zst' -o -name '*.gz' -o -name 'mysql' \) -printf '%f\n' | sed 's/backup_*//' | sed 's/\.[^.]*$//' | sed 's/\.[^.]*$//' | sort -u)
   for file in $(ls -f "${FOLDER_SELECTION[${input_sel}]}"); do
     if [[ ${file} =~ vmail ]]; then
       echo "[ ${i} ] - Mail directory (/var/vmail)"

+ 301 - 0
helper-scripts/dev_tests/test_backup_and_restore.sh

@@ -0,0 +1,301 @@
+#!/usr/bin/env bash
+
+# Test script for backup_and_restore.sh
+# Tests backward compatibility with .tar.gz and new .tar.zst format
+
+set -e
+
+SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+BACKUP_IMAGE="${BACKUP_IMAGE:-ghcr.io/mailcow/backup:latest}"
+TEST_DIR="/tmp/mailcow_backup_test_$$"
+THREADS=2
+
+echo "=== Mailcow Backup & Restore Test Suite ==="
+echo "Test directory: ${TEST_DIR}"
+echo "Backup image: ${BACKUP_IMAGE}"
+echo ""
+
+# Cleanup function
+cleanup() {
+  echo "Cleaning up test files..."
+  rm -rf "${TEST_DIR}"
+  docker rmi mailcow-backup-test 2>/dev/null || true
+}
+trap cleanup EXIT
+
+# Create test directory structure
+mkdir -p "${TEST_DIR}"/{test_data,backup_zst,backup_gz,restore_zst,restore_gz,backup_large_zst,backup_large_gz}
+echo "Test data for mailcow backup compatibility test" > "${TEST_DIR}/test_data/test.txt"
+echo "Additional file to verify complete restore" > "${TEST_DIR}/test_data/test2.txt"
+
+# Build test backup image with zstd support
+echo "=== Building backup image with zstd support ==="
+docker build -t mailcow-backup-test "${SCRIPT_DIR}/../data/Dockerfiles/backup/" || {
+  echo "ERROR: Failed to build backup image"
+  exit 1
+}
+
+# Test 1: Create .tar.zst backup
+echo ""
+echo "=== Test 1: Creating .tar.zst backup ==="
+docker run --rm \
+  -w /data \
+  -v "${TEST_DIR}/test_data:/data:ro" \
+  -v "${TEST_DIR}/backup_zst:/backup" \
+  mailcow-backup-test \
+  /bin/tar --use-compress-program="zstd --rsyncable -T${THREADS}" \
+  -cvpf /backup/backup_test.tar.zst . \
+  > /dev/null
+echo "✓ .tar.zst backup created: $(ls -lh ${TEST_DIR}/backup_zst/backup_test.tar.zst | awk '{print $5}')"
+
+# Test 2: Create .tar.gz backup
+echo ""
+echo "=== Test 2: Creating .tar.gz backup (legacy) ==="
+docker run --rm \
+  -w /data \
+  -v "${TEST_DIR}/test_data:/data:ro" \
+  -v "${TEST_DIR}/backup_gz:/backup" \
+  mailcow-backup-test \
+  /bin/tar --use-compress-program="pigz --rsyncable -p ${THREADS}" \
+  -cvpf /backup/backup_test.tar.gz . \
+  > /dev/null
+echo "✓ .tar.gz backup created: $(ls -lh ${TEST_DIR}/backup_gz/backup_test.tar.gz | awk '{print $5}')"
+
+# Test 3: Test get_archive_info function
+echo ""
+echo "=== Test 3: Testing get_archive_info function ==="
+
+# Extract and test the function directly
+get_archive_info() {
+  local backup_name="$1"
+  local location="$2"
+
+  if [[ -f "${location}/${backup_name}.tar.zst" ]]; then
+    echo "${backup_name}.tar.zst|zstd -d -T${THREADS}"
+  elif [[ -f "${location}/${backup_name}.tar.gz" ]]; then
+    echo "${backup_name}.tar.gz|pigz -d -p ${THREADS}"
+  else
+    echo ""
+  fi
+}
+
+# Test with .tar.zst
+result=$(get_archive_info "backup_test" "${TEST_DIR}/backup_zst")
+if [[ "${result}" =~ "zstd" ]]; then
+  echo "✓ Correctly detects .tar.zst and returns zstd decompressor"
+else
+  echo "✗ Failed to detect .tar.zst"
+  exit 1
+fi
+
+# Test with .tar.gz
+result=$(get_archive_info "backup_test" "${TEST_DIR}/backup_gz")
+if [[ "${result}" =~ "pigz" ]]; then
+  echo "✓ Correctly detects .tar.gz and returns pigz decompressor"
+else
+  echo "✗ Failed to detect .tar.gz"
+  exit 1
+fi
+
+# Test with no file
+result=$(get_archive_info "backup_test" "${TEST_DIR}")
+if [[ -z "${result}" ]]; then
+  echo "✓ Correctly returns empty when no backup file found"
+else
+  echo "✗ Should return empty but got: ${result}"
+  exit 1
+fi
+
+# Test 4: Restore from .tar.zst
+echo ""
+echo "=== Test 4: Restoring from .tar.zst ==="
+docker run --rm \
+  -w /restore \
+  -v "${TEST_DIR}/backup_zst:/backup:ro" \
+  -v "${TEST_DIR}/restore_zst:/restore" \
+  mailcow-backup-test \
+  /bin/tar --use-compress-program="zstd -d -T${THREADS}" -xvpf /backup/backup_test.tar.zst \
+  > /dev/null 2>&1
+
+if [[ -f "${TEST_DIR}/restore_zst/test.txt" ]] && \
+   [[ -f "${TEST_DIR}/restore_zst/test2.txt" ]]; then
+  echo "✓ Successfully restored from .tar.zst"
+else
+  echo "✗ Failed to restore from .tar.zst"
+  ls -la "${TEST_DIR}/restore_zst/" || true
+  exit 1
+fi
+
+# Test 5: Restore from .tar.gz
+echo ""
+echo "=== Test 5: Restoring from .tar.gz (backward compatibility) ==="
+docker run --rm \
+  -w /restore \
+  -v "${TEST_DIR}/backup_gz:/backup:ro" \
+  -v "${TEST_DIR}/restore_gz:/restore" \
+  mailcow-backup-test \
+  /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -xvpf /backup/backup_test.tar.gz \
+  > /dev/null 2>&1
+
+if [[ -f "${TEST_DIR}/restore_gz/test.txt" ]] && \
+   [[ -f "${TEST_DIR}/restore_gz/test2.txt" ]]; then
+  echo "✓ Successfully restored from .tar.gz (backward compatible)"
+else
+  echo "✗ Failed to restore from .tar.gz"
+  ls -la "${TEST_DIR}/restore_gz/" || true
+  exit 1
+fi
+
+# Test 6: Verify content integrity
+echo ""
+echo "=== Test 6: Verifying content integrity ==="
+original_content=$(cat "${TEST_DIR}/test_data/test.txt")
+zst_content=$(cat "${TEST_DIR}/restore_zst/test.txt")
+gz_content=$(cat "${TEST_DIR}/restore_gz/test.txt")
+
+if [[ "${original_content}" == "${zst_content}" ]] && \
+   [[ "${original_content}" == "${gz_content}" ]]; then
+  echo "✓ Content integrity verified for both formats"
+else
+  echo "✗ Content mismatch detected"
+  exit 1
+fi
+
+# Test 7: Compare compression ratios
+echo ""
+echo "=== Test 7: Compression comparison ==="
+zst_size=$(stat -f%z "${TEST_DIR}/backup_zst/backup_test.tar.zst" 2>/dev/null || stat -c%s "${TEST_DIR}/backup_zst/backup_test.tar.zst")
+gz_size=$(stat -f%z "${TEST_DIR}/backup_gz/backup_test.tar.gz" 2>/dev/null || stat -c%s "${TEST_DIR}/backup_gz/backup_test.tar.gz")
+improvement=$(echo "scale=2; (${gz_size} - ${zst_size}) * 100 / ${gz_size}" | bc)
+
+echo "  Small files - .tar.gz size: ${gz_size} bytes"
+echo "  Small files - .tar.zst size: ${zst_size} bytes"
+echo "  Small files - Improvement: ${improvement}% smaller with zstd"
+
+# Test 8: Error handling - missing backup file
+echo ""
+echo "=== Test 8: Error handling - Missing backup file ==="
+result=$(get_archive_info "nonexistent_backup" "${TEST_DIR}/backup_zst")
+if [[ -z "${result}" ]]; then
+  echo "✓ Correctly handles missing backup files"
+else
+  echo "✗ Should return empty for missing files"
+  exit 1
+fi
+
+# Test 9: Error handling - Empty directory
+echo ""
+echo "=== Test 9: Error handling - Empty directory ==="
+mkdir -p "${TEST_DIR}/empty_dir"
+result=$(get_archive_info "backup_test" "${TEST_DIR}/empty_dir")
+if [[ -z "${result}" ]]; then
+  echo "✓ Correctly handles empty directories"
+else
+  echo "✗ Should return empty for empty directories"
+  exit 1
+fi
+
+# Test 10: Priority test - .tar.zst preferred over .tar.gz
+echo ""
+echo "=== Test 10: Format priority - .tar.zst preferred ==="
+mkdir -p "${TEST_DIR}/both_formats"
+touch "${TEST_DIR}/both_formats/backup_test.tar.gz"
+touch "${TEST_DIR}/both_formats/backup_test.tar.zst"
+result=$(get_archive_info "backup_test" "${TEST_DIR}/both_formats")
+if [[ "${result}" =~ "zstd" ]]; then
+  echo "✓ Correctly prefers .tar.zst when both formats exist"
+else
+  echo "✗ Should prefer .tar.zst over .tar.gz"
+  exit 1
+fi
+
+# Test 11: Large file compression test
+echo ""
+echo "=== Test 11: Large file compression test ==="
+mkdir -p "${TEST_DIR}/large_data"
+# Create ~10MB of compressible data (log-like content)
+for i in {1..50000}; do
+  echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO: Processing email message $i from user@example.com to recipient@domain.com" >> "${TEST_DIR}/large_data/maillog.txt"
+  echo "[$(date '+%Y-%m-%d %H:%M:%S')] DEBUG: SMTP connection established from 192.168.1.$((i % 255))" >> "${TEST_DIR}/large_data/maillog.txt"
+done 2>/dev/null
+
+# Get size (portable: works on Linux and macOS)
+if du --version 2>/dev/null | grep -q GNU; then
+  original_size=$(du -sb "${TEST_DIR}/large_data" | cut -f1)
+else
+  # macOS
+  original_size=$(find "${TEST_DIR}/large_data" -type f -exec stat -f%z {} \; | awk '{sum+=$1} END {print sum}')
+fi
+echo "  Original data size: $(echo "scale=2; ${original_size} / 1024 / 1024" | bc) MB"
+
+# Backup with zstd
+docker run --rm \
+  -w /data \
+  -v "${TEST_DIR}/large_data:/data:ro" \
+  -v "${TEST_DIR}/backup_large_zst:/backup" \
+  mailcow-backup-test \
+  /bin/tar --use-compress-program="zstd --rsyncable -T${THREADS}" \
+  -cvpf /backup/backup_large.tar.zst . \
+  > /dev/null 2>&1
+
+# Backup with pigz
+docker run --rm \
+  -w /data \
+  -v "${TEST_DIR}/large_data:/data:ro" \
+  -v "${TEST_DIR}/backup_large_gz:/backup" \
+  mailcow-backup-test \
+  /bin/tar --use-compress-program="pigz --rsyncable -p ${THREADS}" \
+  -cvpf /backup/backup_large.tar.gz . \
+  > /dev/null 2>&1
+
+zst_large_size=$(stat -f%z "${TEST_DIR}/backup_large_zst/backup_large.tar.zst" 2>/dev/null || stat -c%s "${TEST_DIR}/backup_large_zst/backup_large.tar.zst" 2>/dev/null || echo "0")
+gz_large_size=$(stat -f%z "${TEST_DIR}/backup_large_gz/backup_large.tar.gz" 2>/dev/null || stat -c%s "${TEST_DIR}/backup_large_gz/backup_large.tar.gz" 2>/dev/null || echo "0")
+
+if [[ ${zst_large_size} -gt 0 ]] && [[ ${gz_large_size} -gt 0 ]]; then
+  large_improvement=$(echo "scale=2; (${gz_large_size} - ${zst_large_size}) * 100 / ${gz_large_size}" | bc)
+
+  echo "  .tar.gz compressed: $(echo "scale=2; ${gz_large_size} / 1024 / 1024" | bc) MB"
+  echo "  .tar.zst compressed: $(echo "scale=2; ${zst_large_size} / 1024 / 1024" | bc) MB"
+  echo "  Improvement: ${large_improvement}% smaller with zstd"
+else
+  echo "  ✗ Failed to get file sizes"
+  exit 1
+fi
+
+if [[ $(echo "${large_improvement} > 0" | bc) -eq 1 ]]; then
+  echo "✓ zstd provides better compression on realistic data"
+else
+  echo "⚠ zstd compression similar or worse than gzip (unusual but not critical)"
+fi
+
+# Test 12: Thread scaling test
+echo ""
+echo "=== Test 12: Multi-threading verification ==="
+# This test verifies that different thread counts work (not measuring speed difference)
+for thread_count in 1 4; do
+  THREADS=${thread_count}
+  result=$(get_archive_info "backup_test" "${TEST_DIR}/backup_zst")
+  if [[ "${result}" =~ "-T${thread_count}" ]]; then
+    echo "✓ Thread count ${thread_count} correctly configured"
+  else
+    echo "✗ Thread count not properly applied"
+    exit 1
+  fi
+done
+
+echo ""
+echo "=== All tests passed! ==="
+echo ""
+echo "Summary:"
+echo "  ✓ zstd compression working"
+echo "  ✓ pigz compression working (legacy)"
+echo "  ✓ zstd decompression working"
+echo "  ✓ pigz decompression working (backward compatible)"
+echo "  ✓ Archive detection working"
+echo "  ✓ Content integrity verified"
+echo "  ✓ Format priority correct (.tar.zst preferred)"
+echo "  ✓ Error handling for missing files"
+echo "  ✓ Error handling for empty directories"
+echo "  ✓ Multi-threading configuration verified"
+echo "  ✓ Large file compression: ${large_improvement}% improvement"
+echo "  ✓ Small file compression: ${improvement}% improvement"

+ 1 - 1
helper-scripts/docker-compose.override.yml.d/EXTERNAL_MYSQL_SOCKET/docker-compose.override.yml

@@ -25,6 +25,6 @@ services:
         - /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysqld.sock
 
     mysql-mailcow:
-      image: alpine:3.22
+      image: alpine:3.23
       command: /bin/true
       restart: "no"