git subrepo clone https://github.com/mailcow/mailcow-dockerized.git mailcow/src/mailcow-dockerized
subrepo: subdir: "mailcow/src/mailcow-dockerized"
merged: "a832becb"
upstream: origin: "https://github.com/mailcow/mailcow-dockerized.git"
branch: "master"
commit: "a832becb"
git-subrepo: version: "0.4.3"
origin: "???"
commit: "???"
Change-Id: If5be2d621a211e164c9b6577adaa7884449f16b5
diff --git a/mailcow/src/mailcow-dockerized/data/assets/mysql/docker-entrypoint.sh b/mailcow/src/mailcow-dockerized/data/assets/mysql/docker-entrypoint.sh
new file mode 100755
index 0000000..94e394a
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/assets/mysql/docker-entrypoint.sh
@@ -0,0 +1,192 @@
+#!/bin/bash
+set -eo pipefail
+shopt -s nullglob
+
+openssl req -x509 -sha256 -newkey rsa:2048 -keyout /var/lib/mysql/sql.key -out /var/lib/mysql/sql.crt -days 3650 -nodes -subj '/CN=mysql'
+
+# if command starts with an option, prepend mysqld
+if [ "${1:0:1}" = '-' ]; then
+ set -- mysqld "$@"
+fi
+
+# skip setup if they want an option that stops mysqld
+wantHelp=
+for arg; do
+ case "$arg" in
+ -'?'|--help|--print-defaults|-V|--version)
+ wantHelp=1
+ break
+ ;;
+ esac
+done
+
+# usage: file_env VAR [DEFAULT]
+# ie: file_env 'XYZ_DB_PASSWORD' 'example'
+# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
+# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
+file_env() {
+ local var="$1"
+ local fileVar="${var}_FILE"
+ local def="${2:-}"
+ if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
+ echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
+ exit 1
+ fi
+ local val="$def"
+ if [ "${!var:-}" ]; then
+ val="${!var}"
+ elif [ "${!fileVar:-}" ]; then
+ val="$(< "${!fileVar}")"
+ fi
+ export "$var"="$val"
+ unset "$fileVar"
+}
+
+_check_config() {
+ toRun=( "$@" --verbose --help --log-bin-index="$(mktemp -u)" )
+ if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then
+ cat >&2 <<-EOM
+
+ ERROR: mysqld failed while attempting to check config
+ command was: "${toRun[*]}"
+
+ $errors
+ EOM
+ exit 1
+ fi
+}
+
+# Fetch value from server config
+# We use mysqld --verbose --help instead of my_print_defaults because the
+# latter only show values present in config files, and not server defaults
+_get_config() {
+ local conf="$1"; shift
+ "$@" --verbose --help --log-bin-index="$(mktemp -u)" 2>/dev/null | awk '$1 == "'"$conf"'" { print $2; exit }'
+}
+
+# allow the container to be started with `--user`
+if [ "$1" = 'mysqld' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then
+ _check_config "$@"
+ DATADIR="$(_get_config 'datadir' "$@")"
+ mkdir -p "$DATADIR"
+ chown -R mysql:mysql "$DATADIR"
+ exec gosu mysql "$BASH_SOURCE" "$@"
+fi
+
+if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
+ # still need to check config, container may have started with --user
+ _check_config "$@"
+ # Get config
+ DATADIR="$(_get_config 'datadir' "$@")"
+
+ if [ ! -d "$DATADIR/mysql" ]; then
+ file_env 'MYSQL_ROOT_PASSWORD'
+ if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
+ echo >&2 'error: database is uninitialized and password option is not specified '
+ echo >&2 ' You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD'
+ exit 1
+ fi
+
+ mkdir -p "$DATADIR"
+
+ echo 'Initializing database'
+ # "Other options are passed to mysqld." (so we pass all "mysqld" arguments directly here)
+ mysql_install_db --datadir="$DATADIR" --rpm "${@:2}"
+ echo 'Database initialized'
+
+ SOCKET="$(_get_config 'socket' "$@")"
+ "$@" --skip-networking --socket="${SOCKET}" &
+ pid="$!"
+
+ mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" )
+
+ for i in {30..0}; do
+ if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then
+ break
+ fi
+ echo 'MySQL init process in progress...'
+ sleep 1
+ done
+ if [ "$i" = 0 ]; then
+ echo >&2 'MySQL init process failed.'
+ exit 1
+ fi
+
+ if [ -z "$MYSQL_INITDB_SKIP_TZINFO" ]; then
+ # sed is for https://bugs.mysql.com/bug.php?id=20545
+ mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql
+ fi
+
+ if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
+ export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
+ echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
+ fi
+
+ rootCreate=
+ # default root to listen for connections from anywhere
+ file_env 'MYSQL_ROOT_HOST' '%'
+ if [ ! -z "$MYSQL_ROOT_HOST" -a "$MYSQL_ROOT_HOST" != 'localhost' ]; then
+ # no, we don't care if read finds a terminating character in this heredoc
+ # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
+ read -r -d '' rootCreate <<-EOSQL || true
+ CREATE USER 'root'@'${MYSQL_ROOT_HOST}' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
+ GRANT ALL ON *.* TO 'root'@'${MYSQL_ROOT_HOST}' WITH GRANT OPTION ;
+ EOSQL
+ fi
+
+ "${mysql[@]}" <<-EOSQL
+ -- What's done in this file shouldn't be replicated
+ -- or products like mysql-fabric won't work
+ SET @@SESSION.SQL_LOG_BIN=0;
+
+ DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ;
+ SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MYSQL_ROOT_PASSWORD}') ;
+ GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ;
+ ${rootCreate}
+ DROP DATABASE IF EXISTS test ;
+ FLUSH PRIVILEGES ;
+ EOSQL
+
+ if [ ! -z "$MYSQL_ROOT_PASSWORD" ]; then
+ mysql+=( -p"${MYSQL_ROOT_PASSWORD}" )
+ fi
+
+ file_env 'MYSQL_DATABASE'
+ if [ "$MYSQL_DATABASE" ]; then
+ echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ;" | "${mysql[@]}"
+ mysql+=( "$MYSQL_DATABASE" )
+ fi
+
+ file_env 'MYSQL_USER'
+ file_env 'MYSQL_PASSWORD'
+ if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then
+ echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" | "${mysql[@]}"
+
+ if [ "$MYSQL_DATABASE" ]; then
+ echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}"
+ fi
+ fi
+
+ echo
+ for f in /docker-entrypoint-initdb.d/*; do
+ case "$f" in
+ *.sh) echo "$0: running $f"; . "$f" ;;
+ *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;;
+ *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;;
+ *) echo "$0: ignoring $f" ;;
+ esac
+ echo
+ done
+
+ if ! kill -s TERM "$pid" || ! wait "$pid"; then
+ echo >&2 'MySQL init process failed.'
+ exit 1
+ fi
+
+ echo
+ echo 'MySQL init process done. Ready for start up.'
+ echo
+ fi
+fi
+
+exec "$@"
diff --git a/mailcow/src/mailcow-dockerized/data/assets/nextcloud/nextcloud.conf b/mailcow/src/mailcow-dockerized/data/assets/nextcloud/nextcloud.conf
new file mode 100644
index 0000000..e143a79
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/assets/nextcloud/nextcloud.conf
@@ -0,0 +1,122 @@
+map $http_x_forwarded_proto $client_req_scheme_nc {
+ default $scheme;
+ https https;
+}
+
+server {
+ include /etc/nginx/conf.d/listen_ssl.active;
+ include /etc/nginx/conf.d/listen_plain.active;
+ include /etc/nginx/mime.types;
+ charset utf-8;
+ override_charset on;
+
+ ssl_certificate /etc/ssl/mail/cert.pem;
+ ssl_certificate_key /etc/ssl/mail/key.pem;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_prefer_server_ciphers on;
+ ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
+ ssl_ecdh_curve X25519:X448:secp384r1:secp256k1;
+ ssl_session_cache shared:SSL:50m;
+ ssl_session_timeout 1d;
+ ssl_session_tickets off;
+ add_header Referrer-Policy "no-referrer" always;
+ add_header X-Content-Type-Options "nosniff" always;
+ add_header X-Download-Options "noopen" always;
+ add_header X-Frame-Options "SAMEORIGIN" always;
+ add_header X-Permitted-Cross-Domain-Policies "none" always;
+ add_header X-Robots-Tag "none" always;
+ add_header X-XSS-Protection "1; mode=block" always;
+
+ fastcgi_hide_header X-Powered-By;
+
+ server_name NC_SUBD;
+
+ root /web/nextcloud/;
+
+ location = /robots.txt {
+ allow all;
+ log_not_found off;
+ access_log off;
+ }
+
+ location = /.well-known/carddav {
+ return 301 $client_req_scheme_nc://$host/remote.php/dav;
+ }
+
+ location = /.well-known/caldav {
+ return 301 $client_req_scheme_nc://$host/remote.php/dav;
+ }
+
+ location ^~ /.well-known/acme-challenge/ {
+ default_type "text/plain";
+ root /web;
+ }
+
+ fastcgi_buffers 64 4K;
+
+ gzip on;
+ gzip_vary on;
+ gzip_comp_level 4;
+ gzip_min_length 256;
+ gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
+ gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
+ set_real_ip_from fc00::/7;
+ set_real_ip_from 10.0.0.0/8;
+ set_real_ip_from 172.16.0.0/12;
+ set_real_ip_from 192.168.0.0/16;
+ real_ip_header X-Forwarded-For;
+ real_ip_recursive on;
+
+ location / {
+ rewrite ^ /index.php$uri;
+ }
+
+ location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
+ deny all;
+ }
+ location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
+ deny all;
+ }
+
+ location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
+ fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
+ set $path_info $fastcgi_path_info;
+ try_files $fastcgi_script_name =404;
+ include fastcgi_params;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ fastcgi_param PATH_INFO $path_info;
+ fastcgi_param HTTPS on;
+ # Avoid sending the security headers twice
+ fastcgi_param modHeadersAvailable true;
+ # Enable pretty urls
+ fastcgi_param front_controller_active true;
+ fastcgi_pass phpfpm:9002;
+ fastcgi_intercept_errors on;
+ fastcgi_request_buffering off;
+ client_max_body_size 0;
+ fastcgi_read_timeout 1200;
+ }
+
+ location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
+ try_files $uri/ =404;
+ index index.php;
+ }
+
+ location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
+ try_files $uri /index.php$request_uri;
+ add_header Cache-Control "public, max-age=15778463";
+ add_header Referrer-Policy "no-referrer" always;
+ add_header X-Content-Type-Options "nosniff" always;
+ add_header X-Download-Options "noopen" always;
+ add_header X-Frame-Options "SAMEORIGIN" always;
+ add_header X-Permitted-Cross-Domain-Policies "none" always;
+ add_header X-Robots-Tag "none" always;
+ add_header X-XSS-Protection "1; mode=block" always;
+ access_log off;
+ }
+
+ location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
+ try_files $uri /index.php$request_uri;
+ access_log off;
+ }
+}
diff --git a/mailcow/src/mailcow-dockerized/data/assets/nextcloud/occ b/mailcow/src/mailcow-dockerized/data/assets/nextcloud/occ
new file mode 100755
index 0000000..5113ac0
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/assets/nextcloud/occ
@@ -0,0 +1,2 @@
+#!/bin/bash
+docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) php /web/nextcloud/occ ${@}
diff --git a/mailcow/src/mailcow-dockerized/data/assets/passwd/generate_passwords.sh b/mailcow/src/mailcow-dockerized/data/assets/passwd/generate_passwords.sh
new file mode 100755
index 0000000..7861315
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/assets/passwd/generate_passwords.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+echo DBPASS=$(openssl rand -base64 32 | tr -dc _A-Z-a-z-0-9)
+echo DBROOT=$(openssl rand -base64 32 | tr -dc _A-Z-a-z-0-9)
diff --git a/mailcow/src/mailcow-dockerized/data/assets/ssl-example/cert.pem b/mailcow/src/mailcow-dockerized/data/assets/ssl-example/cert.pem
new file mode 100644
index 0000000..96d16be
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/assets/ssl-example/cert.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBDCCAe6gAwIBAgIQeJMoL/3dxhxhT9EwuRTL/DALBgkqhkiG9w0BAQswEjEQ
+MA4GA1UEChMHbWFpbGNvdzAeFw0xNjEyMTMxMDExMDBaFw0xOTExMjgxMDExMDBa
+MC0xEDAOBgNVBAoTB21haWxjb3cxGTAXBgNVBAMTEG1haWwuZXhhbXBsZS5vcmcw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRg0xT3At9DSb3H5OMp3K1
+MpXAgYyotSK6TS61fC0QEHy2fMXiws7Agcye6Ln7CG63Fe1eN2jkdlefy9xJivS8
+y5w0M8i168v5znzC8fnylL2iOiSYfK/B/oEqfU7YH4RcegO53oDDIUZmi4Frgnu7
+39VVOU1ZyHEVqGJ2H2aAIkoZRjGzumD9Ym4LWGidtKJzBgFt/qmhUeWXipM8w281
+XkQnJU79+x2ywnJSvEZ3r/ZVJC7kbjiVw+/k15k9Cxk6Ik8wmJ0X/+xWxoZomHQI
+1LM0VKAS/iaU95dn2bplvL6jTiiyWAbrMjSKs4XbPt/fIbOicNkj6+CFy0MVfyyH
+AgMBAAGjPzA9MA4GA1UdDwEB/wQEAwIAqDAdBgNVHSUEFjAUBggrBgEFBQcDAgYI
+KwYBBQUHAwEwDAYDVR0TAQH/BAIwADALBgkqhkiG9w0BAQsDggEBAI/jBJa1P8nB
+eHUN5muQmjBVDVOYyWAAEapOe2HYsBcpjaB2H8Iw3DQzJtz6peYeYSCmHRVqFLCm
+VPrq36l9mPUotyPDPlQQAxCj9R2+WbGaJO+N/E1F8FQ94dr3jqwUyfjVPoqEjmIH
+NFkvbA0RJOeBm9oYGdhM0wjOBV9c9MTHFG82nQ/zQeTuPb7GXuKIOXYCxoLNOZMw
+UJ02Cqjv5ImrgOhcstAKX3Ip0urSvZUGvtPla4CGh+M6yDFJ08GzX6OiMIH207RW
+jAbUXXERSUv/7hysdDjGo5HZjCeMzVu9KAxoZXqnmvkk8g2swKWtWBRcoeU1VGx0
+Bx4Q4KMjuYQ=
+-----END CERTIFICATE-----
diff --git a/mailcow/src/mailcow-dockerized/data/assets/ssl-example/dhparams.pem b/mailcow/src/mailcow-dockerized/data/assets/ssl-example/dhparams.pem
new file mode 100644
index 0000000..b245f05
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/assets/ssl-example/dhparams.pem
@@ -0,0 +1,8 @@
+-----BEGIN DH PARAMETERS-----
+MIIBCAKCAQEA9iHB0CRDhV8wfBgqnmvuJpl0fzL3qL75R4ZvQHlfMNLrxuIz2x9D
+9zcDhPcBTVzV5Ay0AAkke4wP6r6wDQqXqBP4Y8IOkYAyLh3jM40jfHQzQt+5JdQl
+ond3kiscBsFOch/vMfSLMu3lAb0YhPNTvrxhMz7LcVAWYl82swASupdiKR+MgaQr
+XsugpmDKsHW60VmIM9B7K9Y+rNHwvMWkmISd0KxA8oOy1WJvsVEissMALZDE3c4w
+2xHmO2lXxgEx3aez28736t4m/KW3g9Zr31a1M0KusmfY//fGkPk4NUrLBOS2xrgp
+Y/rG1qSBdcVyerM0Ki93qCyHKYu4ene0OwIBAg==
+-----END DH PARAMETERS-----
diff --git a/mailcow/src/mailcow-dockerized/data/assets/ssl-example/key.pem b/mailcow/src/mailcow-dockerized/data/assets/ssl-example/key.pem
new file mode 100644
index 0000000..cedf35a
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/assets/ssl-example/key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEA0YNMU9wLfQ0m9x+TjKdytTKVwIGMqLUiuk0utXwtEBB8tnzF
+4sLOwIHMnui5+whutxXtXjdo5HZXn8vcSYr0vMucNDPItevL+c58wvH58pS9ojok
+mHyvwf6BKn1O2B+EXHoDud6AwyFGZouBa4J7u9/VVTlNWchxFahidh9mgCJKGUYx
+s7pg/WJuC1honbSicwYBbf6poVHll4qTPMNvNV5EJyVO/fsdssJyUrxGd6/2VSQu
+5G44lcPv5NeZPQsZOiJPMJidF//sVsaGaJh0CNSzNFSgEv4mlPeXZ9m6Zby+o04o
+slgG6zI0irOF2z7f3yGzonDZI+vghctDFX8shwIDAQABAoIBAQC9kiLnIgxXGyZt
+pmmYdA6re1jatZ2zLSp+DcY8ul3/0hs195IKCyCOOSQPiR520Pt0t+duP46uYZIJ
+aakp9gxaI5Vz+oMacH/AyaBDuDTj1Mf9WMSyIOfbDVCMRJOppGLcVh62+Gfjp2EO
++h2hTJBuvypFkbK2kVIZOaHVpbXWKw1oYuEcTftk9XfxxvfSMw1HQ12/P2CAcbaa
+jPmVbisunv6kpXtewSBTcaLSYWJf1MYD5Hi8fzkD2FJSXYbfQd8RKvT2rj6FA7ux
+CDMzbYhdnd7lc63OARCIjfCRNtDT1cZ3gR1CQHD98lWxmPQIZukv+w7s/bSrFgnQ
+ROZ0ghBJAoGBAOmE/3d5FDmp0aJNxXynKcRGdpEEM4O40RIdqa2eR6Pa7aTRosao
+z0qVgdFuJrqjlB3jgedxXEX1M0abCUzzM9Q5F7JLl+KsjwRwpkIOkPiyUncLp7LK
+QbY3tvYBIdpjlF1USOMGRL4j11hqr4vQC/yPBF7jj81kCZDTbmZhp82jAoGBAOWu
+ql5QFUOlmqkuWIAFkiLEZhOu+ptqkE+zG50CCGMJIX0dJ2PHXFyNGInomAeT0nbI
+pbnK3x7KeEKiGrAqZFNCTHhApTwkrIj0L/RQbMDZ7u7j1AEUVNFEhIm62kg84FtG
+xtfxVxredE+NQc/tyV3hXegdNZxegALirlcMKIvNAoGAWFwIxk48Ru1o8z72QQqH
+lUsMRicOzwK5qV8r+xPvC6MlVL42F3F8rj4QFwzU/r4yp3SUjNyqC5aSRl8Xj9Re
+gijwPHi6Cf09SHLPliMo29GtvnnchJxfbPF7+23GP3p6gy4HPk/65u9s5nnH3uFk
+B7ad8sGsgg0eSXyXQ4okEn0CgYEAnogPuedGthlxBgMiPMMbmfm7hyyId4t3Ljuu
+/JExnsHnpobf8EPjoVIWNOIhRWGnrCtUEEhR9tvDZCKljyDDfKBPTdU496lMmX8K
+NnToi7gg7iy84T3aSVMktDgPgDrclMPmbZh8CeSvnVUfrtgu3Ci4+4Rlw5eKffNe
+aGDQ/6UCgYAbUq9mRT2WOXIo+Dchi9VzDWgtfOw5VEyqkSpb7hPiIYx5jNaENnVK
+cAi3iqbBgPJBuMlTrKmmaxdmssGOEZNJLuuXLDbCU+f5cpu5PQ4crC6UtRI5rlhp
+8Yc+oiv3HWbSw3sVRpMFB6NP4DnvgFW3B2Wdfb/lNzPCKWqBsX7gWw==
+-----END RSA PRIVATE KEY-----
diff --git a/mailcow/src/mailcow-dockerized/data/assets/templates/quarantine.tpl b/mailcow/src/mailcow-dockerized/data/assets/templates/quarantine.tpl
new file mode 100644
index 0000000..8fa88c5
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/assets/templates/quarantine.tpl
@@ -0,0 +1,69 @@
+<html>
+ <head>
+ <meta name="x-apple-disable-message-reformatting" />
+ <style>
+ body {
+ font-family: Helvetica, Arial, Sans-Serif;
+ }
+ table {
+ border-collapse: collapse;
+ width: 100%;
+ margin-bottom: 20px;
+ }
+ th, td {
+ padding: 8px;
+ text-align: left;
+ border-bottom: 1px solid #ddd;
+ vertical-align: top;
+ }
+ td.fixed {
+ white-space: nowrap;
+ }
+ th {
+ background-color: #56B04C;
+ color: white;
+ }
+ tr:nth-child(even) {
+ background-color: #f2f2f2;
+ }
+ /* mobile devices */
+ @media all and (max-width: 480px) {
+ .mob {
+ display: none;
+ }
+ }
+ </style>
+ </head>
+ <body>
+ <p>Hi {{username}}!<br>
+ {% if counter == 1 %}
+ There is 1 new message waiting in quarantine:<br>
+ {% else %}
+ There are {{counter}} new messages waiting in quarantine:<br>
+ {% endif %}
+ <table>
+ <tr><th>Subject</th><th>Sender</th><th class="mob">Score</th><th class="mob">Action</th><th class="mob">Arrived on</th>{% if quarantine_acl == 1 %}<th>Actions</th>{% endif %}</tr>
+ {% for line in meta|reverse %}
+ <tr>
+ <td>{{ line.subject|e }}</td>
+ <td>{{ line.sender|e }}</td>
+ <td class="mob">{{ line.score }}</td>
+ {% if line.action == "reject" %}
+ <td class="mob">Rejected</td>
+ {% else %}
+ <td class="mob">Sent to Junk folder</td>
+ {% endif %}
+ <td class="mob">{{ line.created }}</td>
+ {% if quarantine_acl == 1 %}
+ {% if line.action == "reject" %}
+ <td class="fixed"><a href="https://{{ hostname }}/qhandler/release/{{ line.qhash }}">Release to inbox</a> | <a href="https://{{ hostname }}/qhandler/delete/{{ line.qhash }}">delete</a></td>
+ {% else %}
+ <td class="fixed"><a href="https://{{ hostname }}/qhandler/release/{{ line.qhash }}">Send copy to inbox</a> | <a href="https://{{ hostname }}/qhandler/delete/{{ line.qhash }}">delete</a></td>
+ {% endif %}
+ {% endif %}
+ </tr>
+ {% endfor %}
+ </table>
+ </p>
+ </body>
+</html>
diff --git a/mailcow/src/mailcow-dockerized/data/assets/templates/quota.tpl b/mailcow/src/mailcow-dockerized/data/assets/templates/quota.tpl
new file mode 100644
index 0000000..b6ad644
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/assets/templates/quota.tpl
@@ -0,0 +1,73 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <style>
+ body {
+ font-family: Calibri, Arial, Verdana;
+ }
+ table {
+ border: 0;
+ border-collapse: collapse;
+ <!--[if mso]>
+ border-spacing: 0px;
+ table-layout: fixed;
+ <![endif]-->
+ }
+ tr {
+ display: flex;
+ }
+ #progressbar {
+ color: #000;
+ background-color: #f1f1f1;
+ width: 100%;
+ }
+ {% if (percent >= 95) %}
+ #progressbar {
+ color: #fff;
+ background-color: #FF0000;
+ text-align: center;
+ width: {{percent}}%;
+ }
+ {% elif (percent < 95) and (percent >= 80) %}
+ #progressbar {
+ color: #fff;
+ background-color: #FF8C00;
+ text-align: center;
+ width: {{percent}}%;
+ }
+ {% else %}
+ #progressbar {
+ color: #fff;
+ background-color: #00B000;
+ text-align: center;
+ width: {{percent}}%;
+ }
+ {% endif %}
+ #graybar {
+ background-color: #D8D8D8;
+ width: {{100 - percent}}%;
+ }
+ a:link, a:visited {
+ color: #858585;
+ text-decoration: none;
+ }
+ a:hover, a:active {
+ color: #4a81bf;
+ }
+ </style>
+ </head>
+ <body>
+ <table>
+ <tr>
+ <td colspan="2">
+ Hi {{username}}!<br /><br />
+ Your mailbox is now {{percent}}% full, please consider deleting old messages to still be able to receive new mails in the future.<br /><br />
+ </td>
+ </tr>
+ <tr>
+ <td id="progressbar">{{percent}}%</td>
+ <td id="graybar"></td>
+ </tr>
+ </table>
+ </body>
+</html>