From e9091cbb8c2da4a5fb7d78df2d3672677f20ffb6 Mon Sep 17 00:00:00 2001
From: DerLinkman <derlinkman@gmail.com>
Date: Wed, 2 Nov 2022 10:32:56 +0100
Subject: [PATCH 01/15] [Rspamd] Update to 3.4 (fix of 3.3 Bug)

---
 docker-compose.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docker-compose.yml b/docker-compose.yml
index 05d5d83b..828b81ad 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -76,7 +76,7 @@ services:
             - clamd
 
     rspamd-mailcow:
-      image: mailcow/rspamd:1.90
+      image: mailcow/rspamd:1.91
       stop_grace_period: 30s
       depends_on:
         - dovecot-mailcow

From a6a7ab45f859a6b54652a4580dc63cb6561d7972 Mon Sep 17 00:00:00 2001
From: thomas <thomas.lauer@dthree.de>
Date: Sun, 13 Nov 2022 07:34:18 +0100
Subject: [PATCH 02/15] switch update.sh/check_online_status() from ping to
 curl to make it proxy ready

---
 update.sh | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/update.sh b/update.sh
index 707b22f5..69ada6b0 100755
--- a/update.sh
+++ b/update.sh
@@ -3,9 +3,9 @@
 ############## Begin Function Section ##############
 
 check_online_status() {
-  CHECK_ONLINE_IPS=(1.1.1.1 9.9.9.9 8.8.8.8)
-  for ip in "${CHECK_ONLINE_IPS[@]}"; do
-    if timeout 3 ping -c 1 ${ip} > /dev/null; then
+  CHECK_ONLINE_DOMAINS=('https://github.com')
+  for domain in "${CHECK_ONLINE_DOMAINS[@]}"; do
+    if timeout 3 curl --head --silent --output /dev/null ${domain}; then
       return 0
     fi
   done

From b79a1530fb59ad35d00e05544e81429257b546b7 Mon Sep 17 00:00:00 2001
From: Link Steve <56674878+yhdsl@users.noreply.github.com>
Date: Mon, 14 Nov 2022 21:18:37 +0800
Subject: [PATCH 03/15] Update Simplified Chinese Translation

---
 data/web/lang/lang.zh-cn.json | 990 +++++++++++++++++++---------------
 1 file changed, 568 insertions(+), 422 deletions(-)

diff --git a/data/web/lang/lang.zh-cn.json b/data/web/lang/lang.zh-cn.json
index bbe5c7c3..2b5685ee 100644
--- a/data/web/lang/lang.zh-cn.json
+++ b/data/web/lang/lang.zh-cn.json
@@ -2,100 +2,106 @@
     "acl": {
         "alias_domains": "添加域名别名",
         "app_passwds": "管理应用密码",
-        "bcc_maps": "BCC映射",
-        "delimiter_action": "邮件地址标签处理",
-        "eas_reset": "重置Exchange ActiveSync设备",
-        "extend_sender_acl": "允许用外部地址扩展访问控制表",
+        "bcc_maps": "BCC 映射",
+        "delimiter_action": "邮箱地址标签处理",
+        "domain_desc": "更改域名描述",
+        "domain_relayhost": "更改域名的中继主机",
+        "eas_reset": "重置 Exchange ActiveSync (EAS) 设备",
+        "extend_sender_acl": "允许通过外部地址扩展发件人的 ACL 设置",
         "filters": "过滤器",
-        "login_as": "以邮箱用户登录",
-        "prohibited": "禁止访问",
+        "login_as": "作为邮箱用户登录",
+        "mailbox_relayhost": "更改邮箱的中继主机",
+        "prohibited": "被 ACL 禁止访问",
         "protocol_access": "更改访问协议",
         "pushover": "Pushover",
         "quarantine": "隔离操作",
         "quarantine_attachments": "隔离附件",
+        "quarantine_category": "更改隔离通知类型",
         "quarantine_notification": "更改隔离通知",
         "ratelimit": "频率限制",
         "recipient_maps": "收件人映射",
-        "smtp_ip_access": "更改SMTP允许主机",
-        "sogo_access": "允许管理SOGo访问",
-        "sogo_profile_reset": "重置SOGo个人资料",
+        "smtp_ip_access": "更改 SMTP 允许主机",
+        "sogo_access": "允许管理 SOGo 访问权限",
+        "sogo_profile_reset": "重置 SOGo 个人资料",
         "spam_alias": "临时别名",
         "spam_policy": "黑名单/白名单",
         "spam_score": "垃圾邮件分数",
         "syncjobs": "同步任务",
-        "tls_policy": "TLS策略",
-        "unlimited_quota": "无限邮箱容量配额",
-        "domain_desc": "更改域名描述"
+        "tls_policy": "TLS 策略",
+        "unlimited_quota": "无限邮箱容量配额"
     },
     "add": {
-        "activate_filter_warn": "当\"启用\"被勾选,所有其他过滤器都会被禁用",
+        "activate_filter_warn": "当 \"启用\" 选项被勾选后,所有其他过滤器都会被禁用",
         "active": "启用",
         "add": "添加",
         "add_domain_only": "只添加域名",
         "add_domain_restart": "添加域名并重启",
         "alias_address": "地址别名",
-        "alias_address_info": "<small>完整邮件地址,或 @example.com 以捕获此域名下所有邮件地址的信息 (英文逗号分隔多个地址)。 <b>只允许此mailcow实例下的域名</b>。</small>",
+        "alias_address_info": "<small>使用完整的邮箱地址,或使用 @example.com 匹配此域名下所有的邮箱地址 (存在多个地址时使用英文逗号分隔)。 <b>只允许此 Mailcow 实例下的域名</b></small>",
         "alias_domain": "域名别名",
-        "alias_domain_info": "<small>只允许合法的域名 (英文逗号分隔多个地址)</small>",
+        "alias_domain_info": "<small>只允许合法的域名 (存在多个地址时使用英文逗号分隔)</small>",
         "app_name": "应用名称",
         "app_password": "添加应用密码",
-        "automap": "尝试自动映射文件夹 (如:\"已发送\", \"Sent\" => \"Sent\")",
+        "app_passwd_protocols": "应用密码允许的协议",
+        "automap": "将尝试自动映射文件夹 (例如将 \"已发送消息\" 和 \"已发送\" 均映射到 \"已发送\" 文件夹)",
         "backup_mx_options": "中继选项",
-        "comment_info": "私密评论对用户不可见,公开评论会给用户展示为鼠标悬停显示的提示",
+        "bcc_dest_format": "BCC 的目标地址必须是一个有效的电子邮箱地址。<br>如果你需要向多个地址发送副本,请创建一个别名并在此使用。",
+        "comment_info": "私密评论对用户不可见,公开评论将会在鼠标悬停时作为用户提示显示",
         "custom_params": "自定义参数",
-        "custom_params_hint": "正确的写法: --param=xy ,错误的写法: --param xy",
-        "delete1": "完成后将源邮件删除",
-        "delete2": "删除目的邮箱中存在但源邮箱中不存在的邮件",
-        "delete2duplicates": "删除目的邮箱中的重复邮件",
+        "custom_params_hint": "正确的格式: --param=xy ,错误的格式: --param xy",
+        "delete1": "在完成后删除源邮件",
+        "delete2": "删除在目标邮箱中存在但在源邮箱中不存在的邮件",
+        "delete2duplicates": "删除目标邮箱中的重复邮件",
         "description": "描述",
-        "destination": "目的邮箱",
-        "disable_login": "不允许登录 (仍然会接收邮件)",
+        "destination": "目标邮箱",
+        "disable_login": "不允许登录 (但仍然会接收邮件)",
         "domain": "域名",
-        "domain_matches_hostname": "域名 %s 与主机名匹配",
+        "domain_matches_hostname": "域名 %s 与主机名称匹配",
         "domain_quota_m": "域名总配额 (MiB)",
         "enc_method": "加密方法",
-        "exclude": "拒绝对象 (regex)",
-        "full_name": "全名",
+        "exclude": "拒绝对象 (Regex)",
+        "full_name": "全称",
         "gal": "全球地址簿",
-        "gal_info": "<b>全球地址簿</b>包含了域名下的所有对象,并且此行为不能被用户更改。如果关闭,用户的 空闲/繁忙 信息将不能在SOGo中显示。 <b>重启SOGo以应用更改。</b>",
+        "gal_info": "<b>全球地址簿</b>包含了域名下的所有对象,并且此行为不能被用户更改。如果关闭,用户的 \"空闲/繁忙\" 的状态将无法在 SOGo 中显示。 <b>重启 SOGo 服务以应用更改。</b>",
         "generate": "生成",
-        "goto_ham": "学习为 <span class=\"text-success\"><b>非垃圾邮件</b></span>",
+        "goto_ham": "学习为<span class=\"text-success\"><b>非垃圾邮件</b></span>",
         "goto_null": "静默丢弃邮件",
-        "goto_spam": "学习为 <span class=\"text-danger\"><b>垃圾邮件</b></span>",
+        "goto_spam": "学习为<span class=\"text-danger\"><b>垃圾邮件</b></span>",
         "hostname": "主机名",
         "inactive": "禁用",
         "kind": "类型",
         "mailbox_quota_def": "默认邮箱配额",
         "mailbox_quota_m": "每个邮箱的最大配额 (MiB)",
-        "mailbox_username": "用户名<br><small>(邮件地址的左侧部分)</small>",
-        "max_aliases": "最大允许地址别名数",
-        "max_mailboxes": "最大允许邮箱数",
+        "mailbox_username": "用户名 (邮箱地址左侧的部分)",
+        "max_aliases": "最大允许的地址别名数",
+        "max_mailboxes": "最大允许的邮箱数",
         "mins_interval": "轮询间隔 (分钟)",
         "multiple_bookings": "登记限制",
         "nexthop": "下一跳",
         "password": "密码",
-        "password_repeat": "确认密码<br><small>(重复输入)</small>",
+        "password_repeat": "确认密码 (重复)",
         "port": "端口",
-        "post_domain_add": "在添加新域名后SOGo的容器\"sogo-mailcow\"需要重新启动。<br><br>此外请检查并修改域名的DNS配置。一旦DNS配置生效, 重启\"acme-mailcow\"容器以自动地为你的新域名生成证书 (autoconfig.&lt;domain&gt;, autodiscover.&lt;domain&gt;)。<br>重新启动容器是可选的,生成证书的操作会每24小时重试一次。",
+        "post_domain_add": "在添加新域名后,SOGo 服务的容器 \"sogo-mailcow\" 需要重新启动。<br><br>此外请检查并修改该域名的 DNS 配置。当 DNS 配置生效后,请重启 \"acme-mailcow\" 容器以便自动地为你的新域名生成证书 (包括 autoconfig.&lt;domain&gt; 和 autodiscover.&lt;domain&gt; 两个域名)。<br>重启该容器是可选的,因为生成证书的操作会每隔24小时重试一次。",
         "private_comment": "私密评论",
         "public_comment": "公开评论",
         "quota_mb": "配额 (MiB)",
         "relay_all": "中继所有收件人",
-        "relay_all_info": "↪ 如果<b>不</b>选择中继所有收件人,你将需要为每个应该中继的邮件添加一个 (\"盲\") 邮箱。",
+        "relay_all_info": "↪ 如果<b>不</b>选择中继所有收件人,你将需要为每个需要中继的邮件添加一个(\"虚拟\")邮箱。",
         "relay_domain": "中继这个域名",
-        "relay_transport_info": "<div class=\"label label-info\"></div> 你可以为此域名定义传输规则以自定义发件目标主机,否则遵照MX记录发送邮件。",
-        "relay_unknown_only": "只为不存在的邮箱地址中继。已存在的邮箱地址则在本地递送。",
-        "relayhost_wrapped_tls_info": "请 <b>不要</b> 使用\"嵌套TLS\"的端口 (大多为端口465).<br>\r\n使用其他\"非嵌套\"的端口发起STARTTLS. 你可以在\"TLS策略规则\"中添加强制使用TLS的策略。",
+        "relay_transport_info": "<div class=\"label label-info\">注意</div> 你可以为此域名自定义传输规则来指定发件目标主机,否则将按照 MX 记录发送邮件。",
+        "relay_unknown_only": "只为不存在的邮箱地址中继。已存在的邮箱地址将在本地发送。",
+        "relayhost_wrapped_tls_info": "请<b>不要</b>使用\"嵌套 TLS \"的端口 (大多数为端口 465)。<br>\r\n使用其他\"非嵌套\"的端口发起 STARTTLS。你可以在\"TLS 策略规则\"中添加强制使用 TLS 的策略。",
         "select": "请选择...",
         "select_domain": "请先选择一个域名",
         "sieve_desc": "简短描述",
         "sieve_type": "过滤器类型",
-        "skipcrossduplicates": "跳过其他文件夹中已存在的邮件(保留先存在的邮件)",
+        "skipcrossduplicates": "跳过其他文件夹中已存在的邮件 (保留已经存在的邮件)",
         "subscribeall": "订阅所有文件夹",
         "syncjob": "添加同步任务",
-        "syncjob_hint": "注意密码需要以明文存储!",
+        "syncjob_hint": "注意密码将以明文存储!",
+        "tags": "标签",
         "target_address": "目标地址",
-        "target_address_info": "<small>完整的邮箱地址 (英文逗号分隔多个地址)。</small>",
+        "target_address_info": "<small>完整的邮箱地址 (存在多个地址时使用英文逗号分隔)</small>",
         "target_domain": "目标域名",
         "timeout1": "远程主机连接超时时间",
         "timeout2": "本地主机连接超时时间",
@@ -104,12 +110,12 @@
         "validation_success": "验证成功"
     },
     "admin": {
-        "access": "访问",
+        "access": "权限管理",
         "action": "操作",
-        "activate_api": "启用API",
+        "activate_api": "启用 API",
         "activate_send": "启用发送按钮",
         "active": "启用",
-        "active_rspamd_settings_map": "启用的设置规则",
+        "active_rspamd_settings_map": "启用的规则",
         "add": "添加",
         "add_admin": "添加管理员",
         "add_domain_admin": "添加域名管理员",
@@ -124,36 +130,41 @@
         "admin": "管理员",
         "admin_details": "编辑管理员详情",
         "admin_domains": "分配域名",
+        "admins": "管理员",
+        "admins_ldap": "LDAP 管理员",
         "advanced_settings": "高级设置",
-        "api_allow_from": "允许来自这些IP/CIDR网络的API访问",
-        "api_info": "API功能仍在完善中。你可以在<a href=\"/api\">/api</a>找到API文档",
-        "api_key": "API密钥",
-        "api_skip_ip_check": "跳过API的IP检查",
+        "api_allow_from": "允许来自这些 IP/CIDR 网络的 API 访问",
+        "api_info": "API 功能仍在完善中。你可以在<a href=\"/api\">这里</a>找到 API 文档",
+        "api_key": "API 密钥",
+        "api_read_only": "只读权限",
+        "api_read_write": "可写权限",
+        "api_skip_ip_check": "跳过 API 的 IP 检查",
         "app_links": "应用链接",
         "app_name": "应用名称",
-        "apps_name": "\"mailcow Apps\" 名称",
-        "arrival_time": "到达时间(服务器)",
+        "apps_name": "Mailcow 应用的名称",
+        "arrival_time": "到达时间 (服务器时间)",
         "authed_user": "已认证用户",
         "ays": "确定继续操作?",
-        "ban_list_info": "下为封禁掉的IP列表: <b>网络 (剩余封禁时间) - [操作]</b>。<br />取消封禁的IP将会在几秒之内从封禁列表中移除<br />红色标签表示因黑名单而导致的永久封禁",
-        "change_logo": "更改logo",
+        "ban_list_info": "以下为被封禁的 IP 列表: <b>网络 (剩余封禁时间) - [操作]</b>。<br />被取消封禁的 IP 将会在几秒之内从封禁列表中移除<br />红色标签表示因黑名单而导致的永久封禁",
+        "change_logo": "更改 Logo",
         "configuration": "配置",
-        "credentials_transport_warning": "<b>警告</b>: 添加新的传输规则会为所有\"下一跳\"列匹配的规则更新认证凭证。",
-        "customer_id": "客户ID",
-        "customize": "自定义",
+        "convert_html_to_text": "将 HTML 转换为纯文本内容",
+        "credentials_transport_warning": "<b>警告</b>: 添加新的传输规则将会为所有的\"下一跳\"列匹配的规则更新认证凭证。",
+        "customer_id": "客户 ID",
+        "customize": "页面自定义",
         "delete_queue": "删除所有",
         "destination": "目标地址",
-        "dkim_add_key": "添加ARC/DKIM密钥",
+        "dkim_add_key": "添加 ARC/DKIM 密钥",
         "dkim_domains_selector": "选择器",
-        "dkim_domains_wo_keys": "选择没有密钥的域名",
+        "dkim_domains_wo_keys": "选择缺失密钥的域名",
         "dkim_from": "从",
         "dkim_from_title": "源域名 - 数据来源",
-        "dkim_key_length": "DKIM密钥长度 (bits)",
+        "dkim_key_length": "DKIM 密钥长度 (Bits)",
         "dkim_key_missing": "密钥缺失",
-        "dkim_key_unused": "密钥未被使用",
+        "dkim_key_unused": "密钥闲置",
         "dkim_key_valid": "密钥合法",
-        "dkim_keys": "ARC/DKIM密钥",
-        "dkim_overwrite_key": "覆盖已存在的DKIM密钥",
+        "dkim_keys": "ARC/DKIM 密钥",
+        "dkim_overwrite_key": "覆盖已存在的 DKIM 密钥",
         "dkim_private_key": "私钥",
         "dkim_to": "到",
         "dkim_to_title": "目标域名 - 数据将会被覆盖",
@@ -162,48 +173,51 @@
         "domain_admins": "域名管理员",
         "domain_s": "域名",
         "duplicate": "复制",
-        "duplicate_dkim": "复制DKIM记录",
+        "duplicate_dkim": "复制 DKIM 记录",
         "edit": "编辑",
         "empty": "结果为空",
         "excludes": "除了",
         "f2b_ban_time": "封禁时间 (秒)",
         "f2b_blacklist": "网络/主机黑名单",
         "f2b_filter": "正则表达式过滤器",
-        "f2b_list_info": "黑名单的优先级总是高于白名单。 <b>列表更新将会在几秒之后应用。</b>",
+        "f2b_list_info": "黑名单的优先级总是高于白名单。 <b>列表更新将会在几秒之后完成。</b>",
         "f2b_max_attempts": "最多尝试次数",
-        "f2b_netban_ipv4": "应用封禁的IPv4子网大小 (8-32)",
-        "f2b_netban_ipv6": "应用封禁的IPv6子网大小 (8-128)",
-        "f2b_parameters": "Fail2ban参数",
-        "f2b_regex_info": "会过滤这些应用的日志: SOGo、Postfix、Dovecot、PHP-FPM。",
+        "f2b_netban_ipv4": "应用封禁的 IPv4 子网大小 (8-32)",
+        "f2b_netban_ipv6": "应用封禁的 IPv6 子网大小 (8-128)",
+        "f2b_parameters": "Fail2ban 参数",
+        "f2b_regex_info": "将会过滤这些应用的日志: SOGo,Postfix,Dovecot 和 PHP-FPM。",
         "f2b_retry_window": "最多尝试次数重试窗口 (秒)",
         "f2b_whitelist": "网络/主机白名单",
         "filter_table": "筛选表格",
         "flush_queue": "清空队列",
         "forwarding_hosts": "转发主机",
-        "forwarding_hosts_add_hint": "你可以指定 IPv4/IPv6 地址、CIDR 表示的网络、主机名 (解析为IP地址),或者邮箱域名 (查询SPF记录或MX记录并解析为IP地址)。",
-        "forwarding_hosts_hint": "来自此处所列的主机的入站信息会被无条件接收。并且这些主机不会经过DNSBL检查或者被加入灰名单。 来自它们的垃圾邮件不会被拒绝,但可选的可以被移入垃圾文件夹。当你设置了转发规则将邮件转发到此mailcow服务器,通常你可以将来源主机加入此列表。",
+        "forwarding_hosts_add_hint": "你可以指定 IPv4/IPv6 地址、CIDR 表示的网络、主机名 (解析为 IP 地址),或者邮箱域名 (查询 SPF 记录或 MX 记录并解析为 IP 地址)。",
+        "forwarding_hosts_hint": "来自此处所列的主机的入站信息将会被无条件接收。并且这些主机将不会经过 DNSBL 检查或者被加入灰名单。来自它们的垃圾邮件将不会被拒绝,但可以选择将其移入垃圾文件夹。当你设置了转发规则将邮件转发到此 Mailcow 服务器,你通常可以将来源主机加入此列表。",
         "from": "来自",
         "generate": "生成",
-        "guid": "GUID - 唯一实例ID",
+        "guid": "GUID - 唯一的安装实例 ID",
         "guid_and_license": "GUID和许可证",
-        "hash_remove_info": "移除一个频率限制特征 (如果还存在的话) 会完全移除它的计数器。<br>\r\n 每个特征将以不同颜色表示。",
-        "help_text": "覆盖登录面板下的帮助文字 (允许使用HTML)",
+        "hash_remove_info": "移除一个频率限制特征 (如果还存在的话) 将会完全移除它的计数器。<br>\r\n 每个特征将以不同颜色表示。",
+        "help_text": "覆盖登录面板下的帮助文字 (允许使用 HTML)",
         "host": "主机",
+        "html": "HTML",
         "import": "导入",
         "import_private_key": "导入私钥",
         "in_use_by": "使用者",
         "inactive": "禁用",
         "include_exclude": "包括/排除",
-        "include_exclude_info": "没有选择时默认包括所有邮箱",
+        "include_exclude_info": "默认 - 没有选择时默认包括所有邮箱",
         "includes": "包括这些收件人",
+        "is_mx_based": "基于 MX 记录",
         "last_applied": "最后应用的条目",
-        "license_info": "你不需要获取证书以使用此项目,但是获取证书可以帮助此项目进一步发展。<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">在这里注册你的GUID</a> 或者 <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Support order\">为你的mailcow安装购买支持服务。</a>",
+        "license_info": "你不需要获取证书便可以使用此项目,但是获取证书可以帮助此项目进一步发展。<br>在这里<a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">注册</a>你的 GUID或者为你的 Mailcow 安装<a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Support order\">购买</a>支持服务。",
         "link": "链接",
         "loading": "请等待...",
-        "logo_info": "你的图片会在顶部导航栏被缩放为40px高,在起始页被缩放为最大250px高度。强烈推荐使用能较好缩放的图片。",
-        "lookup_mx": "匹配MX记录 (如匹配.outlook.com MX记录以通过这一跳来路由所有指向*.outlook.com的邮件)",
-        "main_name": "\"mailcow UI\" 名称",
-        "merged_vars_hint": "灰色行来自 <code>vars.(local.)inc.php</code> 并且不能被更改。",
+        "login_time": "登录时间",
+        "logo_info": "你的图片将会在顶部导航栏被缩放为 40px 高,在起始页被缩放为最大 250px 高。强烈推荐使用能较好适应缩放的图片。",
+        "lookup_mx": "应当为一个正则表达式,用于匹配 MX 记录 (例如 <code>.*google\\.com</code> 将转发所有拥有以 google.com 结尾的 MX 记录的邮件)",
+        "main_name": "Mailcow UI 的名称",
+        "merged_vars_hint": "灰色行来自 <code>vars.(local.)inc.php</code> 文件并且无法修改。",
         "message": "消息",
         "message_size": "消息大小",
         "nexthop": "下一跳",
@@ -211,58 +225,69 @@
         "no_active_bans": "没有启用的封禁",
         "no_new_rows": "已经到底了",
         "no_record": "没有记录",
-        "oauth2_client_id": "客户端ID",
-        "oauth2_client_secret": "客户端secret",
-        "oauth2_info": "此OAuth2实现支持\"Authorization Code\"和生成refresh token。<br>\r\n并且服务器会自动在refresh token被使用后重新生成refresh token。<br><br>\r\n→ 默认的scope是 <i>profile</i>。只有邮箱用户可以使用OAuth2来认证。如果scope参数被省略则会回退到 <i>profile</i>。<br>\r\n→ 客户端必须在认证请求中发送 <i>state</i> 参数。<br><br>\r\nOAuth2 API路径: <br>\r\n<ul>\r\n  <li>Authorization endpoint: <code>/oauth/authorize</code></li>\r\n  <li>Token endpoint: <code>/oauth/token</code></li>\r\n  <li>Resource page:  <code>/oauth/profile</code></li>\r\n</ul>\r\n重新生成客户端secret不会使已存在的authorization code过期,但是会在它们刷新token时失败。<br><br>\r\n撤销客户端token会立即终止所有活动会话。 所有的客户端都需要重新认证。",
-        "oauth2_redirect_uri": "重定向URI",
-        "oauth2_renew_secret": "生成新的客户端secret",
-        "oauth2_revoke_tokens": "撤销所有客户端token",
+        "oauth2_apps": "OAuth2 应用",
+        "oauth2_add_client": "添加 OAuth2 客户端",
+        "oauth2_client_id": "客户端 ID",
+        "oauth2_client_secret": "客户端 secret",
+        "oauth2_info": "此 OAuth2 服务支持 \"Authorization Code\" 和生成 refresh token。<br>\r\n并且服务器会自动在 refresh token 被使用后重新生成新的 refresh token。<br><br>\r\n→ 默认的 scope 是 <i>profile</i>。只有邮箱用户可以使用 OAuth2 进行认证。如果 scope 参数被省略则会回退到 <i>profile</i>。<br>\r\n→ 客户端必须在认证请求中发送 <i>state</i> 参数。<br><br>\r\nOAuth2 API 路径: <br>\r\n<ul>\r\n  <li>Authorization endpoint: <code>/oauth/authorize</code></li>\r\n  <li>Token endpoint: <code>/oauth/token</code></li>\r\n  <li>Resource page:  <code>/oauth/profile</code></li>\r\n</ul>\r\n重新生成客户端 secret 不会使已存在的 authorization code 过期,但是会在使用它们刷新 token 时失败。<br><br>\r\n撤销客户端的 token 会立即终止所有的活动会话。 并且所有的客户端都需要重新认证。",
+        "oauth2_redirect_uri": "重定向 URI",
+        "oauth2_renew_secret": "生成新的客户端 secret",
+        "oauth2_revoke_tokens": "撤销所有的客户端 token",
+        "optional": "可选",
         "password": "密码",
+        "password_length": "密码长度",
+        "password_policy": "密码规则",
+        "password_policy_chars": "必须包含至少一个英文字母",
+        "password_policy_length": "密码最小长度为 %d",
+        "password_policy_lowerupper": "必须包含小写和大写的英文字母",
+        "password_policy_numbers": "必须包含至少一个数字",
+        "password_policy_special_chars": "必须包含特殊字符",
         "password_repeat": "确认密码 (重复)",
         "priority": "优先级",
         "private_key": "私钥",
         "quarantine": "隔离",
-        "quarantine_bcc": "发送所有通知邮件的副本(BCC)到这个收件人:<br><small>留空以关闭。 <b>发送的邮件未被签名也未被检查。 故只应在内部递送。</b></small>",
-        "quarantine_exclude_domains": "不启用隔离的域名和域名别名",
-        "quarantine_max_age": "最长保留日数<br><small>必须大于或等于1日</small>",
-        "quarantine_max_size": "最大文件大小,单位MiB (超出限制的元素会被丢弃):<br><small>0 <b>不</b> 表示不限大小。</small>",
-        "quarantine_max_score": "如果垃圾分数大于此值则不通知:<br><small>默认为 9999.0</small>",
-        "quarantine_notification_html": "通知邮件模板:<br><small>留空以恢复默认模板。</small>",
+        "quarantine_bcc": "发送所有通知邮件的副本 (BCC) 到这个收件人:<br><small>留空以禁用该操作。 <b>发送的邮件未被签名也未被检查。 因此只应在内部传递。</b></small>",
+        "quarantine_exclude_domains": "未启用隔离的域名和域名别名",
+        "quarantine_max_age": "最长保留天数<br><small>必须大于或等于1天</small>",
+        "quarantine_max_score": "如果垃圾邮件的分数大于此值则不通知:<br><small>默认为 9999.0</small>",
+        "quarantine_max_size": "文件的最大大小,单位 MiB (超出限制的部分会被丢弃):<br><small>0 表示<b>无限制</b>。</small>",
+        "quarantine_notification_html": "通知邮件模板:<br><small>留空则恢复默认模板。</small>",
         "quarantine_notification_sender": "通知邮件发件人",
         "quarantine_notification_subject": "通知邮件主题",
-        "quarantine_redirect": "<b>转发所有通知</b>到这个收件人:<br><small>留空以关闭。 <b>发送的邮件未被签名也未被检查。 故只应在内部递送。</b></small>",
-        "quarantine_release_format": "被释放的项目的格式",
+        "quarantine_redirect": "<b>转发所有的通知</b>到这个收件人:<br><small>留空以禁用该操作。 <b>发送的邮件未被签名也未被检查。 故只应在内部传递。</b></small>",
+        "quarantine_release_format": "被移除的项目的格式",
         "quarantine_release_format_att": "附件",
-        "quarantine_release_format_raw": "未修改原件",
+        "quarantine_release_format_raw": "原件 (未修改)",
         "quarantine_retention_size": "每个邮箱保留隔离项目数:<br><small>0 表示 <b>禁用</b>。</small>",
-        "queue_ays": "请确认你真的想要删除当前队列中的所有项目。",
-        "queue_deliver_mail": "递送",
+        "queue_ays": "你真的确定想要删除当前队列中的所有项目吗?",
+        "queue_deliver_mail": "传递",
         "queue_hold_mail": "暂停",
-        "queue_manager": "队列管理器",
+        "queue_manager": "队列管理",
+        "queue_show_message": "显示消息",
         "queue_unban": "队列取消封禁",
         "queue_unhold_mail": "继续",
-        "queue_show_message": "显示消息",
-        "quota_notification_html": "通知邮件模板:<br><small>留空以恢复默认模板。</small>",
+        "quota_notification_html": "通知邮件模板:<br><small>留空则恢复默认模板。</small>",
         "quota_notification_sender": "通知邮件发件人",
         "quota_notification_subject": "通知邮件主题",
         "quota_notifications": "配額通知",
-        "quota_notifications_info": "配額通知会在用户配额超过80%和95%时各发送一次。",
-        "quota_notifications_vars": "{{percent}} 表示当前用户配额<br>{{username}} 未邮箱名称",
+        "quota_notifications_info": "配額通知会在用户配额超过 80% 和 95% 时各发送一次。",
+        "quota_notifications_vars": "{{percent}} 表示当前用户配额<br>{{username}} 为邮箱名称",
         "r_active": "启用的限制规则",
         "r_inactive": "禁用的限制规则",
-        "r_info": "启用的限制规则列表中灰色的/关闭的元素不能被mailcow识别为合法的限制规则,且不可移动。未知的限制规则将会按照原来的顺序被设置。<br>你可以在 <code>inc/vars.local.inc.php</code> 中添加新元素以勾选它们。",
+        "r_info": "启用的限制规则列表中灰色的和关闭的部分无法被 Mailcow 识别为合法的限制规则,并且不可移动。未知的限制规则将会按照原来的顺序被设置。<br>你可以在 <code>inc/vars.local.inc.php</code> 中添加新内容以勾选它们。",
         "rate_name": "频率名称",
         "recipients": "收件人",
         "refresh": "刷新",
-        "regen_api_key": "重新生成API密钥",
+        "regen_api_key": "重新生成 API 密钥",
         "regex_maps": "正则表达式规则",
         "relay_from": "\"来自:\" 地址",
+        "relay_rcpt": "\"到达:\" 地址",
         "relay_run": "运行测试",
         "relayhosts": "中继传输",
-        "relayhosts_hint": "定义的中继传输可以在域名配置弹出框中被选择。<br>\r\n 中继传输服务总是使用 \"smtp:\" 并且会在可能时使用STARTTLS。不支持SMTPS。用户的出站TLS策略会影响此行为。<br>\r\n 对选中的域名和域名别名生效。",
+        "relayhosts_hint": "自定义的中继传输可以在域名配置的弹出框中被选择。<br>\r\n 中继传输服务总是使用 \"smtp:\" 并且会在可能时使用 TLS,并且不支持 Wrapped TLS (SMTPS)。用户的出站 TLS 策略将会影响此行为。<br>\r\n 对选中的域名和域名别名生效。",
         "remove": "删除",
         "remove_row": "删除行",
-        "reset_default": "重置回默认值",
+        "reset_default": "重置为默认值",
         "reset_limit": "移除特征",
         "routing": "路由",
         "rsetting_add_rule": "添加规则",
@@ -271,221 +296,237 @@
         "rsetting_no_selection": "请选择一个规则",
         "rsetting_none": "没有可用的规则",
         "rsettings_insert_preset": "插入示例预设 \"%s\"",
-        "rsettings_preset_1": "为已认证用户关闭除DKIM和ratelimit规则外的所有规则",
-        "rsettings_preset_2": "管理员(postmaster)想要垃圾邮件",
-        "rsettings_preset_3": "只允许指定的发件人 (如只允许内部邮箱发送)",
-        "rspamd_com_settings": "自动生成设置名称,请看下方的示例预设。查看<a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd docs</a>以了解更多细节。",
+        "rsettings_preset_1": "为已认证用户关闭除 DKIM 和频率限制规则外的所有规则",
+        "rsettings_preset_2": "允许管理员接收垃圾邮件",
+        "rsettings_preset_3": "只允许指定的发件人发信 (例如只允许内部邮箱发送)",
+        "rsettings_preset_4": "禁用域名的 Rspamd 服务",
+        "rspamd_com_settings": "设置名称将会自动生成,请看参考下方的示例预设。查看<a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd 文档</a>以了解更多的细节。",
         "rspamd_global_filters": "全局过滤规则",
         "rspamd_global_filters_agree": "我会小心谨慎的!",
         "rspamd_global_filters_info": "全局过滤规则包含了不同类型的全局黑名单和白名单。",
-        "rspamd_global_filters_regex": "它们的名字解释了它们的用途。所有内容必须包含 \"/pattern/options\" 格式的合法表达式(如 <code>/.+@domain\\.tld/i</code>)。<br>\r\n 对正则表达式只执行了基本的检查,Rspamd功能仍可能因正则表达式表达式语法问题导致错误。<br>\r\n  Rspamd会在规则更改后读取其内容。 如果你遇到了问题,<a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">重启Rspamd</a> 以强制重载规则。<br>黑名单中项目会被隔离系统排除。",
-        "rspamd_settings_map": "Rspamd设置规则",
-        "sal_level": "Moo等级",
+        "rspamd_global_filters_regex": "它们的名字解释了它们的用途。所有内容必须包含 \"/pattern/options\" 格式的合法表达式 (例如 <code>/.+@domain\\.tld/i</code>)。<br>\r\n 因为仅对正则表达式执行了基本的检查,Rspamd 的功能仍可能因正则表达式语法问题出现错误。<br>\r\n  Rspamd 会在规则更改后读取其内容。 如果你遇到了问题,<a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">重启 Rspamd</a> 以强制重载规则。<br>黑名单中的项目会被系统排除。",
+        "rspamd_settings_map": "Rspamd 设置",
+        "sal_level": "Moo 等级",
         "save": "保存更改",
         "search_domain_da": "搜索域名",
         "send": "发送",
         "sender": "发件人",
-        "service_id": "服务ID",
+        "service": "服务",
+        "service_id": "服务 ID",
         "source": "来源",
         "spamfilter": "垃圾邮件过滤器",
         "subject": "主题",
+        "success": "成功",
         "sys_mails": "系统邮件",
         "text": "文本",
         "time": "时间",
         "title": "标题",
-        "title_name": "\"mailcow UI\" 网站标题",
+        "title_name": "Mailcow UI 的网站标题",
         "to_top": "返回顶部",
-        "transport_dest_format": "格式: example.org, .example.org, *, box@example.org (英文逗号分隔多个值)",
+        "transport_dest_format": "正则表达式格式: example.org, .example.org, *, box@example.org (存在多个地址时使用英文逗号分隔)",
         "transport_maps": "传输规则",
-        "transports_hint": "→ 传输规则条目<b>优先于</b>中继传输</b>。<br>\r\n→ 用户的出站TLS策略设置会被忽略,只会执行域名的TLS策略规则。<br>\r\n→ 传输服务总是使用 \"smtp:\" 并且会在可能时使用STARTTLS。不支持SMTPS。\r\n→ 匹配 \"/localhost$/\" 的地址会通过 \"local:\" 传输,但是 \"*\" 不会匹配这些本地地址。<br>\r\n→ 为了确定下一跳 \"[host]:25\" 的认证凭证, Postfix <b>总会</b> 先查询 \"host\" 而不是 \"[host]:25\"。此行为使不能同时使用 \"host\" 和 \"[host]:25\"。",
-        "ui_footer": "页脚 (允许使用HTML)",
+        "transport_test_rcpt_info": "&#8226; 使用 null@hosted.mailcow.de 测试中继到国外目标的状况。",
+        "transports_hint": "&#8226; 传输规则条目会<b>覆盖</b>发件人的传输规则条目</b>.<br>\r\n&#8226; 建议使用基于 MX 记录的传输规则条目。<br>\r\n&#8226; 用户的出站 TLS 策略将会被忽略,并且只接受域名的 TLS 策略。<br>\r\n&#8226; 传输服务总是使用 \"smtp:\" 并且会在可能时使用 TLS,并且不支持 Wrapped TLS (SMTPS)。<br>\r\n&#8226; 匹配 \"/localhost$/\" 的地址将会通过 \"local:\" 传输,但是 \"*\" 不会匹配这些本地地址。<br>\r\n&#8226; 为了确定下一跳 \"[host]:25\" 的认证凭证,Postfix <b>总会</b> 先查询 \"host\" 而不是 \"[host]:25\"。此行为使得 \"host\" 和 \"[host]:25\" 不能同时被使用。",
+        "ui_footer": "页脚 (允许使用 HTML)",
         "ui_header_announcement": "公告",
         "ui_header_announcement_active": "启用公告",
-        "ui_header_announcement_content": "文本 (允许使用HTML)",
-        "ui_header_announcement_help": "公告会在UI登录屏幕和用户登录后页面显示。",
+        "ui_header_announcement_content": "文本 (允许使用 HTML)",
+        "ui_header_announcement_help": "公告会在登录页面以及用户登录后的页面显示。",
         "ui_header_announcement_select": "选择公告类型",
         "ui_header_announcement_type": "类型",
-        "ui_header_announcement_type_info": "信息",
-        "ui_header_announcement_type_warning": "重要",
-        "ui_header_announcement_type_danger": "非常重要",
-        "ui_texts": "UI标签和文本",
+        "ui_header_announcement_type_danger": "重要",
+        "ui_header_announcement_type_info": "通知",
+        "ui_header_announcement_type_warning": "注意",
+        "ui_texts": "UI 标签和文本",
         "unban_pending": "等待解除封禁",
         "unchanged_if_empty": "如果不更改则留空",
         "upload": "上传",
         "username": "用户名",
-        "validate_license_now": "通过证书服务器验证GUID",
+        "validate_license_now": "通过证书服务器验证 GUID",
         "verify": "验证",
         "yes": "&#10003;"
     },
     "danger": {
-        "access_denied": "访问拒绝或表单数据非法",
-        "alias_domain_invalid": "域名别名 %s 非法",
+        "access_denied": "访问被拒绝或者表单数据无效",
+        "alias_domain_invalid": "域名别名 %s 无效",
         "alias_empty": "域名地址不能为空",
         "alias_goto_identical": "别名不能与目标地址相同",
-        "alias_invalid": "别名地址 %s 非法",
-        "aliasd_targetd_identical": "域名别名不能与目标域名不能与目标域名相同: %s",
+        "alias_invalid": "别名地址 %s 无效",
+        "aliasd_targetd_identical": "域名别名不能与目标域名 %s 相同",
         "aliases_in_use": "最大别名数必须大于等于 %d",
         "app_name_empty": "应用名称不能为空",
-        "app_passwd_id_invalid": "应用密码 ID %s 非法",
-        "bcc_empty": "BCC目标地址不能为空",
-        "bcc_exists": "%s类型的BCC映射%s已存在",
-        "bcc_must_be_email": "BCC目标地址 %s 不是合法的邮箱地址",
+        "app_passwd_id_invalid": "应用密码 ID %s 无效",
+        "bcc_empty": "BCC 目标地址不能为空",
+        "bcc_exists": "%s 类型的 BCC 映射 %s 已存在",
+        "bcc_must_be_email": "BCC 目标地址 %s 不是有效的邮箱地址",
         "comment_too_long": "评论太长,最多允许160个字符",
         "defquota_empty": "每个邮箱的默认配额必须不为0。",
-        "description_invalid": "%s 的资源描述非法",
-        "dkim_domain_or_sel_exists": "\"%s\"的DKIM密钥已存在,因此不会覆盖此密钥",
-        "dkim_domain_or_sel_invalid": "DKIM域名或选择器非法: %s",
-        "domain_cannot_match_hostname": "域名与主机名不匹配",
+        "description_invalid": "%s 的资源描述无效",
+        "dkim_domain_or_sel_exists": "\"%s\"的 DKIM 密钥已存在,因此不会被覆盖",
+        "dkim_domain_or_sel_invalid": "DKIM 域名或选择器无效: %s",
+        "domain_cannot_match_hostname": "域名与主机名称不匹配",
         "domain_exists": "域名 %s 已存在",
-        "domain_invalid": "域名地址为空或非法",
+        "domain_invalid": "域名地址为空或无效",
         "domain_not_empty": "不能删除非空域名 %s",
-        "domain_not_found": "不能找到域名 %s",
+        "domain_not_found": "无法找到域名 %s",
         "domain_quota_m_in_use": "域名配额必须大于等于 %s MiB",
-        "extra_acl_invalid": "外部发件人地址 \"%s\" 非法",
-        "extra_acl_invalid_domain": "外部发件人地址 \"%s\" 包含了非法的域名",
-        "file_open_error": "不能打开文件以写入",
+        "extra_acl_invalid": "外部发件人地址 \"%s\" 无效",
+        "extra_acl_invalid_domain": "外部发件人地址 \"%s\" 包含了无效的域名",
+        "fido2_verification_failed": "FIDO2 验证失败: %s",
+        "file_open_error": "无法打开文件以写入内容",
         "filter_type": "过滤器类型错误",
         "from_invalid": "发件人地址不能为空",
-        "global_filter_write_error": "不能写入过滤器文件: %s",
-        "global_map_invalid": "全局规则 ID %s 非法",
-        "global_map_write_error": "全局规则 ID %s: %s",
-        "goto_empty": "一个别名地址必须包含至少一个合法的目标地址",
-        "goto_invalid": "目标地址 %s 不合法",
-        "ham_learn_error": "学习非垃圾消息错误: %s",
-        "imagick_exception": "错误: 读取图片时Imagick发生了异常",
-        "img_invalid": "不能验证图片文件",
-        "img_tmp_missing": "不能验证图片文件: 找不到临时文件",
-        "invalid_bcc_map_type": "BCC映射类型非法",
-        "invalid_destination": "目的地址 \"%s\" 非法",
-        "invalid_filter_type": "过滤器类型非法",
-        "invalid_host": "非法主机: %s",
-        "invalid_mime_type": "mime类型非法",
-        "invalid_nexthop": "下一跳格式非法",
+        "global_filter_write_error": "无法写入过滤器文件: %s",
+        "global_map_invalid": "全局规则 ID %s 无效",
+        "global_map_write_error": "无法写入全局规则 ID %s: %s",
+        "goto_empty": "别名地址必须包含至少一个合法的目标地址",
+        "goto_invalid": "目标地址 %s 无效",
+        "ham_learn_error": "学习非垃圾邮件错误: %s",
+        "imagick_exception": "错误: 读取图片时发生了 Imagick 异常",
+        "img_invalid": "无法验证图片文件",
+        "img_tmp_missing": "无法验证图片文件: 找不到临时文件",
+        "invalid_bcc_map_type": "BCC 映射类型无效",
+        "invalid_destination": "目标地址 \"%s\" 无效",
+        "invalid_filter_type": "过滤器类型无效",
+        "invalid_host": "无效主机: %s",
+        "invalid_mime_type": "MIME 类型无效",
+        "invalid_nexthop": "下一跳格式无效",
         "invalid_nexthop_authenticated": "存在使用不同凭证的下一跳,请先更改这些下一跳的凭证。",
-        "invalid_recipient_map_new": "新收件人地址非法: %s",
-        "invalid_recipient_map_old": "原收件人地址非法: %s",
-        "ip_list_empty": "IP允许列表不能为空",
+        "invalid_recipient_map_new": "新收件人地址无效: %s",
+        "invalid_recipient_map_old": "原收件人地址无效: %s",
+        "ip_list_empty": "IP 允许列表不能为空",
         "is_alias": "%s 已经被作为别名地址使用",
         "is_alias_or_mailbox": "%s 已经被作为别名地址、邮箱地址或域名别名扩展出的别名地址使用。",
         "is_spam_alias": "%s 已经被作为临时别名地址使用 (垃圾邮件别名地址)",
-        "last_key": "最后一个密钥不能被删除,你应该先禁用两步验证。",
+        "last_key": "无法删除最后一个密钥,你应该先禁用两步验证。",
         "login_failed": "登录失败",
         "mailbox_defquota_exceeds_mailbox_maxquota": "默认配额超出配额限制",
-        "mailbox_invalid": "邮箱名称不合法",
+        "mailbox_invalid": "邮箱名称无效",
         "mailbox_quota_exceeded": "配额超出域名配额限制 (最大 %d MiB)",
         "mailbox_quota_exceeds_domain_quota": "最大配额超出域名配额限制",
         "mailbox_quota_left_exceeded": "空间不足 (剩余空间: %d MiB)",
         "mailboxes_in_use": "最大邮箱数必须大于等于 %d",
-        "malformed_username": "畸形用户名",
+        "malformed_username": "异常的用户名",
         "map_content_empty": "规则内容不能为空",
         "max_alias_exceeded": "超出最大别名数",
         "max_mailbox_exceeded": "超出最大邮箱数 (%d / %d)",
         "max_quota_in_use": "邮箱数必须大于等于 %d MiB",
-        "maxquota_empty": "每个邮箱最大配额必须不为0",
-        "mysql_error": "MySQL错误: %s",
-        "network_host_invalid": "网络或主机非法: %s",
+        "maxquota_empty": "每个邮箱的最大配额必须不为0",
+        "mysql_error": "MySQL 错误: %s",
+        "network_host_invalid": "网络或主机无效: %s",
         "next_hop_interferes": "%s 与下一跳 %s 冲突",
         "next_hop_interferes_any": "一个已存在的下一跳与 %s 冲突",
-        "no_user_defined": "未定义用户",
+        "nginx_reload_failed": "重启 Nginx 失败: %s",
+        "no_user_defined": "用户未定义",
         "object_exists": "对象 %s 已存在",
-        "object_is_not_numeric": "不是数字值: %s",
+        "object_is_not_numeric": "%s 不是一个数字",
         "password_complexity": "密码不符合规则",
         "password_empty": "密码必须不为空",
         "password_mismatch": "确认密码不匹配",
         "policy_list_from_exists": "指定的名称已存在记录",
-        "policy_list_from_invalid": "记录格式非法",
+        "policy_list_from_invalid": "记录格式无效",
         "private_key_error": "私钥错误: %s",
-        "pushover_credentials_missing": "Pushover token或密钥缺失",
-        "pushover_key": "Pushover密钥格式错误",
-        "pushover_token": "Pushover token格式错误",
-        "quota_not_0_not_numeric": "配额必须为数值且 >= 0",
+        "pushover_credentials_missing": "Pushover token 或密钥缺失",
+        "pushover_key": "Pushover 密钥格式错误",
+        "pushover_token": "Pushover token 格式错误",
+        "quota_not_0_not_numeric": "配额必须为数字且 >= 0",
         "recipient_map_entry_exists": "收件人映射条目 \"%s\" 已存在",
         "redis_error": "Redis 错误: %s",
         "relayhost_invalid": "中继主机条目 %s 已存在",
         "release_send_failed": "消息不能被释放: %s",
-        "reset_f2b_regex": "暂时不能重置正则表达式过滤器,请重试或多等待几秒并重载网页。",
-        "resource_invalid": "资源名称 %s 非法",
-        "rl_timeframe": "频率限制时间数不正确",
-        "rspamd_ui_pw_length": "Rspamd UI密码需要为至少6字符长",
+        "reset_f2b_regex": "暂时不能重置正则表达式过滤器,请重试或在几秒后重载网页。",
+        "resource_invalid": "资源名称 %s 无效",
+        "rl_timeframe": "频率限制时间设置错误",
+        "rspamd_ui_pw_length": "Rspamd UI 密码至少为为6个字符",
         "script_empty": "脚本不能为空",
-        "sender_acl_invalid": "发件人ACL值 %s 非法",
-        "set_acl_failed": "设置ACL失败",
-        "settings_map_invalid": "设置规则非法,ID %s",
-        "sieve_error": "sieve解析器错误: %s",
-        "spam_learn_error": "垃圾邮件学习错误: %s",
+        "sender_acl_invalid": "发件人的 ACL 值 %s 无效",
+        "set_acl_failed": "设置 ACL 失败",
+        "settings_map_invalid": "设置规则 ID %s 无效",
+        "sieve_error": "Sieve 解析器错误: %s",
+        "spam_learn_error": "学习垃圾邮件错误: %s",
         "subject_empty": "主题必须不为空",
-        "target_domain_invalid": "目标域名 %s 非法",
+        "target_domain_invalid": "目标域名 %s 无效",
         "targetd_not_found": "未找到目标域名 %s",
         "targetd_relay_domain": "目标域名 %s 是中继域名",
         "temp_error": "临时错误",
         "text_empty": "文本必须不为空",
-        "tls_policy_map_dest_invalid": "策略目标非法",
-        "tls_policy_map_entry_exists": "TLS策略规则条目 \"%s\" 已存在",
-        "tls_policy_map_parameter_invalid": "策略参数非法",
-        "totp_verification_failed": "TOTP认证失败",
+        "tfa_token_invalid": "TFA token 无效",
+        "tls_policy_map_dest_invalid": "策略目标无效",
+        "tls_policy_map_entry_exists": "TLS 策略规则条目 \"%s\" 已存在",
+        "tls_policy_map_parameter_invalid": "策略参数无效",
+        "totp_verification_failed": "TOTP 认证失败",
         "transport_dest_exists": "传输目标 \"%s\" 已存在",
-        "webauthn_verification_failed": "WebAuthn认证失败: %s",
+        "webauthn_verification_failed": "WebAuthn 认证失败: %s",
         "unknown": "发生未知错误",
-        "unknown_tfa_method": "未知TFA方法",
-        "unlimited_quota_acl": "ACL设置禁止了无限配额",
-        "username_invalid": "不能使用用户名 %s",
+        "unknown_tfa_method": "未知的 TFA 方法",
+        "unlimited_quota_acl": "ACL 设置禁止了无限配额",
+        "username_invalid": "用户名 %s 无法使用",
         "validity_missing": "请设置有效期",
         "value_missing": "请填入所有值",
-        "yotp_verification_failed": "Yubico OTP认证失败: %s"
+        "yotp_verification_failed": "Yubico OTP 认证失败: %s"
     },
     "debug": {
         "chart_this_server": "图表 (此服务器)",
         "containers_info": "容器信息",
         "disk_usage": "磁盘使用",
+        "docs": "文档",
         "external_logs": "外部日志",
         "history_all_servers": "历史 (所有服务器)",
         "in_memory_logs": "内存日志",
-        "jvm_memory_solr": "JVM内存使用",
-        "log_info": "<p>mailcow <b>内存日志</b> 收集于Redis列表中并且每分钟自动缩减到 LOG_LINES (%d) 以减少错误(Rowhammer)。\r\n  <br>内存日志不是为了持久化,所有使用内存日志的应用同时也会写入日志到Docker守护程序的默认日志驱动中。\r\n  <br>内存日志应该用于debug容器中的不明显问题。</p>\r\n  <p><b>外部日志</b> 通过相应应用提供的API收集。</p>\r\n  <p><b>静态日志</b> 大多为不写入日志到Dockerd但仍然需要被持久化的活动日志(API日志外的)。</p>",
-        "logs": "日志",
-        "restart_container": "重启",
-        "solr_dead": "Solr在启动中、已关闭或已停止运行",
-        "docs": "文档",
+        "jvm_memory_solr": "JVM 内存使用",
         "last_modified": "最后修改",
+        "log_info": "<p>Mailcow 的<b>内存日志</b>储存于 Redis 列表中,并且每分钟自动降低到 LOG_LINES (%d) 以减少错误。\r\n  <br>内存日志不是为了持久化储存的,所有使用内存日志的应用同时也会写入日志到 Docker 的守护进程的默认日志驱动中。\r\n  <br>内存日志应该用于分析 (Debug) 容器中不明显的问题。</p>\r\n  <p><b>外部日志</b>通过相应应用提供的 API 收集。</p>\r\n  <p><b>静态日志</b>大多数为不写入日志到 Docker ,但仍然需要被持久化的活动日志 (API 日志外的)。</p>",
+        "login_time": "时间",
+        "logs": "日志",
+        "online_users": "在线用户",
+        "restart_container": "重启",
+        "service": "服务",
         "size": "大小",
+        "solr_dead": "Solr 在启动中、已关闭或已停止",
+        "solr_status": "Solr 状态",
         "started_at": "开始于",
-        "solr_status": "Solr状态",
-        "uptime": "运行时间",
         "started_on": "启动于",
         "static_logs": "静态日志",
-        "system_containers": "系统和容器"
+        "success": "成功",
+        "system_containers": "系统和容器",
+        "uptime": "运行时间",
+        "username": "用户名"
     },
     "diagnostics": {
-        "cname_from_a": "虽然此值记录为 A/AAAA 类型,但只要此记录指向了正确的资源则该行为是被支持的",
-        "dns_records": "DNS记录",
-        "dns_records_24hours": "请注意DNS记录的更改可能需要24小时才可以使此页面的当前状态显示正确。此页为你提供了一个可以简单查看如何配置DNS记录和检查你的DNS记录是否正确的方式。",
+        "cname_from_a": "虽然此记录为 A/AAAA 类型,但只要此记录指向了正确的资源便可以被支持",
+        "dns_records": "DNS 记录",
+        "dns_records_24hours": "请注意 DNS 记录的更改可能需要24小时才可以使此页面的当前状态显示正确。此页面为你提供了一个可以便捷查询如何配置 DNS 记录以及检查你的 DNS 记录是否正确的方式。",
         "dns_records_data": "正确数据",
+        "dns_records_docs": "请同时也参考这个<a target=\"_blank\" href=\"https://mailcow.github.io/mailcow-dockerized-docs/prerequisite/prerequisite-dns/\">文档</a>.",
         "dns_records_name": "名称",
         "dns_records_status": "当前状态",
         "dns_records_type": "类型",
         "optional": "此记录是可选的。"
     },
     "edit": {
+        "acl": "ACL (许可)",
         "active": "启用",
+        "admin": "编辑管理员",
         "advanced_settings": "高级设置",
         "alias": "编辑别名",
-        "allow_from_smtp": "只允许这些IP使用<b>SMTP</b>",
-        "allow_from_smtp_info": "留空以允许所有发送者<br>IPv4/IPv6地址或网络",
+        "allow_from_smtp": "只允许这些 IP 使用 <b>SMTP</b>",
+        "allow_from_smtp_info": "留空以允许所有发送者。<br>IPv4/IPv6地址或网络",
         "allowed_protocols": "允许的协议",
         "app_name": "应用名称",
         "app_passwd": "应用密码",
-        "automap": "尝试自动映射文件夹 (如:\"已发送\", \"Sent\" => \"Sent\")",
+        "app_passwd_protocols": "应用密码允许的协议",
+        "automap": "将尝试自动映射文件夹 (例如将 \"已发送消息\" 和 \"已发送\" 均映射到 \"已发送\" 文件夹)",
         "backup_mx_options": "中继选项",
-        "bcc_dest_format": "BCC目标地址必须为合法的邮件地址",
-        "client_id": "客户端ID",
-        "client_secret": "客户端secret",
-        "comment_info": "私密评论对用户不可见,公开评论会给用户展示为鼠标悬停显示的提示",
-        "delete1": "完成后将源邮件删除",
-        "delete2": "删除目的邮箱中存在但源邮箱中不存在的邮件",
-        "delete2duplicates": "删除目的邮箱中的重复邮件",
+        "bcc_dest_format": "BCC 的目标必须是一个有效的电子邮箱地址。<br>如果你需要向多个地址发送副本,请创建一个别名并在此使用。",
+        "client_id": "客户端 ID",
+        "client_secret": "客户端 secret",
+        "comment_info": "私密评论对用户不可见,公开评论将会在鼠标悬停时作为用户提示显示",
+        "delete1": "在完成后删除源邮件",
+        "delete2": "删除在目标邮箱中存在但在源邮箱中不存在的邮件",
+        "delete2duplicates": "删除目标邮箱中的重复邮件",
         "delete_ays": "请确认删除。",
         "description": "描述",
-        "disable_login": "不允许登录 (仍然会接收邮件)",
+        "disable_login": "不允许登录 (但仍然会接收邮件)",
         "domain": "编辑域名",
         "domain_admin": "编辑域名管理员",
         "domain_quota": "域名配额",
@@ -493,70 +534,80 @@
         "dont_check_sender_acl": "为域名 %s (+ 域名别名) 关闭发件人检查",
         "edit_alias_domain": "编辑域名别名",
         "encryption": "加密",
-        "exclude": "排除对象 (正则表达式)",
+        "exclude": "排除对象 (Regex)",
         "extended_sender_acl": "外部发件人地址",
-        "extended_sender_acl_info": "如果可以的话请导入DKIM域名密钥。<br>\r\n  别忘记将此服务器添加到相应的SPF TXT中。<br>\r\n 当域名或域名别名被添加时,若其与此外部发件人地址交叠,则外部发件人地址会被移除。<br>\r\n  填入 @domain.tld 以允许作为 *@domain.tld 发送邮件。",
+        "extended_sender_acl_info": "当可用时请导入域名的 DKIM 密钥。<br>\r\n  请注意将此服务器添加到相应的 SPF TXT 记录中。<br>\r\n 当域名或域名别名被添加时,若其与此外部发件人地址交叠,则外部发件人地址将会被移除。<br>\r\n  填入 @domain.tld 以允许作为 *@domain.tld 发送邮件。",
         "force_pw_update": "在下一次登录时强制要求更新密码",
         "force_pw_update_info": "此用户只能登录到 %s。",
         "full_name": "全名",
         "gal": "全球地址簿",
-        "gal_info": "<b>全球地址簿</b>包含了域名下的所有对象,并且此行为不能被用户更改。如果关闭,用户的 空闲/繁忙 信息将不能在SOGo中显示。<b>重启SOGo以应用更改。</b>",
+        "gal_info": "<b>全球地址簿</b>包含了域名下的所有对象,并且此行为不能被用户更改。如果关闭,用户的 \"空闲/繁忙\" 的信息将不能在 SOGo 中显示。 <b>重启 SOGo 服务以应用更改。</b>",
         "generate": "生成",
         "grant_types": "授权类型",
         "hostname": "主机名",
         "inactive": "禁用",
         "kind": "类型",
+        "lookup_mx": "应当为一个正则表达式,用于匹配 MX 记录 (例如 <code>.*google\\.com</code> 将转发所有拥有以 google.com 结尾的 MX 记录的邮件)",
         "mailbox": "编辑邮箱",
-        "mailbox_quota_def": "默认邮箱配额",
-        "max_aliases": "最大允许地址别名数",
-        "max_mailboxes": "最大允许邮箱数",
+        "mailbox_quota_def": "邮箱默认配额",
+        "mailbox_relayhost_info": "只适用于邮箱和邮箱别名,不会覆盖域名的中继主机。",
+        "max_aliases": "最大允许的地址别名数",
+        "max_mailboxes": "最大允许的邮箱数",
         "max_quota": "每个邮箱的最大配额 (MiB)",
-        "maxage": "从远程拉取消息的最大消息年龄限制<br><small>(0表示忽略)</small>",
-        "maxbytespersecond": "最大速率 (Bytes/s) <br><small>(0表示不限)</small>",
-        "mbox_rl_info": "此频率限制应用于SASL登录名,它会匹配邮件的\"来自\"地址。邮箱的频率限制设置会覆盖域名的频率限制值设置。",
+        "maxage": "从远程拉取消息的最大时间间隔限制<br><small>(0表示忽略)</small>",
+        "maxbytespersecond": "最大速率 (Bytes/s) <br><small>(0表示无限制)</small>",
+        "mbox_rl_info": "此频率限制应用于 SASL 登录名,它会匹配邮件的 \"from\" 地址。邮箱的频率限制设置会覆盖域名的频率限制值设置。",
         "mins_interval": "轮询间隔 (分钟)",
         "multiple_bookings": "登记限制",
+        "none_inherit": "无/继承",
         "nexthop": "下一跳",
         "password": "密码",
-        "password_repeat": "确认密码 (重复输入)",
+        "password_repeat": "确认密码 (重复)",
         "previous": "上一页",
         "private_comment": "私密评论",
         "public_comment": "公开评论",
-        "pushover_evaluate_x_prio": "加速高优先级邮件 [<code>X-Priority: 1</code>]",
+        "pushover": "Pushover",
+        "pushover_evaluate_x_prio": "优先响应高优先级邮件 [<code>X-Priority: 1</code>]",
         "pushover_info": "推送通知设置会应用到所有递送到 <b>%s</b> (包括其别名) 的非垃圾邮件。",
         "pushover_only_x_prio": "只为高优先级邮件开启 [<code>X-Priority: 1</code>]",
-        "pushover_sender_array": "只为以下发件人邮箱地址开启 <small>(英文逗号分隔)</small>",
+        "pushover_sender_array": "只为以下发件人邮箱地址开启 <small>(存在多个地址时使用英文逗号分隔)</small>",
         "pushover_sender_regex": "也可以使用正则表达式过滤发件人",
         "pushover_text": "通知文本",
         "pushover_title": "通知标题",
-        "pushover_vars": "如果没有定义发件人过滤器则会为所有邮件开启通知推送。<br>正则表达式过滤器可以和普通过滤器分别被定义,并且会依序应用,而不是覆盖另一个。<br>在文本和标题中可用的变量 (请注意数据保护条例)",
+        "pushover_vars": "如果没有定义发件人过滤器则会为所有的邮件开启通知推送。<br>正则表达式过滤器可以和普通过滤器一同使用,并且会按顺序被使用,而不是被覆盖。<br>在文本和标题中可用的变量 (请注意数据保护)",
         "pushover_verify": "校验凭证",
         "quota_mb": "配额 (MiB)",
+        "quota_warning_bcc": "BCC 配额警告",
+        "quota_warning_bcc_info": "警告将作为单独的副本发送至以下的收件人。主题将以放置在括号内的用户名做为后缀结尾,例如,<code>Quota warning (user@example.com)</code>。",
+        "ratelimit": "频率限制",
         "redirect_uri": "重定向/回调 URL",
         "relay_all": "中继所有收件人",
-        "relay_all_info": "↪ 如果<b>不</b>选择中继所有,你将需要为每个应该中继的邮件添加一个 (\"盲\") 邮箱。",
+        "relay_all_info": "↪ 如果<b>不</b>选择中继所有收件人,你将需要为每个应该中继的邮件添加一个(\"虚拟\")邮箱。",
         "relay_domain": "中继这个域名",
-        "relay_transport_info": "<div class=\"label label-info\"></div> 你可以为此域名定义传输规则以自定义发件目标主机,否则遵照MX记录发送邮件。",
-        "relay_unknown_only": "只为不存在的邮箱地址中继。已存在的邮箱地址则在本地递送。",
+        "relay_transport_info": "<div class=\"label label-info\">注意</div> 你可以为此域名自定义传输规则来指定发件目标主机,否则将遵照 MX 记录发送邮件。",
+        "relay_unknown_only": "只为不存在的邮箱地址中继。已存在的邮箱地址将在本地发送。",
         "relayhost": "中继传输",
         "remove": "删除",
-        "resource": "日历资源",
+        "resource": "资源",
         "save": "保存更改",
         "scope": "范围",
         "sender_acl": "允许发送为",
         "sender_acl_disabled": "<span class=\"label label-danger\">发件人检查已关闭</span>",
-        "sender_acl_info": "如果允许邮箱用户A作为邮箱用户B发送邮件,发件人的地址不会在SOGo中\"来自\"区域自动地作为下拉可选项显示。<br>\r\n 邮箱用户B需要添加授权以允许邮箱用户A选择B的地址作为发件人;授权方法为,在SOGo中点击左上方邮箱地址右边的菜单按钮(三个点)并授权。",
+        "sender_acl_info": "如果允许邮箱用户 A 作为邮箱用户 B 发送邮件,发件人的地址不会在 SOGo 中的 \"from\" 区域中作为下拉项显示。<br>\r\n 邮箱用户 B 需要添加授权以允许邮箱用户 A 选择 B 的地址作为发件人;授权方法为,在 SOGo 中点击左上方邮箱地址右边的菜单按钮 (三个点) 并授权。",
         "sieve_desc": "简短描述",
         "sieve_type": "过滤器类型",
-        "skipcrossduplicates": "跳过其他文件夹中已存在的邮件(保留先存在的邮件)",
-        "sogo_visible": "SOGo别名显示",
-        "sogo_visible_info": "此设置只影响SOGo上的可显示对象(指向本地邮箱的共享或非共享别名地址)。如果设为隐藏,别名地址不会作为下拉可选发件人项显示。",
+        "skipcrossduplicates": "跳过其他文件夹中已存在的邮件(保留已经存在的邮件)",
+        "sogo_access": "允许直接登录 SOGo",
+        "sogo_access_info": "在邮箱的用户界面内的单点登录仍然有效。这一设置既不影响对所有其他服务的访问,也不删除或改变用户现有的 SOGo 的配置文件。",
+        "sogo_visible": "SOGo 显示的别名",
+        "sogo_visible_info": "此设置只影响 SOGo 上可显示的对象 (指向本地邮箱的共享或非共享别名地址)。如果设置为隐藏,则别名地址不会作为可选发件人的下拉项显示。",
         "spam_alias": "添加或更改临时别名地址",
+        "spam_filter": "垃圾邮件过滤器",
         "spam_policy": "将项目添加到白/黑名单或从其中移除",
         "spam_score": "自定义垃圾邮件分数",
-        "subfolder2": "同步到目标邮箱子文件夹<br><small>(留空表示不使用子文件夹)</small>",
+        "subfolder2": "同步到目标邮箱的子文件夹<br><small>(留空表示不使用子文件夹)</small>",
         "syncjob": "编辑同步任务",
-        "target_address": "目标地址 <small>(英文逗号分隔多个地址)</small>",
+        "target_address": "目标地址 <small>(存在多个地址时使用英文逗号分隔)</small>",
         "target_domain": "目标域名",
         "timeout1": "远程主机连接超时时间",
         "timeout2": "本地主机连接超时时间",
@@ -565,18 +616,35 @@
         "username": "用户名",
         "validate_save": "验证并保存"
     },
+    "fido2": {
+        "confirm": "确认",
+        "fido2_auth": "使用FIDO2登录",
+        "fido2_success": "已注册的设备",
+        "fido2_validation_failed": "验证失败",
+        "fn": "别名",
+        "known_ids": "已注册的 ID",
+        "none": "禁用",
+        "register_status": "注册状态",
+        "rename": "重命名",
+        "set_fido2": "重新注册 FIDO2 设备",
+        "set_fido2_touchid": "在 Apple M1 上使用 Touch ID 注册",
+        "set_fn": "设置别名",
+        "start_fido2_validation": "开始 FIDO2 验证"
+    },
     "footer": {
         "cancel": "取消",
         "confirm_delete": "确认删除",
         "delete_now": "立即删除",
-        "delete_these_items": "请确认对以下对象id的更改",
+        "delete_these_items": "请确认对以下对象 ID 的更改",
+        "hibp_check": "使用 haveibeenpwned.com 网站检查密码",
         "hibp_nok": "匹配到密码!存在潜在的使用危险!",
-        "hibp_ok": "未匹配到密码。",
+        "hibp_ok": "未匹配到密码",
         "loading": "请等待...",
+        "nothing_selected": "未选择",
         "restart_container": "重启容器",
-        "restart_container_info": "<b>重要:</b> 可能需要一些时间以完整地重启容器,请等待重启完成。",
+        "restart_container_info": "<b>重要:</b> 完整的重启容器可能需要花费一些时间,请耐心等待重启完成。",
         "restart_now": "立即重启",
-        "restarting_container": "容器重启中,这可能需要一些时间"
+        "restarting_container": "容器重启中,这可能需要花费一些时间"
     },
     "header": {
         "administration": "配置和管理",
@@ -585,19 +653,21 @@
         "mailboxes": "邮箱设置",
         "mailcow_settings": "配置",
         "quarantine": "隔离",
-        "restart_netfilter": "重启netfilter",
-        "restart_sogo": "重启SOGo",
+        "restart_netfilter": "重启 netfilter",
+        "restart_sogo": "重启 SOGo",
         "user_settings": "用户设置"
     },
     "info": {
-        "awaiting_tfa_confirmation": "等待TFA确认",
+        "awaiting_tfa_confirmation": "等待 TFA 确认",
         "no_action": "没有可适用的操作",
-        "session_expires": "你的会话会在15秒后过期"
+        "session_expires": "你的会话将会在15秒之后过期"
     },
     "login": {
-        "delayed": "请在%s秒后重新登录。",
+        "delayed": "请在 %s 秒后重新登录。",
+        "fido2_webauthn": "使用 FIDO2/WebAuthn 登录",
         "login": "登录",
-        "mobileconfig_info": "请用邮箱用户登录以下载Apple连接描述文件。",
+        "mobileconfig_info": "请使用邮箱用户登录以下载 Apple 连接描述文件。",
+        "other_logins": "Key 登录",
         "password": "密码",
         "username": "用户名"
     },
@@ -607,7 +677,8 @@
         "active": "启用",
         "add": "添加",
         "add_alias": "添加别名",
-        "add_bcc_entry": "添加BCC映射",
+        "add_alias_expand": "在域名别名上拓展别名",
+        "add_bcc_entry": "添加 BCC 映射",
         "add_domain": "添加域名",
         "add_domain_alias": "添加域名别名",
         "add_domain_record_first": "请先添加一个域名",
@@ -615,35 +686,37 @@
         "add_mailbox": "添加邮箱",
         "add_recipient_map_entry": "添加收件人映射",
         "add_resource": "添加资源",
-        "add_tls_policy_map": "添加TLS策略规则",
+        "add_tls_policy_map": "添加 TLS 策略规则",
         "address_rewriting": "地址重写",
         "alias": "别名",
-        "alias_domain_alias_hint": "邮箱别名<b>不会</b>自动应用到域名别名。邮箱别名地址 <code>my-alias@domain</code> <b>不会</b> 应用到 <code>my-alias@alias-domain</code> (假设 \"alias-domain\" 是 \"domain\" 的域名别名)。<br>若需要将邮件转发到外部邮箱,请使用sieve过滤器 (查看标签页 \"过滤器\" 或者使用 SOGo -> 转发器) 。",
-        "alias_domain_backupmx": "域名别名在中继域名下不启用",
+        "alias_domain_alias_hint": "邮箱别名<b>不会</b>自动应用到域名别名。邮箱别名地址 <code>my-alias@domain</code> <b>不会</b> 应用到 <code>my-alias@alias-domain</code> (假设 \"alias-domain\" 是 \"domain\" 的域名别名)。<br>若需要将邮件转发到外部邮箱,请使用 sieve 过滤器 (查看标签页 \"过滤器\" 或者使用 SOGo -> 转发器) 。",
+        "alias_domain_backupmx": "域名别名在中继域名下不会启用",
         "aliases": "别名",
-        "allow_from_smtp": "只允许这些IP使用<b>SMTP</b>",
-        "allow_from_smtp_info": "留空以允许所有发送者<br>IPv4/IPv6地址或网络",
-        "allowed_protocols": "允许的协议",
+        "all_domains": "全部域名",
+        "allow_from_smtp": "只允许这些 IP 使用 <b>SMTP</b>",
+        "allow_from_smtp_info": "留空以允许所有发送者,<br>IPv4/IPv6地址或网络",
+        "allowed_protocols": "允许用户直接访问的协议 (不会影响应用的密码协议)",
         "backup_mx": "中继域名",
         "bcc": "BCC",
-        "bcc_destination": "BCC目标地址",
-        "bcc_destinations": "BCC目标地址",
-        "bcc_info": "BCC映射用于静默地将邮件转发到另一个邮箱地址。当目标地址为本地地址时则会添加一个收件人映射条目,同发件人映射。<br/>\r\n 递送失败时不会通知本地目标地址。",
+        "bcc_destination": "BCC 目标地址",
+        "bcc_destinations": "BCC 目标地址",
+        "bcc_info": "BCC 映射用于静默地将邮件转发到另一个邮箱地址。当目标地址为本地地址时则会添加一个收件人映射条目,与发件人映射相同。<br/>\r\n 递送失败时不会通知本地目标地址。",
         "bcc_local_dest": "本地目标地址",
-        "bcc_map": "BCC映射",
-        "bcc_map_type": "BCC类型",
-        "bcc_maps": "BCC映射",
+        "bcc_map": "BCC 映射",
+        "bcc_map_type": "BCC 类型",
+        "bcc_maps": "BCC 映射",
         "bcc_rcpt_map": "收件人映射",
         "bcc_sender_map": "发件人映射",
         "bcc_to_rcpt": "切换到收件人映射",
         "bcc_to_sender": "切换到发件人映射",
-        "bcc_type": "BCC类型",
+        "bcc_type": "BCC 类型",
         "booking_null": "永远显示为空闲",
-        "booking_0_short": "永远空闲",
+        "booking_0_short": "空闲限制",
         "booking_custom": "严格限制登记数",
         "booking_custom_short": "严格限制",
-        "booking_ltnull": "不限制登记数,但会在被登记后显示为繁忙",
+        "booking_ltnull": "不会限制登记数,但会在被登记后显示为繁忙",
         "booking_lt0_short": "宽松限制",
+        "catch_all": "接收所有",
         "daily": "每天",
         "deactivate": "禁用",
         "description": "描述",
@@ -660,21 +733,24 @@
         "excludes": "除了",
         "filter_table": "筛选表格",
         "filters": "过滤器",
-        "fname": "全名",
+        "fname": "全称",
+        "goto_ham": "学习为<b>非垃圾邮件</b>",
+        "goto_spam": "学习为<b>垃圾邮件</b>",
         "hourly": "每小时",
         "in_use": "使用数 (%)",
         "inactive": "禁用",
         "insert_preset": "插入示例预设 \"%s\"",
         "kind": "类型",
-        "last_mail_login": "最后的邮箱登录",
-        "last_run": "最后运行",
+        "last_mail_login": "最后一次邮箱登录",
+        "last_pw_change": "最后一次密码修改",
+        "last_run": "最后一次运行",
         "last_run_reset": "下一次运行",
         "mailbox": "邮箱",
+        "mailbox_defaults": "默认设置",
+        "mailbox_defaults_info": "调整新邮箱的默认设置",
         "mailbox_defquota": "默认邮箱大小",
         "mailbox_quota": "最大邮箱大小",
         "mailboxes": "邮箱",
-        "mailbox_defaults": "默认设置",
-        "mailbox_defaults_info": "配置新邮箱的默认设置",
         "mins_interval": "间隔 (分钟)",
         "msg_num": "消息 #",
         "multiple_bookings": "登记限制",
@@ -682,69 +758,85 @@
         "no": "&#10005;",
         "no_record": "没有找到对象 %s 的记录",
         "no_record_single": "没有记录",
+        "open_logs": "打开日志",
         "owner": "所有者",
         "private_comment": "私密评论",
         "public_comment": "公开评论",
+        "q_add_header": "当移动到垃圾邮件文件夹时",
+        "q_all": " 当移动到垃圾邮件文件夹并被拒绝接收时",
+        "q_reject": "拒绝接收时",
+        "quarantine_category": "隔离通知类型",
         "quarantine_notification": "隔离通知",
         "quick_actions": "操作",
+        "recipient": "收件人",
         "recipient_map": "收件人映射",
-        "recipient_map_info": "收件人映射用于在邮件被递送前替换收件人地址。",
+        "recipient_map_info": "收件人映射用于在邮件被发送前替换收件人的地址。",
         "recipient_map_new": "新收件人",
-        "recipient_map_new_info": "新收件人必须为合法的邮件地址",
+        "recipient_map_new_info": "新收件人必须为合法的邮箱地址",
         "recipient_map_old": "原收件人",
-        "recipient_map_old_info": "原收件人必须为合法的邮件地址",
+        "recipient_map_old_info": "原收件人必须为合法的邮箱地址",
         "recipient_maps": "收件人映射",
         "remove": "删除",
-        "resources": "日历资源",
+        "resources": "资源",
         "running": "运行中",
-        "set_postfilter": "标记为postfilter",
-        "set_prefilter": "标记为prefilter",
-        "sieve_info": "你可以为每个用户存储多个过滤器,但只能同时启用一个prefilter和一个postfilter。<br>\r\n过滤器将按列表中的顺序依次执行,下一个脚本不会因为上一个脚本失败或\"keep;\"而停止运行。更改全局sieve脚本会重启Dovecot。<br><br>全局sieve prefilter → prefilter → 用户脚本 → postfilter → 全局sieve postfilter",
-        "sieve_preset_1": "丢弃含有潜在危险文件格式的邮箱",
+       "sender": "发件人",
+        "set_postfilter": "标记为 postfilter",
+        "set_prefilter": "标记为 prefilter",
+        "sieve_info": "你可以为每个用户存储多个过滤器,但只能同时启用一个 prefilter 和一个 postfilter 。<br>\r\n过滤器将按列表中的顺序依次执行,下一个脚本不会因为上一个脚本运行失败或保留运行而停止运行。更改全局 sieve 脚本会重启 Dovecot。<br><br>全局 sieve prefilter &#8226; prefilter &#8226; 用户脚本 &#8226; postfilter &#8226; 全局 sieve postfilter",
+        "sieve_preset_1": "丢弃包含有潜在危险文件格式的邮箱",
         "sieve_preset_2": "标记来至指定发件人的邮件为已读",
-        "sieve_preset_3": "静默删除,并停止继续运行sieve脚本",
-        "sieve_preset_4": "移动到收件箱,并停止继续运行sieve脚本",
+        "sieve_preset_3": "静默删除,并停止继续运行 sieve 脚本",
+        "sieve_preset_4": "移动到收件箱,并停止继续运行 sieve 脚本",
         "sieve_preset_5": "自动回复 (休假)",
-        "sieve_preset_6": "拒绝邮件并反馈",
-        "sieve_preset_7": "重定向邮件并保留/删除",
+        "sieve_preset_6": "拒绝接收邮件并通知",
+        "sieve_preset_7": "重定向邮件并保留或删除",
         "sieve_preset_8": "删除发件人发送给自己别名地址的邮件",
-        "sieve_preset_header": "请看下方的示例预设。 查看 <a href=\"https://en.wikipedia.org/wiki/Sieve_(mail_filtering_language)\" target=\"_blank\">Wikipedia</a> 以了解更多细节。",
-        "sogo_visible": "SOGo别名显示",
-        "sogo_visible_n": "在SOGo中隐藏别名",
-        "sogo_visible_y": "在SOGo中显示别名",
+        "sieve_preset_header": "请看下方的示例预设。 查看 <a href=\"https://en.wikipedia.org/wiki/Sieve_(mail_filtering_language)\" target=\"_blank\">Sieve Wikipedia 页面 (英文)</a>以了解更多细节。",
+        "sogo_visible": "SOGo 别名显示",
+        "sogo_visible_n": "在 SOGo 中隐藏别名",
+        "sogo_visible_y": "在 SOGo 中显示别名",
         "spam_aliases": "临时别名",
         "stats": "统计",
         "status": "状态",
         "sync_jobs": "同步任务",
+        "syncjob_check_log": "检查日志",
+        "syncjob_last_run_result": "最后一次运行结果",
+        "syncjob_EX_OK": "成功",
+        "syncjob_EXIT_CONNECTION_FAILURE": "连接问题",
+        "syncjob_EXIT_TLS_FAILURE": "加密连接问题",
+        "syncjob_EXIT_AUTHENTICATION_FAILURE": "身份认证问题",
+        "syncjob_EXIT_OVERQUOTA": "目标邮箱配额已满",
+        "syncjob_EXIT_CONNECTION_FAILURE_HOST1": "无法连接到远程服务器",
+        "syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "用户名或密码错误",
         "table_size": "表格尺寸",
         "table_size_show_n": "显示 %s 个项目",
         "target_address": "目标地址",
         "target_domain": "目标域名",
-        "tls_enforce_in": "强制入站TLS",
-        "tls_enforce_out": "强制出站TLS",
+        "tls_enforce_in": "强制入站使用 TLS",
+        "tls_enforce_out": "强制出站使用 TLS",
         "tls_map_dest": "目标",
         "tls_map_dest_info": "示例: example.org, .example.org, [mail.example.org]:25",
         "tls_map_parameters": "参数",
-        "tls_map_parameters_info": "留空或填入参数,比如: protocols=!SSLv2 ciphers=medium exclude=3DES",
+        "tls_map_parameters_info": "留空或填入相关参数,例如: protocols=!SSLv2 ciphers=medium exclude=3DES",
         "tls_map_policy": "策略",
-        "tls_policy_maps": "TLS策略规则",
-        "tls_policy_maps_info": "此策略规则覆盖用户的出站TLS策略设置。<br>\r\n  查看 <a href=\"http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps\" target=\"_blank\">\"smtp_tls_policy_maps\"文档</a> 以了解更多细节。",
-        "tls_policy_maps_enforced_tls": "这些策略同时会影响邮箱用户的出站TLS连接行为。如果在下方没有任何策略,则用户会应用 <code>smtp_tls_mandatory_protocols</code> 和 <code>smtp_tls_mandatory_ciphers</code> 指定的默认值",
-        "tls_policy_maps_long": "出站TLS策略规则重写",
-        "toggle_all": "选择/取消所有",
+        "tls_policy_maps": "TLS 策略规则",
+        "tls_policy_maps_enforced_tls": "这些策略会同时影响邮箱用户的出站 TLS 连接行为。如果在下方没有任何策略,则用户会使用 <code>smtp_tls_mandatory_protocols</code> 和 <code>smtp_tls_mandatory_ciphers</code> 指定的默认值。",
+        "tls_policy_maps_info": "此策略规则会覆盖用户的出站 TLS 策略设置。<br>\r\n  查看 <a href=\"http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps\" target=\"_blank\">\"smtp_tls_policy_maps\" 文档</a>以了解更多细节。",
+        "tls_policy_maps_long": "重写出站 TLS 策略规则",
+        "toggle_all": "选择所有/取消所有",
         "username": "用户名",
         "waiting": "等待中",
         "weekly": "每周",
         "yes": "&#10003;"
     },
     "oauth2": {
-        "access_denied": "请作为邮箱所有者登录以使用OAuth2授权",
+        "access_denied": "请作为邮箱所有者登录以使用 OAuth2 授权",
         "authorize_app": "授权应用",
         "deny": "拒绝",
         "permit": "授权应用",
         "profile": "个人资料",
-        "profile_desc": "查看个人信息: 用户名,全面,创建时间,修改时间,启用状态",
-        "scope_ask_permission": "一个应用请求了以下权限"
+        "profile_desc": "查看个人信息: 用户名,全称,创建时间,修改时间,状态",
+        "scope_ask_permission": "应用请求了以下权限"
     },
     "quarantine": {
         "action": "操作",
@@ -752,61 +844,70 @@
         "check_hash": "搜索文件特征 @ VT",
         "confirm": "确认",
         "confirm_delete": "确认删除此元素。",
-        "danger": "危险性",
-        "deliver_inbox": "递送到收件箱",
-        "disabled_by_config": "当前系统设置关闭了隔离功能,请设置 \"每个邮箱保留隔离项目数\" 和 \"最大文件大小\" 以开启隔离。",
+        "danger": "危险等级",
+        "deliver_inbox": "发送到收件箱",
+        "disabled_by_config": "当前系统设置关闭了隔离功能,请通过设置 \"每个邮箱保留的隔离项目数\" 以及 \"最大文件大小\" 以开启隔离。",
         "download_eml": "下载 (.eml)",
         "empty": "结果为空",
-        "high_danger": "高危险",
+        "high_danger": "高危险等级",
         "info": "信息",
         "junk_folder": "垃圾箱",
-        "learn_spam_delete": "学习为垃圾并删除",
-        "low_danger": "低危险",
-        "medium_danger": "中危险",
-        "neutral_danger": "中性",
-        "notified": "已通知",
-        "qhandler_success": "成功向系统发送请求,现在你可以关闭窗口了。",
+        "learn_spam_delete": "学习为垃圾邮件并删除",
+        "low_danger": "低危险等级",
+        "medium_danger": "中危险等级",
+        "neutral_danger": "无危险等级",
+        "notified": "已发送通知",
+        "qhandler_success": "已成功向系统发送请求,现在你可以关闭这个窗口了。",
         "qid": "Rspamd QID",
-        "qinfo": "隔离系统会将被拒绝的邮件以及作为拷贝发送到垃圾箱的邮件保存到数据库中 (发件人<em>不</em>会知道)。\r\n  <br>\"学习为垃圾并删除\" 会根据贝叶斯定理将消息作为垃圾学习并计算其模糊特征以拒绝未来收到相似消息。\r\n  <br>请注意,取决于你的系统资源,学习多个消息可能会花费较长时间。<br>黑名单中项目会被隔离系统排除。",
+        "qinfo": "隔离系统会把已被拒绝接收的邮件以及作为拷贝发送到垃圾箱的邮件保存到数据库中 (发件人<em>不</em>会知道)。\r\n  <br>\"学习为垃圾并删除\" 会根据贝叶斯定理将消息作为垃圾学习并计算其模糊特征以拒绝未来收到相似消息。\r\n  <br>请注意,这取决于你的系统资源,学习多个消息可能会花费较长时间。<br>黑名单中项目会被隔离系统排除。",
         "qitem": "隔离项目",
         "quarantine": "隔离",
         "quick_actions": "操作",
-        "rcpt": "收件人",
-        "received": "已接收",
-        "rejected": "已拒绝",
-        "recipients": "收件人",
-        "refresh": "刷新",
-        "release": "释放",
-        "release_body": "我们已在此消息中将你的消息附为eml文件",
-        "release_subject": "存在潜在危险的隔离文件 %s",
-        "remove": "删除",
-        "rspamd_result": "Rspamd结果",
-        "sender": "发件人 (SMTP)",
-        "sender_header": "发件人 (\"From\" 头)",
-        "type": "类型",
-        "quick_release_link": "打开快速释放链接",
         "quick_delete_link": "打开快速删除链接",
         "quick_info_link": "打开详情链接",
+        "quick_release_link": "打开快速移除链接",
+        "rcpt": "收件人",
+        "received": "已接收",
+        "recipients": "收件人",
+        "refresh": "刷新",
+        "rejected": "已拒绝",
+        "release": "移除",
+        "release_body": "我们已在此消息中将你的消息作为 eml 附件文件",
+        "release_subject": "存在潜在危险的隔离文件 %s",
+        "remove": "删除",
+        "rewrite_subject": "重写主题",
+        "rspamd_result": "Rspamd 结果",
+        "sender": "发件人 (SMTP)",
+        "sender_header": "发件人 (\"From\" 头)",
+        "settings_info": "被隔离的元素的最大数目: %s<br>电子邮件的最大大小: %s MiB",
         "show_item": "显示项目",
-        "spam": "垃圾",
+        "spam": "垃邮件圾",
         "spam_score": "分数",
         "subj": "主题",
         "table_size": "表格尺寸",
         "table_size_show_n": "显示 %s 个项目",
-        "text_from_html_content": "内容 (已转换 html)",
+        "text_from_html_content": "内容 (已转换为 html)",
         "text_plain_content": "内容 (text/plain)",
-        "toggle_all": "选择/取消所有"
+        "toggle_all": "选择所有/取消所有",
+        "type": "类型"
+    },
+    "ratelimit": {
+      "disabled": "禁用",
+      "second": "msgs / 秒",
+      "minute": "msgs / 分钟",
+      "hour": "msgs / 小说",
+      "day": "msgs / 天"
     },
     "start": {
         "help": "显示/隐藏 帮助面板",
-        "imap_smtp_server_auth_info": "请使用你的完整邮箱地址并使用PLAIN(明文)认证方法。<br>\r\n你的登录数据会被服务端强制加密。",
-        "mailcow_apps_detail": "使用mailcow应用访问你的邮件、日历、联系人和更多。",
-        "mailcow_panel_detail": "<b>域名管理员</b> 可以创建、修改或删除邮箱胡别名,更改分配给其的域名并读取更多域名相关信息。<br>\r\n<b>邮箱用户</b> 可以创建临时别名 (垃圾邮件别名),更改他们的密码和垃圾过滤器设置。"
+        "imap_smtp_server_auth_info": "请使用你的完整邮箱地址并使用 PLAIN (明文) 认证方法。<br>\r\n你的登录数据会被服务端强制加密。",
+        "mailcow_apps_detail": "使用 Mailcow 应用访问你的邮件、日历、联系人以及更多内容。",
+        "mailcow_panel_detail": "<b>域名管理员</b>可以创建、修改或删除邮箱的别名,更改分配给用户的域名并读取更多域名相关信息。<br>\r\n<b>邮箱用户</b>可以创建临时别名 (垃圾邮件别名),更改密码以及设置垃圾邮件过滤器。"
     },
     "success": {
-        "acl_saved": "已保存对象 %s 的ACL",
+        "acl_saved": "已保存对象 %s 的 ACL 设置",
         "admin_added": "已添加管理员 %s",
-        "admin_api_modified": "已保存API更改",
+        "admin_api_modified": "已保存 API 的更改",
         "admin_modified": "已保存管理员更改",
         "admin_removed": "已删除管理员 %s",
         "alias_added": "已添加别名地址 %s (%d)",
@@ -817,95 +918,102 @@
         "aliasd_modified": "已保存域名别名 %s 更改",
         "app_links": "已保存应用链接更改",
         "app_passwd_added": "已添加新的应用密码",
-        "app_passwd_removed": "已删除应用密码,ID %s",
-        "bcc_deleted": "已删除BCC映射条目: %s",
-        "bcc_edited": "已编辑BCC映射条目 %s",
-        "bcc_saved": "已保存BCC映射条目",
+        "app_passwd_removed": "已删除应用密码 ID %s",
+        "bcc_deleted": "已删除 BCC 映射条目: %s",
+        "bcc_edited": "已编辑 BCC 映射条目 %s",
+        "bcc_saved": "已保存 BCC 映射条目",
         "db_init_complete": "数据库初始化完成",
-        "delete_filter": "已删除过滤器,ID %s",
+        "delete_filter": "已删除过滤器 ID %s",
         "delete_filters": "已删除过滤器: %s",
-        "deleted_syncjob": "已删除同步任务,ID %s",
+        "deleted_syncjob": "已删除同步任务 ID %s",
         "deleted_syncjobs": "已删除同步任务: %s",
-        "dkim_added": "已保存DKIM密钥 %s",
-        "dkim_duplicated": "已复制域名 %s 的DKIM密钥到 %s",
-        "dkim_removed": "已删除DKIM密钥 %s",
+        "dkim_added": "已保存 DKIM 密钥 %s",
+        "domain_add_dkim_available": "DKIM 密钥已经存在",
+        "dkim_duplicated": "已复制域名 %s 的 DKIM 密钥到 %s",
+        "dkim_removed": "已删除 DKIM 密钥 %s",
         "domain_added": "已添加域名 %s",
         "domain_admin_added": "已添加域名管理员 %s",
         "domain_admin_modified": "已保存域名管理员 %s 更改",
         "domain_admin_removed": "已删除域名管理员 %s",
-        "domain_modified": "已保存域名 %s 更改",
+        "domain_modified": "已保存域名 %s 的更改",
         "domain_removed": "已删除域名 %s",
-        "dovecot_restart_success": "Dovecot重启成功",
-        "eas_reset": "已重置用户 %s 的ActiveSync设备",
-        "f2b_modified": "已保存Fail2ban参数更改",
+        "dovecot_restart_success": "Dovecot 重新启动成功",
+        "eas_reset": "已重置用户 %s 的 ActiveSync 设备",
+        "f2b_modified": "已保存 Fail2ban 参数的更改",
         "forwarding_host_added": "已添加转发主机 %s",
         "forwarding_host_removed": "已删除转发主机 %s",
         "global_filter_written": "成功将过滤器写入到文件",
         "hash_deleted": "已删除特征",
         "item_deleted": "成功删除项目 %s",
-        "item_released": "已释放项目 %s",
+        "item_released": "已移除项目 %s",
         "items_deleted": "成功删除项目 %s",
-        "items_released": "已释放选中的项目",
-        "learned_ham": "成功学习ID %s为非垃圾",
+        "items_released": "已移除选中的项目",
+        "learned_ham": "成功学习 ID %s 为非垃圾邮件",
         "license_modified": "已保存许可证更改",
         "logged_in_as": "登录为 %s",
         "mailbox_added": "已添加邮箱 %s",
-        "mailbox_modified": "已保存邮箱 %s 更改",
+        "mailbox_modified": "已保存邮箱 %s 的更改",
         "mailbox_removed": "已删除邮箱 %s",
+        "nginx_reloaded": "Nginx 已重新启动",
         "object_modified": "已保存对象 %s 更改",
-        "pushover_settings_edited": "成功设置Pushover设置,请校验凭证",
-        "qlearn_spam": "消息 ID %s 已被学习为垃圾并被删除",
+        "password_policy_saved": "已成功保存密码规则",
+        "pushover_settings_edited": "已成功设置 Pushover,请重新校验凭证",
+        "qlearn_spam": "消息 ID %s 已被学习为垃圾邮件并被删除",
         "queue_command_success": "成功执行配额命令",
-        "recipient_map_entry_deleted": "已删除接收人映射,ID %s",
+        "recipient_map_entry_deleted": "已删除接收人映射 ID %s",
         "recipient_map_entry_saved": "已保存接收人映射条目 \"%s\"",
         "relayhost_added": "已添加中继主机 %s",
         "relayhost_removed": "已删除中继主机 %s",
-        "reset_main_logo": "重置为默认logo",
+        "reset_main_logo": "重置为默认 Logo",
         "resource_added": "已添加资源 %s",
-        "resource_modified": "已保存资源 %s 更改",
+        "resource_modified": "已保存资源 %s 的更改",
         "resource_removed": "已删除资源 %s",
         "rl_saved": "已保存 %s",
-        "rspamd_ui_pw_set": "成功设置Rspamd UI密码",
+        "rspamd_ui_pw_set": "成功设置 Rspamd UI 的密码",
         "saved_settings": "已保存设置",
         "settings_map_added": "已添加设置规则",
-        "settings_map_removed": "已删除设置规则,ID %s",
-        "sogo_profile_reset": "已重置用户 %s 的SOGo个人资料",
-        "tls_policy_map_entry_deleted": "已删除TLS策略规则,ID %s",
-        "tls_policy_map_entry_saved": "已保存TLS策略规则 \"%s\"",
-        "ui_texts": "已保存UI文本更改",
-        "upload_success": "成功上传文件",
-        "verified_totp_login": "TOTP登录验证成功",
-        "verified_webauthn_login": "WebAuthn登录验证成功",
-        "verified_yotp_login": "Yubico OTP登录验证成功"
+        "settings_map_removed": "已删除设置规则 ID %s",
+        "sogo_profile_reset": "已重置用户 %s 的 SOGo 个人资料",
+        "tls_policy_map_entry_deleted": "已删除 TLS 策略规则 ID %s",
+        "tls_policy_map_entry_saved": "已保存 TLS 策略规则 \"%s\"",
+        "ui_texts": "已保存 UI 文本更改",
+        "upload_success": "文件上传成功",
+        "verified_fido2_login": "FIDO2 登录验证成功",
+        "verified_totp_login": "TOTP 登录验证成功",
+        "verified_webauthn_login": "WebAuthn 登录验证成功",
+        "verified_yotp_login": "Yubico OTP 登录验证成功"
     },
     "tfa": {
-        "api_register": "%s 使用 Yubico Cloud API,请 <a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">在此</a> 为你的密钥获取API密钥",
+        "api_register": "%s 使用了 Yubico Cloud API,请<a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">在此</a>为你的密钥获取 API 密钥",
         "confirm": "确认",
-        "confirm_totp_token": "请输入生成的token以确认更改",
+        "confirm_totp_token": "请输入生成的验证码以确认更改",
         "delete_tfa": "关闭两步验证",
         "disable_tfa": "在下一次成功登录前关闭两步验证",
-        "enter_qr_code": "如果你的设备不能扫描QR码,输入此TOTP码",
-        "error_code": "错误码",
+        "enter_qr_code": "如果你的设备无法扫描 QR 码,请输入此 TOTP 码",
+        "error_code": "故障代码",
         "init_webauthn": "初始化中,请等待...",
-        "key_id": "你的YubiKey的标识",
-        "key_id_totp": "你的密钥的标识",
+        "key_id": "你的设备的标识符",
+        "key_id_totp": "你的密钥的名称",
         "none": "禁用",
-        "reload_retry": "- (如果一直出现错误,重启浏览器)",
-        "scan_qr_code": "请用你认证应用扫描或手动输入此码。",
+        "reload_retry": "- (如果一直出现错误,请尝试重启浏览器)",
+        "scan_qr_code": "请用你的认证应用扫描或手动输入 TOTP 码。",
         "select": "请选择",
-        "set_tfa": "设置两步验证方法",
+        "set_tfa": "启用两步验证方法",
         "start_webauthn_validation": "开始认证",
-        "tfa": "两步验证(2FA)",
-        "totp": "TOTP认证 (Google Authenticator、Authy等)",
-        "webauthn": "WebAuthn认证",
-        "waiting_usb_auth": "<i>等待USB设备...</i><br><br>现在请触碰你的WebAuthn USB设备上的按钮。",
-        "waiting_usb_register": "<i>等待USB设备...</i><br><br>请在上方输入你的密码并请触碰你的WebAuthn USB设备上的按钮以确认注册WebAuthn设备。",
-        "yubi_otp": "Yubico OTP认证"
+        "tfa": "两步验证 (2FA)",
+        "tfa_token_invalid": "TFA token 无效",
+        "totp": "TOTP 认证 (Google Authenticator、Authy 等)",
+        "u2f_deprecated": "似乎你的密钥是使用废弃的 U2F 方法获得的。我们将为停用你的两步验证并删除该密钥。",
+        "u2f_deprecated_important": "请在管理面板上使用新的 WebAuthn 方法获得你的密钥。",
+        "webauthn": "WebAuthn 认证",
+        "waiting_usb_auth": "<i>等待 USB 设备中...</i><br><br>现在请触碰你的 WebAuthn USB 设备上的按钮。",
+        "waiting_usb_register": "<i>等待 USB 设备中...</i><br><br>请在上方输入你的密码并请触碰你的 WebAuthn USB 设备上的按钮以确认注册该 WebAuthn 设备。",
+        "yubi_otp": "Yubico OTP 认证"
     },
     "user": {
         "action": "操作",
         "active": "启用",
-        "active_sieve": "启用的过滤器",
+        "active_sieve": "已启用的过滤器",
         "advanced_settings": "高级设置",
         "alias": "别名",
         "alias_create_random": "生成随机别名",
@@ -916,85 +1024,110 @@
         "alias_time_left": "剩余时间",
         "alias_valid_until": "有效至",
         "aliases_also_send_as": "同时允许发送为",
-        "aliases_send_as_all": "关闭发件人可访性检查的域名(别名)",
-        "app_hint": "应用密码是你登录 <b>IMAP 和 SMTP</b> 时的可选替代密码,用户名保持不变。<br>应用密码不作用于SOGo (包括 ActiveSync) ",
+        "aliases_send_as_all": "已关闭发件人可访性检查的域名和域名别名",
+        "app_hint": "应用密码是你登录 <b>IMAP 和 SMTP</b> 时的可选替代密码,用户名仍然保持不变。<br>应用密码不适用于 SOGo (包括 ActiveSync) ",
+        "allowed_protocols": "允许使用的协议",
         "app_name": "应用名称",
         "app_passwds": "应用密码",
-        "apple_connection_profile": "Apple连接描述文件",
-        "apple_connection_profile_complete": "此连接描述文件包括提供给Apple设备的IMAP和SMTP配置参数并包括CalDAV (日历) 和 CardDAV (联系人) 访问路径。",
-        "apple_connection_profile_mailonly": "此连接描述文件包括提供给Apple设备的IMAP和SMTP配置参数。",
+        "apple_connection_profile": "Apple 连接描述文件",
+        "apple_connection_profile_complete": "此连接描述文件包括提供给 Apple 设备的 IMAP 和 SMTP 配置参数,并会包括 CalDAV (日历) 和 CardDAV (联系人) 的访问路径。",
+        "apple_connection_profile_mailonly": "此连接描述文件包括提供给 Apple 设备的 IMAP 和 SMTP 配置参数。",
+        "apple_connection_profile_with_app_password": "一个新的应用程序密码将会被生成并添加到该配置文件中,因此在设备设置时不需要输入密码。请不要随意分享该文件,因为它包含你的邮箱的完全访问权限。",
         "change_password": "更改密码",
-        "client_configuration": "显示邮箱客户端和智能手机配置指南",
+        "change_password_hint_app_passwords": "你的账户有 {{number_of_app_passwords}} 个应用密码,这些密码将不会被更改。如果需要管理这些密码,请访问应用密码标签。",
+        "clear_recent_successful_connections": "清除成功匹配的连接",
+        "client_configuration": "显示邮箱客户端和智能手机的配置指南",
         "create_app_passwd": "添加应用密码",
         "create_syncjob": "添加同步任务",
+        "created_on": "添加于",
         "daily": "每日",
         "day": "日",
         "delete_ays": "请确认删除。",
         "direct_aliases": "直接别名",
-        "direct_aliases_desc": "垃圾邮件过滤和TLS策略会作用于直接别名。",
-        "eas_reset": "重置ActiveSync设备缓存",
-        "eas_reset_help": "在许多情况下,重置设备缓存可以帮助恢复错误的ActiveSync资料。<br><b>注意:</b> 所有元素会被重新下载!",
+        "direct_aliases_desc": "垃圾邮件过滤和 TLS 策略会作用于直接别名。",
+        "direct_protocol_access": "该邮箱用户可以<b>直接</b>从<b>外部</b>访问以下的协议和应用程序。该选项由你的管理员进行设置。并可以创建应用密码,以授予对个别协议和应用的访问权限。<br>\"登录到 Webmail\" 按钮提供到 SOGo 的单点登录方式,并且始终可用。",
+        "eas_reset": "重置 ActiveSync 设备缓存",
+        "eas_reset_help": "在许多情况下,重置设备缓存可以帮助恢复错误的 ActiveSync 资料。<br><b>注意:</b> 所有元素将会被重新下载!",
         "eas_reset_now": "立即重置",
         "edit": "编辑",
         "email": "邮件",
         "email_and_dav": "邮件、日历和联系人",
+        "empty": "结果为空",
         "encryption": "加密",
         "excludes": "排除",
         "expire_in": "过期于",
-        "force_pw_update": "你<b>必须</b>设置一个新密码以继续使用群件相关服务。",
+        "fido2_webauthn": "FIDO2/WebAuthn",
+        "force_pw_update": "你<b>必须</b>设置一个新密码才能继续使用群组的相关服务。",
+        "from": "从",
         "generate": "生成",
         "hour": "小时",
         "hourly": "每小时",
         "hours": "小时",
         "in_use": "已使用",
         "interval": "间隔",
-        "is_catch_all": "收取域名下所有邮件",
-        "last_mail_login": "最后邮箱登录",
-        "last_run": "最后运行",
+        "is_catch_all": "接收该域名下的所有邮件",
+        "last_mail_login": "最后一次邮箱登录",
+        "last_pw_change": "最后一次密码修改",
+        "last_run": "最后一次运行",
+        "last_ui_login": "最后一次 UI 登录信息",
         "loading": "加载中...",
+        "login_history": "登录历史",
+        "mailbox": "Mailbox",
         "mailbox_details": "邮箱详情",
+        "mailbox_general": "通用设置",
+        "mailbox_settings": "邮箱设置",
         "messages": "消息",
+        "month": "月",
+        "months": "月",
         "never": "从不",
         "new_password": "新密码",
         "new_password_repeat": "确认密码 (重复)",
-        "no_active_filter": "没有启用的过滤器",
-        "no_last_login": "没有最后UI登录信息",
+        "no_active_filter": "没有已启用的过滤器",
+        "no_last_login": "没有最后一次 UI 登录信息",
         "no_record": "没有记录",
+        "open_logs": "打开日志",
+        "open_webmail_sso": "登录到 Webmail",
         "password": "密码",
         "password_now": "当前密码 (确认更改)",
-        "password_repeat": "密码 (重复)",
-        "pushover_evaluate_x_prio": "加速高优先级邮件 [<code>X-Priority: 1</code>]",
+        "password_repeat": "确认密码 (重复)",
+        "pushover_evaluate_x_prio": "优先响应高优先级邮件 [<code>X-Priority: 1</code>]",
         "pushover_info": "推送通知设置会应用到所有递送到 <b>%s</b> (包括其别名) 的非垃圾邮件。",
         "pushover_only_x_prio": "只为高优先级邮件开启 [<code>X-Priority: 1</code>]",
-        "pushover_sender_array": "只为以下发件人邮箱地址开启 <small>(英文逗号分隔)</small>",
+        "pushover_sender_array": "只为以下发件人邮箱地址开启 <small>(存在多个地址时使用英文逗号分隔)</small>",
         "pushover_sender_regex": "也可以使用正则表达式过滤发件人",
         "pushover_text": "通知文本",
         "pushover_title": "通知标题",
-        "pushover_vars": "如果没有定义发件人过滤器则会为所有邮件开启通知推送。<br>正则表达式过滤器可以和普通过滤器分别被定义,并且会依序应用,而不是覆盖另一个。<br>在文本和标题中可用的变量 (请注意数据保护条例)",
+        "pushover_vars": "如果没有定义发件人过滤器则会为所有的邮件开启通知推送。<br>正则表达式过滤器可以和普通过滤器一同使用,并且会按顺序被使用,而不是被覆盖。<br>在文本和标题中可用的变量 (请注意数据保护)",
         "pushover_verify": "验证凭证",
+        "q_add_header": "垃圾邮件文件夹",
+        "q_all": "全部类别",
+        "q_reject": "拒绝接收",
+        "quarantine_category": "隔离通知类别",
+        "quarantine_category_info": "隔离通知类别\"拒绝接收\"包括所有被拒绝的邮件,而\"垃圾邮件文件夹\"将通知用户被放入垃圾邮件文件夹的邮件。",
         "quarantine_notification": "隔离通知",
-        "quarantine_notification_info": "一旦某通知已被发送,其会被标记为\"已通知\"且不会被再次发送。",
+        "quarantine_notification_info": "一但通知被发送,其会被标记为\"已通知\"且不会被再次发送。",
+        "recent_successful_connections": "成功匹配的连接",
         "remove": "删除",
         "running": "运行中",
         "save": "保存更改",
         "save_changes": "保存更改",
         "sender_acl_disabled": "<span class=\"label label-danger\">发件人检查已关闭</span>",
         "shared_aliases": "共享别名地址",
-        "shared_aliases_desc": "用户设置如垃圾过滤器和加密策略等不会应用到共享别名地址。共享别名地址只能应用域名级别的垃圾过滤器且只能被管理员修改。",
-        "show_sieve_filters": "显示启用的用户sieve过滤器",
-        "sogo_profile_reset": "重置SOGo个人资料",
-        "sogo_profile_reset_help": "此操作会不可恢复地删除用户SOGo个人资料并<b>删除所有联系人和日历数据</b>。",
+        "shared_aliases_desc": "用户设置的垃圾邮件过滤器和加密策略等不会应用到共享别名地址。共享别名地址只能应用域名级别的垃圾邮件过滤器,并且只能被管理员修改。",
+        "show_sieve_filters": "显示用户启用的 sieve 过滤器",
+        "sogo_profile_reset": "重置 SOGo 个人资料",
+        "sogo_profile_reset_help": "此操作会不可恢复地删除用户的 SOGo 个人资料并<b>删除所有联系人和日历数据</b>。",
         "sogo_profile_reset_now": "立即重置个人资料",
         "spam_aliases": "临时邮箱别名",
         "spam_score_reset": "重置为服务器默认值",
-        "spamfilter": "垃圾过滤器",
-        "spamfilter_behavior": "评分",
+        "spamfilter": "垃圾邮件过滤器",
+        "spamfilter_behavior": "分数",
         "spamfilter_bl": "黑名单",
-        "spamfilter_bl_desc": "黑名单中地址<b>总是会</b>被标记为垃圾邮件。被拒绝的邮件<b>不会</b>进入隔离。此处可以使用通配符\"*\"。此过滤器也会应用到直接别名(只指向一个目标邮箱),但不会应用到\"捕获所有\"别名和邮箱地址本身。",
+        "spamfilter_bl_desc": "黑名单中地址<b>总是会</b>被标记为垃圾邮件。被拒绝的邮件<b>不会</b>进入隔离区。此处可以使用通配符 \"*\"。此过滤器也会应用到直接别名 (只指向一个目标邮箱),但不会应用到\"接收所有\"别名和邮箱地址本身。",
         "spamfilter_default_score": "默认值",
-        "spamfilter_green": "绿色: 此消息不是垃圾",
-        "spamfilter_hint": "第一个值表示\"低垃圾分数\",第二个值表示\"高垃圾分数\"。",
-        "spamfilter_red": "红色: 此消息是垃圾并且会被服务器拒绝",
+        "spamfilter_green": "绿色: 此消息不是垃圾邮件",
+        "spamfilter_hint": "第一个值表示\"低垃圾邮件分数\",第二个值表示\"高垃圾邮件分数\"。",
+        "spamfilter_red": "红色: 此消息是垃圾邮件并且会被服务器拒收",
         "spamfilter_table_action": "操作",
         "spamfilter_table_add": "添加项目",
         "spamfilter_table_domain_policy": "n/a (域名策略)",
@@ -1002,40 +1135,53 @@
         "spamfilter_table_remove": "删除",
         "spamfilter_table_rule": "规则",
         "spamfilter_wl": "白名单",
-        "spamfilter_wl_desc": "白名单中地址<b>永远不会</b>被标记为垃圾邮件。此处可以使用通配符\"*\"。此过滤器也会应用到直接别名(只指向一个目标邮箱),但不会应用到\"捕获所有\"别名和邮箱地址本身。",
-        "spamfilter_yellow": "黄色: 此为垃圾消息,会被标记为垃圾并且移入垃圾文件夹",
+        "spamfilter_wl_desc": "白名单中地址<b>永远不会</b>被标记为垃圾邮件。此处可以使用通配符 \"*\"。此过滤器也会应用到直接别名 (只指向一个目标邮箱),但不会应用到\"接收所有\"别名和邮箱地址本身。",
+        "spamfilter_yellow": "黄色: 此为垃圾邮件,会被标记为垃圾邮件并且移入垃圾邮件文件夹",
         "status": "状态",
         "sync_jobs": "同步任务",
-        "tag_handling": "处理有标签的邮件",
-        "tag_help_example": "有标签的邮箱地址示例: me<b>+Facebook</b>@example.org",
-        "tag_help_explain": "置于子文件夹: 在INBOX(收件箱)下创建一个以标签名命名的子文件夹 (\"INBOX/Facebook\")。<br>\r\n置于主题: 标签名会被前置到邮件主题, 如: \"[Facebook] 我的新闻\"。",
+        "syncjob_check_log": "检查日志",
+        "syncjob_last_run_result": "最后一次运行结果",
+        "syncjob_EX_OK": "成功",
+        "syncjob_EXIT_CONNECTION_FAILURE": "连接问题",
+        "syncjob_EXIT_TLS_FAILURE": "加密连接问题",
+        "syncjob_EXIT_AUTHENTICATION_FAILURE": "身份认证问题",
+        "syncjob_EXIT_OVERQUOTA": "目标邮箱配额已满",
+        "syncjob_EXIT_CONNECTION_FAILURE_HOST1": "无法连接到远程服务器",
+        "syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "用户名或密码错误",
+        "tag_handling": "处理带有标签的邮件",
+        "tag_help_example": "带有标签的邮箱地址示例: me<b>+Facebook</b>@example.org",
+        "tag_help_explain": "置于子文件夹: 在 INBOX (收件箱) 下创建一个以标签名命名的子文件夹 (\"INBOX/Facebook\")。<br>\r\n置于主题: 标签名会被前置到邮件主题, 例如: \"[Facebook] My News\"。",
         "tag_in_none": "不处理",
         "tag_in_subfolder": "置于子文件夹",
         "tag_in_subject": "置于主题",
         "text": "文本",
         "title": "标题",
-        "tls_enforce_in": "强制入站TLS",
-        "tls_enforce_out": "强制出站TLS",
+        "tls_enforce_in": "强制入站使用 TLS",
+        "tls_enforce_out": "强制出站使用 TLS",
         "tls_policy": "加密策略",
-        "tls_policy_warning": "<strong>警告:</strong> 如果你决定强制加密邮箱传输,你有可能丢失邮件。<br>不支持加密的邮件系统将不能与此服务器交换邮件。<br>此选项会应用到你的主邮件地址(登录名)、域名别名对应的地址和<b>只指向此一个邮箱</b>(非共享)的别名地址。",
+        "tls_policy_warning": "<strong>警告:</strong> 如果你决定强制使用加密邮箱传输,你有可能丢失邮件。<br>不支持加密的邮件系统将无法与此服务器交换邮件。<br>此选项会应用到你的主邮箱地址 (登录名)、域名别名对应的地址和<b>只指向此一个邮箱</b> (非共享) 的别名地址。",
         "user_settings": "用户设置",
         "username": "用户名",
         "verify": "验证",
         "waiting": "等待中",
         "week": "周",
         "weekly": "每周",
-        "weeks": "周"
+        "weeks": "周",
+        "with_app_password": "包含应用密码",
+        "year": "年",
+        "years": "年"
     },
     "warning": {
-        "cannot_delete_self": "不能删除已登录用户",
-        "domain_added_sogo_failed": "域名已添加但是重启Dovecot失败,请检查日志。",
-        "dovecot_restart_failed": "Dovecot重启失败,请检查日志",
+        "cannot_delete_self": "不能删除已登录的用户",
+        "domain_added_sogo_failed": "域名已添加但是重启 Dovecot 失败,请检查相关日志。",
+        "dovecot_restart_failed": "Dovecot 重启失败,请检查相关日志",
         "fuzzy_learn_error": "模糊特征学习失败: %s",
         "hash_not_found": "找不到特征或已被删除",
-        "ip_invalid": "跳过的非法IP: %s",
-        "no_active_admin": "不能禁用最后一个启用的管理员",
-        "quota_exceeded_scope": "域名配额超出: 此域名下现在只能创建无限容量的邮箱。",
-        "session_token": "表单字段非法: 字段不匹配",
-        "session_ua": "表单字段非法: User-Agent校验错误"
+        "ip_invalid": "跳过的无效 IP: %s",
+        "is_not_primary_alias": "跳过的非主要别名 %s",
+        "no_active_admin": "不能禁用最后一个被启用的管理员",
+        "quota_exceeded_scope": "域名配额超标: 此域名下现在只能创建无限容量的邮箱。",
+        "session_token": "表单字段无效: Token 不匹配",
+        "session_ua": "表单字段无效: User-Agent 校验错误"
     }
 }

From e82f3b39755d6bc20ebd0fe5c316028bf7b8f1ea Mon Sep 17 00:00:00 2001
From: bluewalk <noreply@bluewalk.net>
Date: Thu, 17 Nov 2022 14:30:06 +0100
Subject: [PATCH 04/15] Added SENDER_ADDRESS and SENDER_NAME as variables for
 messages

---
 data/conf/rspamd/local.d/metadata_exporter.conf |  3 +--
 data/conf/rspamd/meta_exporter/pushover.php     | 11 +++++++++--
 data/web/templates/edit/mailbox.twig            |  2 +-
 data/web/templates/user/Pushover.twig           |  2 +-
 4 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/data/conf/rspamd/local.d/metadata_exporter.conf b/data/conf/rspamd/local.d/metadata_exporter.conf
index 47373d99..daaa79b4 100644
--- a/data/conf/rspamd/local.d/metadata_exporter.conf
+++ b/data/conf/rspamd/local.d/metadata_exporter.conf
@@ -16,8 +16,7 @@ rules {
     backend = "http";
     url = "http://nginx:9081/pushover.php";
     selector = "mailcow_rcpt";
-    # Only return msgid, do not parse the full message
-    formatter = "msgid";
+    formatter = "json";
     meta_headers = true;
   }
 }
diff --git a/data/conf/rspamd/meta_exporter/pushover.php b/data/conf/rspamd/meta_exporter/pushover.php
index a5e83343..974a282d 100644
--- a/data/conf/rspamd/meta_exporter/pushover.php
+++ b/data/conf/rspamd/meta_exporter/pushover.php
@@ -65,6 +65,13 @@ if (is_array($symbols_array)) {
   }
 }
 
+$json = json_decode(file_get_contents('php://input'));
+
+$sender_address = $json->header_from ;
+if (preg_match('/[a-zA-Z0-9.!#$%&’*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)/i', $sender, $matches))
+	$sender_address = $matches[0];
+$sender_name =  trim(str_replace('<' . $email . '>', '', $from));
+
 $rcpt_final_mailboxes = array();
 
 // Loop through all rcpts
@@ -229,9 +236,9 @@ foreach ($rcpt_final_mailboxes as $rcpt_final) {
     $post_fields = array(
       "token" => $api_data['token'],
       "user" => $api_data['key'],
-      "title" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}'), array($subject, $sender), $title)),
+      "title" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}'), array($subject, $sender, $sender_name, $sender_address), $title)),
       "priority" => $priority,
-      "message" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}'), array($subject, $sender), $text))
+      "message" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}'), array($subject, $sender, $sender_name, $sender_address), $text))
     );
     if ($attributes['evaluate_x_prio'] == "1" && $priority == 1) {
       $post_fields['expire'] = 600;
diff --git a/data/web/templates/edit/mailbox.twig b/data/web/templates/edit/mailbox.twig
index e1c3e883..d4154292 100644
--- a/data/web/templates/edit/mailbox.twig
+++ b/data/web/templates/edit/mailbox.twig
@@ -275,7 +275,7 @@
         </div>
         <div class="col-sm-10">
           <p class="help-block">{{ lang.user.pushover_info|format(mailbox)|raw }}</p>
-          <p class="help-block">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code></p>
+          <p class="help-block">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code></p>
           <div class="form-group">
             <div class="row">
               <div class="col-sm-6">
diff --git a/data/web/templates/user/Pushover.twig b/data/web/templates/user/Pushover.twig
index 096655cb..8a6755a8 100644
--- a/data/web/templates/user/Pushover.twig
+++ b/data/web/templates/user/Pushover.twig
@@ -9,7 +9,7 @@
       </div>
       <div class="col-sm-10">
         <p class="help-block">{{ lang.user.pushover_info|format(mailcow_cc_username)|raw }}</p>
-        <p class="help-block">{{ lang.user.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code></p>
+        <p class="help-block">{{ lang.user.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</p>
         <div class="form-group">
           <div class="row">
             <div class="col-sm-6">

From 65c74c75c74c1a626b8d8c60921a6dcb689e8f4a Mon Sep 17 00:00:00 2001
From: bluewalk <noreply@bluewalk.net>
Date: Thu, 17 Nov 2022 14:30:06 +0100
Subject: [PATCH 05/15] Added SENDER_ADDRESS and SENDER_NAME as variables for
 messages

---
 data/conf/rspamd/meta_exporter/pushover.php | 11 ++++---
 data/web/api/openapi.yaml                   |  5 ++++
 data/web/inc/functions.pushover.inc.php     |  4 ++-
 data/web/inc/init_db.inc.php                |  1 +
 data/web/lang/lang.en-gb.json               |  2 ++
 data/web/lang/lang.nl-nl.json               |  2 ++
 data/web/templates/edit/mailbox.twig        | 30 +++++++++++++++++++
 data/web/templates/user/Pushover.twig       | 32 ++++++++++++++++++++-
 8 files changed, 81 insertions(+), 6 deletions(-)

diff --git a/data/conf/rspamd/meta_exporter/pushover.php b/data/conf/rspamd/meta_exporter/pushover.php
index 974a282d..8db4d3d8 100644
--- a/data/conf/rspamd/meta_exporter/pushover.php
+++ b/data/conf/rspamd/meta_exporter/pushover.php
@@ -67,10 +67,12 @@ if (is_array($symbols_array)) {
 
 $json = json_decode(file_get_contents('php://input'));
 
-$sender_address = $json->header_from ;
-if (preg_match('/[a-zA-Z0-9.!#$%&’*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)/i', $sender, $matches))
+$sender_address = $json->header_from[0];
+$sender_name = '-';
+if (preg_match('/[a-zA-Z0-9.!#$%&’*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)/i', $sender_address, $matches)) {
 	$sender_address = $matches[0];
-$sender_name =  trim(str_replace('<' . $email . '>', '', $from));
+  $sender_name =  trim(str_replace('<' . $sender_address . '>', '', $json->header_from[0]));
+}
 
 $rcpt_final_mailboxes = array();
 
@@ -238,7 +240,8 @@ foreach ($rcpt_final_mailboxes as $rcpt_final) {
       "user" => $api_data['key'],
       "title" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}'), array($subject, $sender, $sender_name, $sender_address), $title)),
       "priority" => $priority,
-      "message" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}'), array($subject, $sender, $sender_name, $sender_address), $text))
+      "message" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}'), array($subject, $sender, $sender_name, $sender_address), $text)),
+      "sound" => $attributes['sound'] ?? "pushover"
     );
     if ($attributes['evaluate_x_prio'] == "1" && $priority == 1) {
       $post_fields['expire'] = 600;
diff --git a/data/web/api/openapi.yaml b/data/web/api/openapi.yaml
index c23380f1..6310aa58 100644
--- a/data/web/api/openapi.yaml
+++ b/data/web/api/openapi.yaml
@@ -3349,6 +3349,7 @@ paths:
                           evaluate_x_prio: "0"
                           key: 21e8918e1jksdjcpis712
                           only_x_prio: "0"
+                          sound: "pushover"
                           senders: ""
                           senders_regex: ""
                           text: ""
@@ -3392,6 +3393,7 @@ paths:
                   evaluate_x_prio: "0"
                   key: 21e8918e1jksdjcpis712
                   only_x_prio: "0"
+                  sound: "pushover"
                   senders: ""
                   senders_regex: ""
                   text: ""
@@ -3413,6 +3415,9 @@ paths:
                     only_x_prio:
                       description: Only send push for prio mails
                       type: number
+                    sound:
+                      description: Set notification sound
+                      type: string
                     senders:
                       description: Only send push for emails from these senders
                       type: string
diff --git a/data/web/inc/functions.pushover.inc.php b/data/web/inc/functions.pushover.inc.php
index 74e8bb1c..5393c0d5 100644
--- a/data/web/inc/functions.pushover.inc.php
+++ b/data/web/inc/functions.pushover.inc.php
@@ -51,6 +51,7 @@ function pushover($_action, $_data = null) {
           $active = (isset($_data['active'])) ? intval($_data['active']) : $is_now['active'];
           $evaluate_x_prio = (isset($_data['evaluate_x_prio'])) ? intval($_data['evaluate_x_prio']) : $is_now['evaluate_x_prio'];
           $only_x_prio = (isset($_data['only_x_prio'])) ? intval($_data['only_x_prio']) : $is_now['only_x_prio'];
+          $sound = (isset($_data['sound'])) ? $_data['sound'] : $is_now['sound'];
         }
         else {
           $_SESSION['return'][] = array(
@@ -101,7 +102,8 @@ function pushover($_action, $_data = null) {
         $po_attributes = json_encode(
           array(
             'evaluate_x_prio' => strval(intval($evaluate_x_prio)),
-            'only_x_prio' => strval(intval($only_x_prio))
+            'only_x_prio' => strval(intval($only_x_prio)),
+            'sound' => strval($sound)
           )
         );
         $stmt = $pdo->prepare("REPLACE INTO `pushover` (`username`, `key`, `attributes`, `senders_regex`, `senders`, `token`, `title`, `text`, `active`)
diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php
index b47bd5c2..48db1a62 100644
--- a/data/web/inc/init_db.inc.php
+++ b/data/web/inc/init_db.inc.php
@@ -1264,6 +1264,7 @@ function init_db_schema() {
     $pdo->query("UPDATE `pushover` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;");
     $pdo->query("UPDATE `pushover` SET `attributes` =  JSON_SET(`attributes`, '$.evaluate_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.evaluate_x_prio') IS NULL;");
     $pdo->query("UPDATE `pushover` SET `attributes` =  JSON_SET(`attributes`, '$.only_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.only_x_prio') IS NULL;");
+    $pdo->query("UPDATE `pushover` SET `attributes` =  JSON_SET(`attributes`, '$.sound', \"0\") WHERE JSON_VALUE(`attributes`, '$.sound') IS NULL;");
     // mailbox
     $pdo->query("UPDATE `mailbox` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;");
     $pdo->query("UPDATE `mailbox` SET `attributes` =  JSON_SET(`attributes`, '$.passwd_update', \"0\") WHERE JSON_VALUE(`attributes`, '$.passwd_update') IS NULL;");
diff --git a/data/web/lang/lang.en-gb.json b/data/web/lang/lang.en-gb.json
index 0a384071..260997de 100644
--- a/data/web/lang/lang.en-gb.json
+++ b/data/web/lang/lang.en-gb.json
@@ -574,6 +574,7 @@
         "pushover_sender_regex": "Consider the following sender regex",
         "pushover_text": "Notification text",
         "pushover_title": "Notification title",
+        "pushover_sound": "Sound",
         "pushover_vars": "When no sender filter is defined, all mails will be considered.<br>Regex filters as well as exact sender checks can be defined individually and will be considered sequentially. They do not depend on each other.<br>Useable variables for text and title (please take note of data protection policies)",
         "pushover_verify": "Verify credentials",
         "quota_mb": "Quota (MiB)",
@@ -1097,6 +1098,7 @@
         "pushover_sender_regex": "Match senders by the following regex",
         "pushover_text": "Notification text",
         "pushover_title": "Notification title",
+        "pushover_sound": "Sound",
         "pushover_vars": "When no sender filter is defined, all mails will be considered.<br>Regex filters as well as exact sender checks can be defined individually and will be considered sequentially. They do not depend on each other.<br>Useable variables for text and title (please take note of data protection policies)",
         "pushover_verify": "Verify credentials",
         "q_add_header": "Junk folder",
diff --git a/data/web/lang/lang.nl-nl.json b/data/web/lang/lang.nl-nl.json
index ecfee43d..af8e9834 100644
--- a/data/web/lang/lang.nl-nl.json
+++ b/data/web/lang/lang.nl-nl.json
@@ -536,6 +536,7 @@
         "pushover_sender_regex": "Uitsluitend een afzender met de volgende regex",
         "pushover_text": "Meldingstekst ({SUBJECT} zal worden vervangen door het onderwerp)",
         "pushover_title": "Meldingstitel",
+        "pushover_sound": "Geluid",
         "pushover_vars": "Wanneer er geen afzenders zijn uitgesloten zullen alle mails doorkomen.<br>Regex-filters en afzendercontroles kunnen individueel worden ingesteld en zullen in volgorde worden verwerkt. Ze zijn niet afhankelijk van elkaar.<br>Bruikbare variabelen voor tekst en titel (neem het gegevensbeschermingsbeleid in acht)",
         "pushover_verify": "Verifieer aanmeldingsgegevens",
         "quota_mb": "Quota (MiB)",
@@ -1002,6 +1003,7 @@
         "pushover_sender_regex": "Uitsluitend een afzender met de volgende regex",
         "pushover_text": "Meldingstekst ({SUBJECT} zal worden vervangen door het onderwerp)",
         "pushover_title": "Meldingstitel",
+        "pushover_sound": "Geluid",
         "pushover_vars": "Wanneer er geen afzenders zijn uitgesloten zullen alle mails doorkomen.<br>Regex-filters en afzendercontroles kunnen individueel worden ingesteld en zullen in volgorde worden verwerkt. Ze zijn niet afhankelijk van elkaar.<br>Bruikbare variabelen voor tekst en titel (let op het gegevensbeschermingsbeleid)",
         "pushover_verify": "Verifieer aanmeldingsgegevens",
         "q_add_header": "Spamfolder",
diff --git a/data/web/templates/edit/mailbox.twig b/data/web/templates/edit/mailbox.twig
index d4154292..f0154584 100644
--- a/data/web/templates/edit/mailbox.twig
+++ b/data/web/templates/edit/mailbox.twig
@@ -308,6 +308,36 @@
                   <input type="text" class="form-control" name="senders" value="{{ pushover_data.senders }}" placeholder="sender1@example.com, sender2@example.com">
                 </div>
               </div>
+              <div class="col-sm-12">
+                <div class="form-group">
+                  <label for="sound">{{ lang.edit.pushover_sound }}</label><br>
+                  <select name="sound" class="form-control">
+                    <option value="pushover"{% if pushover_data.attributes.sound == 'pushover' %} selected{% endif %}>Pushover (default)</option>
+                    <option value="bike"{% if pushover_data.attributes.sound == 'bike' %} selected{% endif %}>Bike</option>
+                    <option value="bugle"{% if pushover_data.attributes.sound == 'bugle' %} selected{% endif %}>Bugle</option>
+                    <option value="cashregister"{% if pushover_data.attributes.sound == 'cashregister' %} selected{% endif %}>Cash Register</option>
+                    <option value="classical"{% if pushover_data.attributes.sound == 'classical' %} selected{% endif %}>Classical</option>
+                    <option value="cosmic"{% if pushover_data.attributes.sound == 'cosmic' %} selected{% endif %}>Cosmic</option>
+                    <option value="falling"{% if pushover_data.attributes.sound == 'falling' %} selected{% endif %}>Falling</option>
+                    <option value="gamelan"{% if pushover_data.attributes.sound == 'gamelan' %} selected{% endif %}>Gamelan</option>
+                    <option value="incoming"{% if pushover_data.attributes.sound == 'incoming' %} selected{% endif %}>Incoming</option>
+                    <option value="intermission"{% if pushover_data.attributes.sound == 'intermission' %} selected{% endif %}>Intermission</option>
+                    <option value="magic"{% if pushover_data.attributes.sound == 'magic' %} selected{% endif %}>Magic</option>
+                    <option value="mechanical"{% if pushover_data.attributes.sound == 'mechanical' %} selected{% endif %}>Mechanical</option>
+                    <option value="pianobar"{% if pushover_data.attributes.sound == 'pianobar' %} selected{% endif %}>Piano Bar</option>
+                    <option value="siren"{% if pushover_data.attributes.sound == 'siren' %} selected{% endif %}>Siren</option>
+                    <option value="spacealarm"{% if pushover_data.attributes.sound == 'spacealarm' %} selected{% endif %}>Space Alarm</option>
+                    <option value="tugboat"{% if pushover_data.attributes.sound == 'tugboat' %} selected{% endif %}>Tug Boat</option>
+                    <option value="alien"{% if pushover_data.attributes.sound == 'alien' %} selected{% endif %}>Alien Alarm (long)</option>
+                    <option value="climb"{% if pushover_data.attributes.sound == 'climb' %} selected{% endif %}>Climb (long)</option>
+                    <option value="persistent"{% if pushover_data.attributes.sound == 'persistent' %} selected{% endif %}>Persistent (long)</option>
+                    <option value="echo"{% if pushover_data.attributes.sound == 'echo' %} selected{% endif %}>Pushover Echo (long)</option>
+                    <option value="updown"{% if pushover_data.attributes.sound == 'updown' %} selected{% endif %}>Up Down (long)</option>
+                    <option value="vibrate"{% if pushover_data.attributes.sound == 'vibrate' %} selected{% endif %}>Vibrate Only</option>
+                    <option value="none"{% if pushover_data.attributes.sound == 'none' %} selected{% endif %}> None (silent) </option>
+                  </select>
+                </div>
+              </div>
               <div class="col-sm-12">
                 <div class="checkbox">
                   <label><input type="checkbox" value="1" name="active"{% if pushover_data.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
diff --git a/data/web/templates/user/Pushover.twig b/data/web/templates/user/Pushover.twig
index 8a6755a8..a1867a8b 100644
--- a/data/web/templates/user/Pushover.twig
+++ b/data/web/templates/user/Pushover.twig
@@ -9,7 +9,7 @@
       </div>
       <div class="col-sm-10">
         <p class="help-block">{{ lang.user.pushover_info|format(mailcow_cc_username)|raw }}</p>
-        <p class="help-block">{{ lang.user.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</p>
+        <p class="help-block">{{ lang.user.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code></p>
         <div class="form-group">
           <div class="row">
             <div class="col-sm-6">
@@ -42,6 +42,36 @@
                 <input type="text" class="form-control" name="senders" value="{{ pushover_data.senders }}" placeholder="sender1@example.com, sender2@example.com">
               </div>
             </div>
+            <div class="col-sm-12">
+              <div class="form-group">
+                <label for="sound">{{ lang.edit.pushover_sound }}</label><br>
+                <select name="sound" class="form-control">
+                  <option value="pushover"{% if pushover_data.attributes.sound == 'pushover' %} selected{% endif %}>Pushover (default)</option>
+                  <option value="bike"{% if pushover_data.attributes.sound == 'bike' %} selected{% endif %}>Bike</option>
+                  <option value="bugle"{% if pushover_data.attributes.sound == 'bugle' %} selected{% endif %}>Bugle</option>
+                  <option value="cashregister"{% if pushover_data.attributes.sound == 'cashregister' %} selected{% endif %}>Cash Register</option>
+                  <option value="classical"{% if pushover_data.attributes.sound == 'classical' %} selected{% endif %}>Classical</option>
+                  <option value="cosmic"{% if pushover_data.attributes.sound == 'cosmic' %} selected{% endif %}>Cosmic</option>
+                  <option value="falling"{% if pushover_data.attributes.sound == 'falling' %} selected{% endif %}>Falling</option>
+                  <option value="gamelan"{% if pushover_data.attributes.sound == 'gamelan' %} selected{% endif %}>Gamelan</option>
+                  <option value="incoming"{% if pushover_data.attributes.sound == 'incoming' %} selected{% endif %}>Incoming</option>
+                  <option value="intermission"{% if pushover_data.attributes.sound == 'intermission' %} selected{% endif %}>Intermission</option>
+                  <option value="magic"{% if pushover_data.attributes.sound == 'magic' %} selected{% endif %}>Magic</option>
+                  <option value="mechanical"{% if pushover_data.attributes.sound == 'mechanical' %} selected{% endif %}>Mechanical</option>
+                  <option value="pianobar"{% if pushover_data.attributes.sound == 'pianobar' %} selected{% endif %}>Piano Bar</option>
+                  <option value="siren"{% if pushover_data.attributes.sound == 'siren' %} selected{% endif %}>Siren</option>
+                  <option value="spacealarm"{% if pushover_data.attributes.sound == 'spacealarm' %} selected{% endif %}>Space Alarm</option>
+                  <option value="tugboat"{% if pushover_data.attributes.sound == 'tugboat' %} selected{% endif %}>Tug Boat</option>
+                  <option value="alien"{% if pushover_data.attributes.sound == 'alien' %} selected{% endif %}>Alien Alarm (long)</option>
+                  <option value="climb"{% if pushover_data.attributes.sound == 'climb' %} selected{% endif %}>Climb (long)</option>
+                  <option value="persistent"{% if pushover_data.attributes.sound == 'persistent' %} selected{% endif %}>Persistent (long)</option>
+                  <option value="echo"{% if pushover_data.attributes.sound == 'echo' %} selected{% endif %}>Pushover Echo (long)</option>
+                  <option value="updown"{% if pushover_data.attributes.sound == 'updown' %} selected{% endif %}>Up Down (long)</option>
+                  <option value="vibrate"{% if pushover_data.attributes.sound == 'vibrate' %} selected{% endif %}>Vibrate Only</option>
+                  <option value="none"{% if pushover_data.attributes.sound == 'none' %} selected{% endif %}> None (silent) </option>
+                </select>
+              </div>
+            </div>
             <div class="col-sm-12">
               <div class="checkbox">
                 <label><input type="checkbox" value="1" name="active"{% if pushover_data.active == '1' %} checked{% endif %}> {{ lang.user.active }}</label>

From 57a5a9baeb5758d441fbd6c80a00c9d3c94af153 Mon Sep 17 00:00:00 2001
From: bluewalk <noreply@bluewalk.net>
Date: Thu, 17 Nov 2022 21:14:44 +0100
Subject: [PATCH 06/15] Updated DB version and make sure default sound is
 "pushover" when null

---
 data/web/inc/init_db.inc.php | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/data/web/inc/init_db.inc.php b/data/web/inc/init_db.inc.php
index 48db1a62..9abd4485 100644
--- a/data/web/inc/init_db.inc.php
+++ b/data/web/inc/init_db.inc.php
@@ -3,7 +3,7 @@ function init_db_schema() {
   try {
     global $pdo;
 
-    $db_version = "25072022_2300";
+    $db_version = "17112022_2115";
 
     $stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
     $num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
@@ -1264,7 +1264,7 @@ function init_db_schema() {
     $pdo->query("UPDATE `pushover` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;");
     $pdo->query("UPDATE `pushover` SET `attributes` =  JSON_SET(`attributes`, '$.evaluate_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.evaluate_x_prio') IS NULL;");
     $pdo->query("UPDATE `pushover` SET `attributes` =  JSON_SET(`attributes`, '$.only_x_prio', \"0\") WHERE JSON_VALUE(`attributes`, '$.only_x_prio') IS NULL;");
-    $pdo->query("UPDATE `pushover` SET `attributes` =  JSON_SET(`attributes`, '$.sound', \"0\") WHERE JSON_VALUE(`attributes`, '$.sound') IS NULL;");
+    $pdo->query("UPDATE `pushover` SET `attributes` =  JSON_SET(`attributes`, '$.sound', \"pushover\") WHERE JSON_VALUE(`attributes`, '$.sound') IS NULL;");
     // mailbox
     $pdo->query("UPDATE `mailbox` SET `attributes` = '{}' WHERE `attributes` = '' OR `attributes` IS NULL;");
     $pdo->query("UPDATE `mailbox` SET `attributes` =  JSON_SET(`attributes`, '$.passwd_update', \"0\") WHERE JSON_VALUE(`attributes`, '$.passwd_update') IS NULL;");

From fd14c51f850beb893624808b468233f874526b84 Mon Sep 17 00:00:00 2001
From: bluewalk <noreply@bluewalk.net>
Date: Fri, 18 Nov 2022 17:28:10 +0100
Subject: [PATCH 07/15] Removed regex as we have the address from the header

---
 data/conf/rspamd/meta_exporter/pushover.php | 26 +++++++++------------
 1 file changed, 11 insertions(+), 15 deletions(-)

diff --git a/data/conf/rspamd/meta_exporter/pushover.php b/data/conf/rspamd/meta_exporter/pushover.php
index 8db4d3d8..ffc826a7 100644
--- a/data/conf/rspamd/meta_exporter/pushover.php
+++ b/data/conf/rspamd/meta_exporter/pushover.php
@@ -48,12 +48,12 @@ if (!function_exists('getallheaders'))  {
 
 $headers = getallheaders();
 
-$qid      = $headers['X-Rspamd-Qid'];
-$rcpts    = $headers['X-Rspamd-Rcpt'];
-$sender   = $headers['X-Rspamd-From'];
-$ip       = $headers['X-Rspamd-Ip'];
-$subject  = $headers['X-Rspamd-Subject'];
-$priority = 0;
+$qid            = $headers['X-Rspamd-Qid'];
+$rcpts          = $headers['X-Rspamd-Rcpt'];
+$sender_address = $headers['X-Rspamd-From'];
+$ip             = $headers['X-Rspamd-Ip'];
+$subject        = $headers['X-Rspamd-Subject'];
+$priority       = 0;
 
 $symbols_array = json_decode($headers['X-Rspamd-Symbols'], true);
 if (is_array($symbols_array)) {
@@ -67,12 +67,8 @@ if (is_array($symbols_array)) {
 
 $json = json_decode(file_get_contents('php://input'));
 
-$sender_address = $json->header_from[0];
-$sender_name = '-';
-if (preg_match('/[a-zA-Z0-9.!#$%&’*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)/i', $sender_address, $matches)) {
-	$sender_address = $matches[0];
-  $sender_name =  trim(str_replace('<' . $sender_address . '>', '', $json->header_from[0]));
-}
+$sender = $json->header_from[0];
+$sender_name =  trim(str_replace('<' . $sender_address . '>', '', $sender));
 
 $rcpt_final_mailboxes = array();
 
@@ -217,18 +213,18 @@ foreach ($rcpt_final_mailboxes as $rcpt_final) {
     }
     else {
       if (!empty($senders)) {
-        if (in_array($sender, $senders)) {
+        if (in_array($sender_address, $senders)) {
           $sender_validated = true;
         }
       }
       if (!empty($senders_regex) && $sender_validated !== true) {
-        if (preg_match($senders_regex, $sender)) {
+        if (preg_match($senders_regex, $sender_address)) {
           $sender_validated = true;
         }
       }
     }
     if ($sender_validated === false) {
-      error_log("NOTIFY: pushover pipe: skipping unwanted sender " . $sender);
+      error_log("NOTIFY: pushover pipe: skipping unwanted sender " . $sender_address);
       continue;
     }
     if ($attributes['only_x_prio'] == "1" && $priority == 0) {

From d8e314db1a34ef29996f7575b66df894351685e3 Mon Sep 17 00:00:00 2001
From: bluewalk <noreply@bluewalk.net>
Date: Sat, 19 Nov 2022 15:32:48 +0100
Subject: [PATCH 08/15] Fixed issue with subdomain senders + added TO variable
 and allow new lines in text using \n

---
 data/conf/rspamd/meta_exporter/pushover.php | 33 ++++++++++++---------
 data/web/templates/edit/mailbox.twig        |  2 +-
 data/web/templates/user/Pushover.twig       |  2 +-
 3 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/data/conf/rspamd/meta_exporter/pushover.php b/data/conf/rspamd/meta_exporter/pushover.php
index ffc826a7..2f2206ea 100644
--- a/data/conf/rspamd/meta_exporter/pushover.php
+++ b/data/conf/rspamd/meta_exporter/pushover.php
@@ -47,13 +47,15 @@ if (!function_exists('getallheaders'))  {
 }
 
 $headers = getallheaders();
+$json_body = json_decode(file_get_contents('php://input'));
 
-$qid            = $headers['X-Rspamd-Qid'];
-$rcpts          = $headers['X-Rspamd-Rcpt'];
-$sender_address = $headers['X-Rspamd-From'];
-$ip             = $headers['X-Rspamd-Ip'];
-$subject        = $headers['X-Rspamd-Subject'];
-$priority       = 0;
+$qid      = $headers['X-Rspamd-Qid'];
+$rcpts    = $headers['X-Rspamd-Rcpt'];
+$sender   = $headers['X-Rspamd-From'];
+$ip       = $headers['X-Rspamd-Ip'];
+$subject  = $headers['X-Rspamd-Subject'];
+$priority = 0;
+$to       = $json_body->header_to[0];
 
 $symbols_array = json_decode($headers['X-Rspamd-Symbols'], true);
 if (is_array($symbols_array)) {
@@ -65,10 +67,13 @@ if (is_array($symbols_array)) {
   }
 }
 
-$json = json_decode(file_get_contents('php://input'));
+$sender_address = $json_body->header_from[0];
+$sender_name = '-';
 
-$sender = $json->header_from[0];
-$sender_name =  trim(str_replace('<' . $sender_address . '>', '', $sender));
+if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $sender_address, $matches)) {
+	$sender_address = $matches['address'];
+  $sender_name =  trim(trim($matches['name']), '"\' ');
+}
 
 $rcpt_final_mailboxes = array();
 
@@ -213,18 +218,18 @@ foreach ($rcpt_final_mailboxes as $rcpt_final) {
     }
     else {
       if (!empty($senders)) {
-        if (in_array($sender_address, $senders)) {
+        if (in_array($sender, $senders)) {
           $sender_validated = true;
         }
       }
       if (!empty($senders_regex) && $sender_validated !== true) {
-        if (preg_match($senders_regex, $sender_address)) {
+        if (preg_match($senders_regex, $sender)) {
           $sender_validated = true;
         }
       }
     }
     if ($sender_validated === false) {
-      error_log("NOTIFY: pushover pipe: skipping unwanted sender " . $sender_address);
+      error_log("NOTIFY: pushover pipe: skipping unwanted sender " . $sender);
       continue;
     }
     if ($attributes['only_x_prio'] == "1" && $priority == 0) {
@@ -234,9 +239,9 @@ foreach ($rcpt_final_mailboxes as $rcpt_final) {
     $post_fields = array(
       "token" => $api_data['token'],
       "user" => $api_data['key'],
-      "title" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}'), array($subject, $sender, $sender_name, $sender_address), $title)),
+      "title" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO}'), array($subject, $sender, $sender_name, $sender_address, $to), $title)),
       "priority" => $priority,
-      "message" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}'), array($subject, $sender, $sender_name, $sender_address), $text)),
+      "message" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO}', '\n'), array($subject, $sender, $sender_name, $sender_address, $to, PHP_EOL), $text)),
       "sound" => $attributes['sound'] ?? "pushover"
     );
     if ($attributes['evaluate_x_prio'] == "1" && $priority == 1) {
diff --git a/data/web/templates/edit/mailbox.twig b/data/web/templates/edit/mailbox.twig
index f0154584..f2e80c96 100644
--- a/data/web/templates/edit/mailbox.twig
+++ b/data/web/templates/edit/mailbox.twig
@@ -275,7 +275,7 @@
         </div>
         <div class="col-sm-10">
           <p class="help-block">{{ lang.user.pushover_info|format(mailbox)|raw }}</p>
-          <p class="help-block">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code></p>
+          <p class="help-block">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code>, <code>{TO}</code></p>
           <div class="form-group">
             <div class="row">
               <div class="col-sm-6">
diff --git a/data/web/templates/user/Pushover.twig b/data/web/templates/user/Pushover.twig
index a1867a8b..ea1d2c16 100644
--- a/data/web/templates/user/Pushover.twig
+++ b/data/web/templates/user/Pushover.twig
@@ -9,7 +9,7 @@
       </div>
       <div class="col-sm-10">
         <p class="help-block">{{ lang.user.pushover_info|format(mailcow_cc_username)|raw }}</p>
-        <p class="help-block">{{ lang.user.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code></p>
+        <p class="help-block">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code>, <code>{TO}</code></p>
         <div class="form-group">
           <div class="row">
             <div class="col-sm-6">

From 360bb6f30603f9bf3104e3fdc575159cc7729805 Mon Sep 17 00:00:00 2001
From: bluewalk <noreply@bluewalk.net>
Date: Sun, 20 Nov 2022 10:42:44 +0100
Subject: [PATCH 09/15] Split name and address for TO-variables

---
 data/conf/rspamd/meta_exporter/pushover.php | 21 ++++++++++++++++-----
 data/web/templates/edit/mailbox.twig        |  2 +-
 data/web/templates/user/Pushover.twig       |  2 +-
 3 files changed, 18 insertions(+), 7 deletions(-)

diff --git a/data/conf/rspamd/meta_exporter/pushover.php b/data/conf/rspamd/meta_exporter/pushover.php
index 2f2206ea..4c8092d1 100644
--- a/data/conf/rspamd/meta_exporter/pushover.php
+++ b/data/conf/rspamd/meta_exporter/pushover.php
@@ -55,7 +55,6 @@ $sender   = $headers['X-Rspamd-From'];
 $ip       = $headers['X-Rspamd-Ip'];
 $subject  = $headers['X-Rspamd-Subject'];
 $priority = 0;
-$to       = $json_body->header_to[0];
 
 $symbols_array = json_decode($headers['X-Rspamd-Symbols'], true);
 if (is_array($symbols_array)) {
@@ -69,10 +68,16 @@ if (is_array($symbols_array)) {
 
 $sender_address = $json_body->header_from[0];
 $sender_name = '-';
-
 if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $sender_address, $matches)) {
 	$sender_address = $matches['address'];
-  $sender_name =  trim(trim($matches['name']), '"\' ');
+  $sender_name =  trim($matches['name'], '"\' ');
+}
+
+$to_address = $json_body->header_to[0];
+$to_name = '-';
+if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $to_address, $matches)) {
+	$to_address = $matches['address'];
+  $to_name =  trim($matches['name'], '"\' ');
 }
 
 $rcpt_final_mailboxes = array();
@@ -239,9 +244,15 @@ foreach ($rcpt_final_mailboxes as $rcpt_final) {
     $post_fields = array(
       "token" => $api_data['token'],
       "user" => $api_data['key'],
-      "title" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO}'), array($subject, $sender, $sender_name, $sender_address, $to), $title)),
+      "title" => sprintf("%s", str_replace(
+        array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}'), 
+        array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address), $title)
+      ),
       "priority" => $priority,
-      "message" => sprintf("%s", str_replace(array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO}', '\n'), array($subject, $sender, $sender_name, $sender_address, $to, PHP_EOL), $text)),
+      "message" => sprintf("%s", str_replace(
+        array('{SUBJECT}', '{SENDER}', '{SENDER_NAME}', '{SENDER_ADDRESS}', '{TO_NAME}', '{TO_ADDRESS}', '\n'),
+        array($subject, $sender, $sender_name, $sender_address, $to_name, $to_address, PHP_EOL), $text)
+      ),
       "sound" => $attributes['sound'] ?? "pushover"
     );
     if ($attributes['evaluate_x_prio'] == "1" && $priority == 1) {
diff --git a/data/web/templates/edit/mailbox.twig b/data/web/templates/edit/mailbox.twig
index f2e80c96..9eb7c951 100644
--- a/data/web/templates/edit/mailbox.twig
+++ b/data/web/templates/edit/mailbox.twig
@@ -275,7 +275,7 @@
         </div>
         <div class="col-sm-10">
           <p class="help-block">{{ lang.user.pushover_info|format(mailbox)|raw }}</p>
-          <p class="help-block">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code>, <code>{TO}</code></p>
+          <p class="help-block">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code>, <code>{TO_NAME}</code>, <code>{TO_ADDRESS}</code></p>
           <div class="form-group">
             <div class="row">
               <div class="col-sm-6">
diff --git a/data/web/templates/user/Pushover.twig b/data/web/templates/user/Pushover.twig
index ea1d2c16..5bd6b1a4 100644
--- a/data/web/templates/user/Pushover.twig
+++ b/data/web/templates/user/Pushover.twig
@@ -9,7 +9,7 @@
       </div>
       <div class="col-sm-10">
         <p class="help-block">{{ lang.user.pushover_info|format(mailcow_cc_username)|raw }}</p>
-        <p class="help-block">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code>, <code>{TO}</code></p>
+        <p class="help-block">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code>, <code>{SENDER_ADDRESS}</code>, <code>{SENDER_NAME}</code>, <code>{TO_NAME}</code>, <code>{TO_ADDRESS}</code></p>
         <div class="form-group">
           <div class="row">
             <div class="col-sm-6">

From 118cb1017a63281fb4dbef4e0959388cc9aacae6 Mon Sep 17 00:00:00 2001
From: Peter <magic@kthx.at>
Date: Tue, 22 Nov 2022 18:37:15 +0100
Subject: [PATCH 10/15] Add new action Build mailcow backup image

---
 .github/workflows/rebuild_backup_image.yml | 34 ++++++++++++++++++++++
 1 file changed, 34 insertions(+)
 create mode 100644 .github/workflows/rebuild_backup_image.yml

diff --git a/.github/workflows/rebuild_backup_image.yml b/.github/workflows/rebuild_backup_image.yml
new file mode 100644
index 00000000..120d68d9
--- /dev/null
+++ b/.github/workflows/rebuild_backup_image.yml
@@ -0,0 +1,34 @@
+name: Build mailcow backup image
+
+on:
+  schedule:
+    # At 00:00 on Sunday
+    - cron: "0 0 * * 0"
+  workflow_dispatch: # Allow to run workflow manually
+
+jobs:
+  docker_image_build:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+
+      - name: Set up QEMU
+        uses: docker/setup-qemu-action@v2
+
+      - name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v2
+
+      - name: Login to Docker Hub
+        uses: docker/login-action@v2
+        with:
+          username: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_USERNAME }}
+          password: ${{ secrets.BACKUPIMAGEBUILD_ACTION_DOCKERHUB_TOKEN }}
+
+      - name: Build and push
+        uses: docker/build-push-action@v3
+        with:
+          context: .
+          file: data/Dockerfiles/backup/Dockerfile
+          push: true
+          tags: mailcow/backup:latest

From ff7102468ee0db49d866301aecc03690f69f1191 Mon Sep 17 00:00:00 2001
From: Peter <magic@kthx.at>
Date: Tue, 22 Nov 2022 18:38:38 +0100
Subject: [PATCH 11/15] [Helper] Backup and restore: Use latest tag for image

---
 helper-scripts/backup_and_restore.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/helper-scripts/backup_and_restore.sh b/helper-scripts/backup_and_restore.sh
index 1853f501..ee9f0202 100755
--- a/helper-scripts/backup_and_restore.sh
+++ b/helper-scripts/backup_and_restore.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 
-DEBIAN_DOCKER_IMAGE="mailcow/backup:1.0"
+DEBIAN_DOCKER_IMAGE="mailcow/backup:latest"
 
 if [[ ! -z ${MAILCOW_BACKUP_LOCATION} ]]; then
   BACKUP_LOCATION="${MAILCOW_BACKUP_LOCATION}"
@@ -58,7 +58,7 @@ if ! [[ "${THREADS}" =~ ^[1-9]+$ ]] ; then
   echo "Thread input is not a number!"
   exit 1
 elif [[ "${THREADS}" =~ ^[1-9]+$ ]] ; then
-  echo "Using ${THREADS} Thread(s) for this run." 
+  echo "Using ${THREADS} Thread(s) for this run."
   echo "Notice: You can set the Thread count with the THREADS Variable before you run this script."
 fi
 
@@ -181,7 +181,7 @@ function restore() {
 
   elif [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then
     COMPOSE_COMMAND="docker-compose"
-  
+
   else
     echo -e "\e[31mCan not read DOCKER_COMPOSE_VERSION variable from mailcow.conf! Is your mailcow up to date? Exiting...\e[0m"
     exit 1
@@ -380,4 +380,4 @@ elif [[ ${1} == "restore" ]]; then
   done
   echo "Restoring ${FILE_SELECTION[${input_sel}]} from ${RESTORE_POINT}..."
   restore "${RESTORE_POINT}" ${FILE_SELECTION[${input_sel}]}
-fi
\ No newline at end of file
+fi

From 524aba09644640dd41b54dee4946c5d9ef590a43 Mon Sep 17 00:00:00 2001
From: milkmaker <milkmaker@mailcow.de>
Date: Fri, 25 Nov 2022 19:52:37 +0100
Subject: [PATCH 12/15] [Web] Updated lang.sk-sk.json (#4873)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Lukáš Matula <lukas@gbely.net>

Co-authored-by: Lukáš Matula <lukas@gbely.net>
---
 data/web/lang/lang.sk-sk.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/data/web/lang/lang.sk-sk.json b/data/web/lang/lang.sk-sk.json
index 8bb1689e..1b702df8 100644
--- a/data/web/lang/lang.sk-sk.json
+++ b/data/web/lang/lang.sk-sk.json
@@ -106,7 +106,7 @@
         "username": "Používateľské meno",
         "validate": "Overiť",
         "validation_success": "Úspešne overené",
-        "app_passwd_protocols": "Povolené protokoly"
+        "app_passwd_protocols": "Povolené protokoly k heslu aplikácie"
     },
     "admin": {
         "access": "Prístup",

From 73370de1f97cb363e5e32a7b625ba01185cc1183 Mon Sep 17 00:00:00 2001
From: FreddleSpl0it <patschul@posteo.de>
Date: Wed, 30 Nov 2022 11:08:38 +0100
Subject: [PATCH 13/15] Update SOGo to 5.8.0 nightly

---
 docker-compose.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docker-compose.yml b/docker-compose.yml
index 05d5d83b..607a1b55 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -168,7 +168,7 @@ services:
             - phpfpm
 
     sogo-mailcow:
-      image: mailcow/sogo:1.111
+      image: mailcow/sogo:1.12
       environment:
         - DBNAME=${DBNAME}
         - DBUSER=${DBUSER}

From 86b67a9a7b33943161fff0821ee94cbe8641ff01 Mon Sep 17 00:00:00 2001
From: DerLinkman <derlinkman@gmail.com>
Date: Wed, 30 Nov 2022 17:13:39 +0100
Subject: [PATCH 14/15] Updated mailcow/sogo to 1.112

---
 docker-compose.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docker-compose.yml b/docker-compose.yml
index 607a1b55..5dec4e3e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -168,7 +168,7 @@ services:
             - phpfpm
 
     sogo-mailcow:
-      image: mailcow/sogo:1.12
+      image: mailcow/sogo:1.112
       environment:
         - DBNAME=${DBNAME}
         - DBUSER=${DBUSER}

From 0b00f15811c328dee74e3b9121282a19846de68b Mon Sep 17 00:00:00 2001
From: DerLinkman <derlinkman@gmail.com>
Date: Wed, 30 Nov 2022 17:37:33 +0100
Subject: [PATCH 15/15] Added additional Check for Docker Hub

---
 update.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/update.sh b/update.sh
index 69ada6b0..3eca2ea6 100755
--- a/update.sh
+++ b/update.sh
@@ -3,7 +3,7 @@
 ############## Begin Function Section ##############
 
 check_online_status() {
-  CHECK_ONLINE_DOMAINS=('https://github.com')
+  CHECK_ONLINE_DOMAINS=('https://github.com' 'https://hub.docker.com')
   for domain in "${CHECK_ONLINE_DOMAINS[@]}"; do
     if timeout 3 curl --head --silent --output /dev/null ${domain}; then
       return 0