NobGit
public nobgit read

NobMail

Based on mailcow: dockerized

Languages

Repository composition by tracked source files.

PHP
PHP 49% JavaScript 35% HTML 9% CSS 4% Shell 2% Python 1% Lua 0% Perl 0% Ruby 0% SCSS 0%
Create file Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git

Commit

Merge branch 'staging' into nightly

d55994b6
DerLinkman <[email protected]> 3 years, 8 months ago
.github/workflows/rebuild_backup_image.yml      |  34 +
 data/conf/rspamd/local.d/metadata_exporter.conf |   3 +-
 data/conf/rspamd/meta_exporter/pushover.php     |  26 +-
 data/web/api/openapi.yaml                       |   5 +
 data/web/inc/functions.pushover.inc.php         |   4 +-
 data/web/inc/init_db.inc.php                    |   3 +-
 data/web/lang/lang.en-gb.json                   |   2 +
 data/web/lang/lang.nl-nl.json                   |   2 +
 data/web/lang/lang.sk-sk.json                   |   2 +-
 data/web/lang/lang.zh-cn.json                   | 975 ++++++++++++++----------
 data/web/templates/edit/mailbox.twig            |  32 +-
 data/web/templates/user/Pushover.twig           |  32 +-
 docker-compose.yml                              |   4 +-
 helper-scripts/backup_and_restore.sh            |   8 +-
 update.sh                                       |   6 +-
 15 files changed, 706 insertions(+), 432 deletions(-)
 create mode 100644 .github/workflows/rebuild_backup_image.yml

Diff

diff --cc data/web/lang/lang.zh-cn.json
index a2dee800,2b5685ee..7715da33
--- a/data/web/lang/lang.zh-cn.json
+++ b/data/web/lang/lang.zh-cn.json
@@@ -81,11 -86,11 +86,11 @@@
          "public_comment": "公开评论",
          "quota_mb": "配额 (MiB)",
          "relay_all": "中继所有收件人",
-         "relay_all_info": "↪ 如果<b>不</b>选择中继所有收件人,你将需要为每个应该中继的邮件添加一个 (\"盲\") 邮箱。",
+         "relay_all_info": "↪ 如果<b>不</b>选择中继所有收件人,你将需要为每个需要中继的邮件添加一个(\"虚拟\")邮箱。",
          "relay_domain": "中继这个域名",
-         "relay_transport_info": "<div class=\"badge fs-6 bg-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_transport_info": "<div class=\"badge fs-6 bg-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": "简短描述",
@@@ -177,16 -189,18 +189,17 @@@
          "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": "使用者",
@@@ -521,34 -574,40 +573,40 @@@
          "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 ([email protected])</code>。",
+         "ratelimit": "频率限制",
          "redirect_uri": "重定向/回调 URL",
          "relay_all": "中继所有收件人",
-         "relay_all_info": "↪ 如果<b>不</b>选择中继所有,你将需要为每个应该中继的邮件添加一个 (\"盲\") 邮箱。",
+         "relay_all_info": "↪ 如果<b>不</b>选择中继所有收件人,你将需要为每个应该中继的邮件添加一个(\"虚拟\")邮箱。",
          "relay_domain": "中继这个域名",
-         "relay_transport_info": "<div class=\"badge fs-6 bg-info\"></div> 你可以为此域名定义传输规则以自定义发件目标主机,否则遵照MX记录发送邮件。",
 -        "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_disabled": "<span class=\"badge fs-6 bg-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": "本地主机连接超时时间",
@@@ -574,11 -650,11 +649,11 @@@
          "administration": "配置和管理",
          "apps": "应用",
          "debug": "系统信息",
 -        "mailboxes": "邮箱设置",
 -        "mailcow_settings": "配置",
 +        "email": "E-Mail",
 +        "mailcow_config": "配置",
          "quarantine": "隔离",
-         "restart_netfilter": "重启netfilter",
-         "restart_sogo": "重启SOGo",
+         "restart_netfilter": "重启 netfilter",
+         "restart_sogo": "重启 SOGo",
          "user_settings": "用户设置"
      },
      "info": {
@@@ -655,9 -733,9 +735,7 @@@
          "excludes": "除了",
          "filter_table": "筛选表格",
          "filters": "过滤器",
 -        "fname": "全称",
 -        "goto_ham": "学习为<b>非垃圾邮件</b>",
 -        "goto_spam": "学习为<b>垃圾邮件</b>",
 +        "fname": "全名",
-         "force_pw_update": "你<b>必须</b>设置一个新密码以继续使用群件相关服务。",
-         "gal": "全球地址簿",
          "hourly": "每小时",
          "in_use": "使用数 (%)",
          "inactive": "禁用",
@@@ -671,11 -751,6 +751,8 @@@
          "mailbox_defquota": "默认邮箱大小",
          "mailbox_quota": "最大邮箱大小",
          "mailboxes": "邮箱",
 +        "mailbox_defaults": "默认设置",
 +        "mailbox_defaults_info": "配置新邮箱的默认设置",
-         "max_aliases": "最大允许地址别名数",
-         "max_mailboxes": "最大允许邮箱数",
-         "max_quota": "每个邮箱的最大配额",
          "mins_interval": "间隔 (分钟)",
          "msg_num": "消息 #",
          "multiple_bookings": "登记限制",
@@@ -686,34 -762,39 +764,40 @@@
          "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": "收件人映射",
 +        "relay_all": "中继所有收件人",
          "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": "状态",
@@@ -795,31 -886,28 +889,39 @@@
          "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": "类型"
      },
 +    "queue": {
 +        "delete_queue": "删除所有",
 +        "flush_queue": "清空队列",
 +        "queue_ays": "请确认你真的想要删除当前队列中的所有项目。",
 +        "queue_deliver_mail": "递送",
 +        "queue_hold_mail": "暂停",
 +        "queue_manager": "队列管理器",
 +        "queue_unban": "队列取消封禁",
 +        "queue_unhold_mail": "继续",
 +        "queue_show_message": "显示消息"
 +    },
+     "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)",
@@@ -991,12 -1111,12 +1125,12 @@@
          "running": "运行中",
          "save": "保存更改",
          "save_changes": "保存更改",
 -        "sender_acl_disabled": "<span class=\"label label-danger\">发件人检查已关闭</span>",
 +        "sender_acl_disabled": "<span class=\"badge fs-6 bg-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": "重置为服务器默认值",
diff --cc data/web/templates/edit/mailbox.twig
index 49f852a8,9eb7c951..73f75ab5
--- a/data/web/templates/edit/mailbox.twig
+++ b/data/web/templates/edit/mailbox.twig
@@@ -270,52 -271,95 +270,82 @@@
        <input type="hidden" value="0" name="active">
        <div class="row">
          <div class="col-sm-1">
 -          <p class="help-block"><a href="https://pushover.net" target="_blank"><img src="data:image/png;base64,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" class="img img-fluid"></a></p>
 +          <p class="text-muted"><a href="https://pushover.net" target="_blank"><img src="data:image/png;base64,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" class="img img-fluid"></a></p>
          </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_NAME}</code>, <code>{TO_ADDRESS}</code></p>
 -          <div class="form-group">
 -            <div class="row">
 -              <div class="col-sm-6">
 -                <div class="form-group">
 -                  <label for="token">API Token/Key (Application)</label>
 -                  <input type="text" class="form-control" name="token" maxlength="30" value="{{ pushover_data.token }}" required>
 -                </div>
 -              </div>
 -              <div class="col-sm-6">
 -                <div class="form-group">
 -                  <label for="key">User/Group Key</label>
 -                  <input type="text" class="form-control" name="key" maxlength="30" value="{{ pushover_data.key }}" required>
 -                </div>
 -              </div>
 -              <div class="col-sm-6">
 -                <div class="form-group">
 -                  <label for="title">{{ lang.edit.pushover_title }}</label>
 -                  <input type="text" class="form-control" name="title" value="{{ pushover_data.title }}" placeholder="Mail">
 -                </div>
 -              </div>
 -              <div class="col-sm-6">
 -                <div class="form-group">
 -                  <label for="text">{{ lang.edit.pushover_text }}</label>
 -                  <input type="text" class="form-control" name="text" value="{{ pushover_data.text }}" placeholder="You've got mail 📧">
 -                </div>
 -              </div>
 -              <div class="col-sm-12">
 -                <div class="form-group">
 -                  <label for="text">{{ lang.edit.pushover_sender_array|raw }}</label>
 -                  <input type="text" class="form-control" name="senders" value="{{ pushover_data.senders }}" placeholder="[email protected], [email protected]">
 -                </div>
 -              </div>
 -              <div class="col-sm-12">
 +          <p class="text-muted">{{ lang.user.pushover_info|format(mailbox)|raw }}</p>
-           <p class="text-muted">{{ lang.edit.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code></p>
++          <p class="text-muted">{{ 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="row">
 +            <div class="col-sm-6 mb-2">
 +              <label for="token">API Token/Key (Application)</label>
 +              <input type="text" class="form-control" name="token" maxlength="30" value="{{ pushover_data.token }}" required>
 +            </div>
 +            <div class="col-sm-6 mb-2">
 +              <label for="key">User/Group Key</label>
 +              <input type="text" class="form-control" name="key" maxlength="30" value="{{ pushover_data.key }}" required>
 +            </div>
 +            <div class="col-sm-6 mb-4">
 +              <label for="title">{{ lang.edit.pushover_title }}</label>
 +              <input type="text" class="form-control" name="title" value="{{ pushover_data.title }}" placeholder="Mail">
 +            </div>
 +            <div class="col-sm-6 mb-4">
 +              <label for="text">{{ lang.edit.pushover_text }}</label>
 +              <input type="text" class="form-control" name="text" value="{{ pushover_data.text }}" placeholder="You've got mail 📧">
 +            </div>
 +            <div class="col-sm-12 mb-4">
 +              <label for="text">{{ lang.edit.pushover_sender_array|raw }}</label>
 +              <input type="text" class="form-control" name="senders" value="{{ pushover_data.senders }}" placeholder="[email protected], [email protected]">
 +            </div>
 +            <div class="col-sm-12 mb-2">
+                 <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>
 -                </div>
 -              </div>
 -              <div class="col-sm-12">
 -                <legend style="cursor:pointer;margin-top:10px" data-target="#po_advanced" unselectable="on" data-toggle="collapse">
 -                  <i class="bi bi-plus"></i> {{ lang.edit.advanced_settings }}
 -                </legend>
 +              <div class="checkbox">
 +                <label><input type="checkbox" value="1" name="active"{% if pushover_data.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
                </div>
 -              <div class="col-sm-12">
 -                <div id="po_advanced" class="collapse">
 -                  <div class="form-group">
 -                    <label for="text">{{ lang.edit.pushover_sender_regex }}</label>
 -                    <input type="text" class="form-control" name="senders_regex" value="{{ pushover_data.senders_regex }}" placeholder="/(.*@example\.org$|^foo@example\.com$)/i" regex="true">
 -                    <div class="checkbox">
 -                      <label><input type="checkbox" value="1" name="evaluate_x_prio"{% if pushover_data.attributes.evaluate_x_prio == '1' %} checked{% endif %}> {{ lang.edit.pushover_evaluate_x_prio|raw }}</label>
 -                    </div>
 -                    <div class="checkbox">
 -                      <label><input type="checkbox" value="1" name="only_x_prio"{% if pushover_data.attributes.only_x_prio == '1' %} checked{% endif %}> {{ lang.edit.pushover_only_x_prio|raw }}</label>
 -                    </div>
 -                  </div>
 +            </div>
 +            <div class="col-sm-12">
 +              <legend style="cursor:pointer;margin-top:10px" data-bs-target="#po_advanced" unselectable="on" data-bs-toggle="collapse">
 +                <i class="bi bi-plus"></i> {{ lang.edit.advanced_settings }}
 +              </legend>
 +              <hr />
 +            </div>
 +            <div class="col-sm-12 mb-4">
 +              <div id="po_advanced" class="collapse">
 +                <label for="text">{{ lang.edit.pushover_sender_regex }}</label>
 +                <input type="text" class="form-control mt-2" name="senders_regex" value="{{ pushover_data.senders_regex }}" placeholder="/(.*@example\.org$|^foo@example\.com$)/i" regex="true">
 +                <div class="checkbox mt-4">
 +                  <label><input type="checkbox" value="1" name="evaluate_x_prio"{% if pushover_data.attributes.evaluate_x_prio == '1' %} checked{% endif %}> {{ lang.edit.pushover_evaluate_x_prio|raw }}</label>
 +                </div>
 +                <div class="checkbox mt-2">
 +                  <label><input type="checkbox" value="1" name="only_x_prio"{% if pushover_data.attributes.only_x_prio == '1' %} checked{% endif %}> {{ lang.edit.pushover_only_x_prio|raw }}</label>
                  </div>
                </div>
              </div>
diff --cc data/web/templates/user/Pushover.twig
index 7a46401a,5bd6b1a4..cf40c888
--- a/data/web/templates/user/Pushover.twig
+++ b/data/web/templates/user/Pushover.twig
@@@ -1,76 -1,97 +1,106 @@@
 -<div role="tabpanel" class="tab-pane" id="Pushover">
 -  <form data-id="pushover" class="form well" method="post">
 -    <input type="hidden" value="0" name="evaluate_x_prio">
 -    <input type="hidden" value="0" name="only_x_prio">
 -    <input type="hidden" value="0" name="active">
 -    <div class="row">
 -      <div class="col-sm-1">
 -        <p class="help-block"><a href="https://pushover.net" target="_blank"><img src="data:image/png;base64,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" class="img img-fluid"></a></p>
 -      </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_NAME}</code>, <code>{TO_ADDRESS}</code></p>
 -        <div class="form-group">
 -          <div class="row">
 -            <div class="col-sm-6">
 -              <div class="form-group">
 -                <label for="token">API Token/Key (Application)</label>
 -                <input type="text" class="form-control" name="token" maxlength="30" value="{{ pushover_data.token }}" required>
 +<div role="tabpanel" class="tab-pane fade" id="Pushover" role="tabpanel" aria-labelledby="Pushover">
 +  <div class="card mb-4">
 +    <div class="card-header d-flex fs-5">
 +      <button class="btn d-md-none flex-grow-1 text-start" data-bs-target="#collapse-tab-Pushover" data-bs-toggle="collapse" aria-controls="collapse-tab-Pushover">
 +        Pushover API
 +      </button>
 +      <span class="d-none d-md-block">Pushover API
 +    </div>
 +    <div id="collapse-tab-Pushover" class="card-body collapse" data-bs-parent="#user-content">
 +      <form data-id="pushover" class="form well" method="post">
 +        <input type="hidden" value="0" name="evaluate_x_prio">
 +        <input type="hidden" value="0" name="only_x_prio">
 +        <input type="hidden" value="0" name="active">
 +        <div class="row">
 +          <div class="col-sm-1">
 +            <p class="text-muted"><a href="https://pushover.net" target="_blank"><img src="data:image/png;base64,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" class="img img-fluid"></a></p>
 +          </div>
 +          <div class="col-sm-10">
 +            <p class="text-muted">{{ lang.user.pushover_info|format(mailcow_cc_username)|raw }}</p>
-             <p class="text-muted">{{ lang.user.pushover_vars|raw }}: <code>{SUBJECT}</code>, <code>{SENDER}</code></p>
++            <p class="text-muted">{{ 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="row">
 +              <div class="col-sm-6 mb-2">
 +                <div class="form-group">
 +                  <label for="token">API Token/Key (Application)</label>
 +                  <input type="text" class="form-control" name="token" maxlength="30" value="{{ pushover_data.token }}" required>
 +                </div>
                </div>
 -            </div>
 -            <div class="col-sm-6">
 -              <div class="form-group">
 -                <label for="key">User/Group Key</label>
 -                <input type="text" class="form-control" name="key" maxlength="30" value="{{ pushover_data.key }}" required>
 +              <div class="col-sm-6 mb-2">
 +                <div class="form-group">
 +                  <label for="key">User/Group Key</label>
 +                  <input type="text" class="form-control" name="key" maxlength="30" value="{{ pushover_data.key }}" required>
 +                </div>
                </div>
 -            </div>
 -            <div class="col-sm-6">
 -              <div class="form-group">
 -                <label for="title">{{ lang.user.pushover_title }}</label>
 -                <input type="text" class="form-control" name="title" value="{{ pushover_data.title }}" placeholder="Mail">
 +              <div class="col-sm-6 mb-2">
 +                <div class="form-group">
 +                  <label for="title">{{ lang.user.pushover_title }}</label>
 +                  <input type="text" class="form-control" name="title" value="{{ pushover_data.title }}" placeholder="Mail">
 +                </div>
                </div>
 -            </div>
 -            <div class="col-sm-6">
 -              <div class="form-group">
 -                <label for="text">{{ lang.user.pushover_text }}</label>
 -                <input type="text" class="form-control" name="text" value="{{ pushover_data.text }}" placeholder="You've got mail 📧">
 +              <div class="col-sm-6 mb-2">
 +                <div class="form-group">
 +                  <label for="text">{{ lang.user.pushover_text }}</label>
 +                  <input type="text" class="form-control" name="text" value="{{ pushover_data.text }}" placeholder="You've got mail 📧">
 +                </div>
                </div>
 -            </div>
 -            <div class="col-sm-12">
 -              <div class="form-group">
 -                <label for="text">{{ lang.user.pushover_sender_array|raw }}</label>
 -                <input type="text" class="form-control" name="senders" value="{{ pushover_data.senders }}" placeholder="[email protected], [email protected]">
 +              <div class="col-sm-12 mb-4">
 +                <div class="form-group">
 +                  <label for="text">{{ lang.user.pushover_sender_array|raw }}</label>
 +                  <input type="text" class="form-control" name="senders" value="{{ pushover_data.senders }}" placeholder="[email protected], [email protected]">
 +                </div>
                </div>
 -            </div>
 -            <div class="col-sm-12">
 +              <div class="col-sm-12 mb-2">
+               <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>
 +                <div class="checkbox">
 +                  <label><input type="checkbox" value="1" name="active"{% if pushover_data.active == '1' %} checked{% endif %}> {{ lang.user.active }}</label>
 +                </div>
                </div>
 -            </div>
 -            <div class="col-sm-12">
 -              <legend style="cursor:pointer;margin-top:10px" data-target="#po_advanced" unselectable="on" data-toggle="collapse">
 -                <i style="font-size:10pt;" class="bi bi-plus-square"></i> {{ lang.user.advanced_settings }}
 -              </legend>
 -            </div>
 -            <div class="col-sm-12">
 -              <div id="po_advanced" class="collapse">
 -                <div class="form-group">
 -                  <label for="text">{{ lang.user.pushover_sender_regex }}</label>
 -                  <input type="text" class="form-control" name="senders_regex" value="{{ pushover_data.senders_regex }}" placeholder="/(.*@example\.org$|^foo@example\.com$)/i" regex="true">
 -                  <div class="checkbox">
 -                    <label><input type="checkbox" value="1" name="evaluate_x_prio"{% if pushover_data.attributes.evaluate_x_prio == '1' %} checked{% endif %}> {{ lang.user.pushover_evaluate_x_prio|raw }}</label>
 -                  </div>
 -                  <div class="checkbox">
 -                    <label><input type="checkbox" value="1" name="only_x_prio"{% if pushover_data.attributes.only_x_prio == '1' %} checked{% endif %}> {{ lang.user.pushover_only_x_prio|raw }}</label>
 +              <div class="col-sm-12">
 +                <legend style="cursor:pointer;margin-top:10px" data-bs-target="#po_advanced" unselectable="on" data-bs-toggle="collapse">
 +                  <i style="font-size:10pt;" class="bi bi-plus-square"></i> {{ lang.user.advanced_settings }}
 +                </legend>
 +                <hr />
 +              </div>
 +              <div class="col-sm-12 mb-4">
 +                <div id="po_advanced" class="collapse">
 +                  <div class="form-group">
 +                    <label for="text">{{ lang.user.pushover_sender_regex }}</label>
 +                    <input type="text" class="form-control mb-4" name="senders_regex" value="{{ pushover_data.senders_regex }}" placeholder="/(.*@example\.org$|^foo@example\.com$)/i" regex="true">
 +                    <div class="checkbox">
 +                      <label><input type="checkbox" value="1" name="evaluate_x_prio"{% if pushover_data.attributes.evaluate_x_prio == '1' %} checked{% endif %}> {{ lang.user.pushover_evaluate_x_prio|raw }}</label>
 +                    </div>
 +                    <div class="checkbox">
 +                      <label><input type="checkbox" value="1" name="only_x_prio"{% if pushover_data.attributes.only_x_prio == '1' %} checked{% endif %}> {{ lang.user.pushover_only_x_prio|raw }}</label>
 +                    </div>
                    </div>
                  </div>
                </div>