diff --git a/README.md b/README.md new file mode 100644 index 0000000..aa976c0 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# mailman integration into mailcow + +Please look at [official mailcow docs](https://mailcow.github.io/mailcow-dockerized-docs/third_party-mailman/) for further information. + +## quick install +copy all files from here into your mailcow root folder and execute `mailman-install.sh`; diff --git a/data/conf/postfix/extra.cf b/data/conf/postfix/extra.cf new file mode 100644 index 0000000..620ad4d --- /dev/null +++ b/data/conf/postfix/extra.cf @@ -0,0 +1,13 @@ +# mailman +unknown_local_recipient_reject_code = 550 +owner_request_special = no +relay_recipient_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_relay_recipient_maps.cf, + regexp:/opt/mailman/var/data/postfix_lmtp +virtual_mailbox_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_mailbox_maps.cf, + regexp:/opt/mailman/var/data/postfix_lmtp +transport_maps = pcre:/opt/postfix/conf/custom_transport.pcre, + pcre:/opt/postfix/conf/local_transport, + proxy:mysql:/opt/postfix/conf/sql/mysql_transport_maps.cf, + regexp:/opt/mailman/var/data/postfix_lmtp +local_recipient_maps = regexp:/opt/mailman/var/data/postfix_lmtp + diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 0000000..48d808d --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,92 @@ +version: '2.1' +services: + + postfix-mailcow: + volumes: + - ./data/mailman/core:/opt/mailman + + mailman-core: + image: maxking/mailman-core:latest + mem_limit: 1g + hostname: mailman-core + restart: always + logging: + driver: json-file + volumes: + - ./data/mailman/core:/opt/mailman/ + stop_grace_period: 30s + links: + - mailman-database:database + depends_on: + - mailman-database + - postfix-mailcow + environment: + - TZ=${TZ} + - MTA=postfix + - DATABASE_URL=postgres://mailman:${MAILMAN_DB_PASSWORD}@database/mailmandb + - DATABASE_TYPE=postgres + - DATABASE_CLASS=mailman.database.postgresql.PostgreSQLDatabase + - HYPERKITTY_API_KEY=${MAILMAN_HYPERKITTY_API_KEY} + dns: + - ${IPV4_NETWORK:-172.22.1}.254 + networks: + mailcow-network: + aliases: + - mailman-core + + mailman-web: + image: maxking/mailman-web:latest + mem_limit: 512m + container_name: mailman-web + hostname: mailman-web + restart: always + logging: + driver: json-file + depends_on: + - mailman-database + - mailman-core + - postfix-mailcow + links: + - mailman-core:mailman-core + - mailman-database:database + volumes: + - ./data/mailman/web:/opt/mailman-web-data + environment: + - TZ=${TZ} + - DATABASE_TYPE=postgres + - DATABASE_URL=postgres://mailman:${MAILMAN_DB_PASSWORD}@database/mailmandb + - HYPERKITTY_API_KEY=${MAILMAN_HYPERKITTY_API_KEY} + - SECRET_KEY=${MAILMAN_SECRET_KEY} + - SERVE_FROM_DOMAIN=${MAILMAN_SERVE_FROM_DOMAIN} + - MAILMAN_ADMIN_USER=${MAILMAN_ADMIN_USER} + - MAILMAN_ADMIN_EMAIL=${MAILMAN_ADMIN_EMAIL} + - SMTP_HOST=${MAILCOW_HOSTNAME} + - SMTP_PORT=${MAILMAN_SMTP_PORT:-587} + - SMTP_HOST_USER=${MAILMAN_SMTP_HOST_USER} + - SMTP_HOST_PASSWORD=${MAILMAN_SMTP_HOST_PASSWORD} + - SMTP_USE_TLS=${MAILMAN_SMTP_USE_TLS:-true} + - UWSGI_STATIC_MAP=/static=/opt/mailman-web-data/static + ports: + - ${MAILMAN_WEB_PORT:-127.0.0.1:8080}:8080 + dns: + - ${IPV4_NETWORK:-172.22.1}.254 + networks: + mailcow-network: + aliases: + - mailman-web + + mailman-database: + image: postgres:12-alpine + mem_limit: 1g + restart: always + environment: + POSTGRES_DB: mailmandb + POSTGRES_USER: mailman + POSTGRES_PASSWORD: ${MAILMAN_DB_PASSWORD} + volumes: + - ./data/mailman/database:/var/lib/postgresql/data + networks: + mailcow-network: + aliases: + - mailman-database + diff --git a/mailman-backup.sh b/mailman-backup.sh new file mode 100755 index 0000000..d2d4517 --- /dev/null +++ b/mailman-backup.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# backup directory +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +backup_dir=${SCRIPT_DIR}/backup + +# current date +DATE=$(date +"%Y%m%d_%H%M%S") + +# create backup directories +mkdir -p ${backup_dir}/mailman + + +# backup +sudo tar -C ${SCRIPT_DIR}/data --exclude='mailman/core/var/logs' -I pbzip2 -cf ${backup_dir}/mailman/${DATE}-core.tbz2 mailman/core +sudo tar -C ${SCRIPT_DIR}/data --exclude='mailman/web/logs' -I pbzip2 -cf ${backup_dir}/mailman/${DATE}-web.tbz2 mailman/web +docker-compose exec mailman-database pg_dumpall -c -U postgres > ${backup_dir}/mailman/${DATE}-db.sql + diff --git a/mailman-install.sh b/mailman-install.sh new file mode 100755 index 0000000..9134d80 --- /dev/null +++ b/mailman-install.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +#set -o pipefail + +# check of existing mailcow config file +if [ ! -f mailcow.conf ]; then + echo "No mailcow.conf exists. Please configure mailcow before." + exit 1 +fi + +# check for existing mailman configuration in mailcow.conf +if grep -q '# mailman configuration' mailcow.conf; then + echo "A mailman configuration already exists in mailcow.conf" + exit 1 +fi + + +echo "I need to ask you some questions of your server configuration. Please enter the needed information or press enter if a default value is present." +# ask for domain +while [ -z "${MAILMAN_DOMAIN}" ]; do + read -p "Mail domain like example.com: " -e MAILMAN_DOMAIN + DOTS=${MAILMAN_DOMAIN//[^.]}; + if [ ${#DOTS} -lt 1 ] && [ ! -z ${MAILMAN_DOMAIN} ]; then + echo "${MAILMAN_DOMAIN} seems not to be a vaild mail domain" + MAILMAN_DOMAIN= + fi +done + +# ask for mailinglist domain +while [ -z "${MAILMAN_LIST_DOMAIN}" ]; do + read -p "Mailman list domain [list.${MAILMAN_DOMAIN}]: " -e MAILMAN_LIST_DOMAIN + [ -z "${MAILMAN_LIST_DOMAIN}" ] && MAILMAN_LIST_DOMAIN="list.${MAILMAN_DOMAIN}" # replace with default if is empty + DOTS=${MAILMAN_LIST_DOMAIN//[^.]}; + if [ ${#DOTS} -lt 1 ] && [ ! -z ${MAILMAN_LIST_DOMAIN} ]; then + echo "${MAILMAN_LIST_DOMAIN} seems not to be a vaild mail domain" + MAILMAN_LIST_DOMAIN= + fi +done + +# admin email address +while [ -z "${MAILMAN_ADMIN_EMAIL}" ]; do + read -p "Email address for the mailman admin user [listadmin@${MAILMAN_DOMAIN}]: " -e MAILMAN_ADMIN_EMAIL + [ -z "${MAILMAN_ADMIN_EMAIL}" ] && MAILMAN_ADMIN_EMAIL="listadmin@${MAILMAN_DOMAIN}" # replace with default if is empty + AT=${MAILMAN_ADMIN_EMAIL//[^@]}; + if [ ${#AT} -ne 1 ] && [ ! -z ${MAILMAN_ADMIN_EMAIL} ]; then + echo "Invalid email detected" + MAILMAN_ADMIN_EMAIL= + fi +done + +# mailman smtp user email address +while [ -z "${MAILMAN_SMTP_USER}" ]; do + read -p "SMTP user for mailman [mailman@${MAILMAN_DOMAIN}]: " -e MAILMAN_SMTP_USER + [ -z "${MAILMAN_SMTP_USER}" ] && MAILMAN_SMTP_USER="mailman@${MAILMAN_DOMAIN}" # replace with default if is empty + AT=${MAILMAN_SMTP_USER//[^@]}; + if [ ${#AT} -ne 1 ] && [ ! -z ${MAILMAN_SMTP_USER} ]; then + echo "Invalid email detected" + MAILMAN_SMTP_USER= + fi + + read -p "Passwort for ${MAILMAN_SMTP_USER}: " -e MAILMAN_SMTP_PASSWORD +done + +echo "Mailman list domain: ${MAILMAN_LIST_DOMAIN}" +echo "Mailman admin email address: ${MAILMAN_ADMIN_EMAIL}" +echo "SMTP user for mailman: ${MAILMAN_SMTP_USER}" + + +# copy and prepare mailcow configuration +cat << EOF >> mailcow.conf + +# mailman configuration +MAILMAN_WEB_PORT=127.0.0.1:8080 +MAILMAN_SECRET_KEY=$(LC_ALL=C