Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/content/config/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ Here you can adjust the [log-level for Supervisor](http://supervisord.org/loggin

The log-level will show everything in its class and above.

##### DMS_VMAIL_UID

Default: 5000

The User ID assigned to the static vmail user for `/var/mail` (_Mail storage managed by Dovecot_).

##### DMS_VMAIL_GID

Default: 5000

The Group ID assigned to the static vmail group for `/var/mail` (_Mail storage managed by Dovecot_).

##### ONE_DIR

- 0 => state in default directories.
Expand Down
6 changes: 6 additions & 0 deletions mailserver.env
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ SUPERVISOR_LOGLEVEL=
# 1 => consolidate all states into a single directory (`/var/mail-state`) to allow persistence using docker volumes
ONE_DIR=1

# Support for deployment where these defaults are not compatible (eg: some NAS appliances):
# /var/mail vmail User ID (default: 5000)
DMS_VMAIL_UID=
# /var/mail vmail Group ID (default: 5000)
DMS_VMAIL_GID=

# **empty** => use FILE
# LDAP => use LDAP authentication
# OIDC => use OIDC authentication (not yet implemented)
Expand Down
4 changes: 2 additions & 2 deletions target/scripts/helpers/accounts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function _create_accounts() {

# Dovecot's userdb has the following format
# user:password:uid:gid:(gecos):home:(shell):extra_fields
DOVECOT_USERDB_LINE="${LOGIN}:${PASS}:5000:5000::/var/mail/${DOMAIN}/${USER}/home::${USER_ATTRIBUTES}"
DOVECOT_USERDB_LINE="${LOGIN}:${PASS}:${DMS_VMAIL_UID}:${DMS_VMAIL_GID}::/var/mail/${DOMAIN}/${USER}/home::${USER_ATTRIBUTES}"
if grep -qF "${DOVECOT_USERDB_LINE}" "${DOVECOT_USERDB_FILE}"; then
_log 'warn' "Login '${LOGIN}' will not be added to '${DOVECOT_USERDB_FILE}' twice"
else
Expand Down Expand Up @@ -141,7 +141,7 @@ function _create_dovecot_alias_dummy_accounts() {
fi
fi

DOVECOT_USERDB_LINE="${ALIAS}:${REAL_ACC[1]}:5000:5000::/var/mail/${REAL_DOMAINNAME}/${REAL_USERNAME}::${REAL_ACC[2]:-}"
DOVECOT_USERDB_LINE="${ALIAS}:${REAL_ACC[1]}:${DMS_VMAIL_UID}:${DMS_VMAIL_GID}::/var/mail/${REAL_DOMAINNAME}/${REAL_USERNAME}::${REAL_ACC[2]:-}"
if grep -qi "^${ALIAS}:" "${DOVECOT_USERDB_FILE}"; then
_log 'warn' "Alias '${ALIAS}' will not be added to '${DOVECOT_USERDB_FILE}' twice"
else
Expand Down
4 changes: 2 additions & 2 deletions target/scripts/helpers/utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ function _get_dms_env_value() {
# /var/mail folders (used during startup and change detection handling).
function _chown_var_mail_if_necessary() {
# fix permissions, but skip this if 3 levels deep the user id is already set
if find /var/mail -maxdepth 3 -a \( \! -user 5000 -o \! -group 5000 \) | read -r; then
if find /var/mail -maxdepth 3 -a \( \! -user "${DMS_VMAIL_UID}" -o \! -group "${DMS_VMAIL_GID}" \) | read -r; then
_log 'trace' 'Fixing /var/mail permissions'
chown -R 5000:5000 /var/mail || return 1
chown -R "${DMS_VMAIL_UID}:${DMS_VMAIL_GID}" /var/mail || return 1
fi
}

Expand Down
1 change: 1 addition & 0 deletions target/scripts/start-mailserver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function _register_functions() {

# ? >> Setup

_register_setup_function '_setup_vmail_id'
_register_setup_function '_setup_logs_general'
_register_setup_function '_setup_timezone'

Expand Down
12 changes: 12 additions & 0 deletions target/scripts/startup/setup.d/vmail-id.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

function _setup_vmail_id() {
if [[ "${DMS_VMAIL_UID}" != "5000" ]]; then
_log 'debug' "Setting 'docker' UID to ${DMS_VMAIL_UID}"
usermod --uid "${DMS_VMAIL_UID}" docker
fi
if [[ "${DMS_VMAIL_GID}" != "5000" ]]; then
_log 'debug' "Setting 'docker' GID to ${DMS_VMAIL_GID}"
groupmod --gid "${DMS_VMAIL_GID}" docker
fi
}
2 changes: 2 additions & 0 deletions target/scripts/startup/variables-stack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ function __environment_variables_general_setup() {
VARS[POSTMASTER_ADDRESS]="${POSTMASTER_ADDRESS:=postmaster@${DOMAINNAME}}"
VARS[REPORT_RECIPIENT]="${REPORT_RECIPIENT:=${POSTMASTER_ADDRESS}}"
VARS[REPORT_SENDER]="${REPORT_SENDER:=mailserver-report@${HOSTNAME}}"
VARS[DMS_VMAIL_UID]="${DMS_VMAIL_UID:=5000}"
VARS[DMS_VMAIL_GID]="${DMS_VMAIL_GID:=5000}"

_log 'trace' 'Setting anti-spam & anti-virus environment variables'

Expand Down
75 changes: 75 additions & 0 deletions test/tests/serial/vmail-id.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
load "${REPOSITORY_ROOT}/test/helper/common"
load "${REPOSITORY_ROOT}/test/helper/setup"

BATS_TEST_NAME_PREFIX='[ENV] (DMS_VMAIL_UID + DMS_VMAIL_GID) '
CONTAINER_NAME='dms-test_env-change-vmail-id'

function setup_file() {
_init_with_defaults

local CUSTOM_SETUP_ARGUMENTS=(
--env PERMIT_DOCKER=container
--env DMS_VMAIL_UID=9042
--env DMS_VMAIL_GID=9042
)

_common_container_setup 'CUSTOM_SETUP_ARGUMENTS'
_wait_for_smtp_port_in_container
}

function teardown_file() { _default_teardown ; }

@test 'should successfully deliver mail' {
_send_email 'email-templates/existing-user1'
_wait_for_empty_mail_queue_in_container

# Should be successfully sent (received) by Postfix:
_run_in_container grep 'to=<[email protected]>' /var/log/mail/mail.log
assert_success
assert_output --partial 'status=sent'
_should_output_number_of_lines 1

# Verify successful delivery via Dovecot to `/var/mail` account by searching for the subject:
_repeat_in_container_until_success_or_timeout 20 "${CONTAINER_NAME}" grep -R \
'Subject: Test Message existing-user1.txt' \
'/var/mail/localhost.localdomain/user1/new/'
assert_success
_should_output_number_of_lines 1
}

# TODO: Migrate to test/helper/common.bash
# This test case is shared with tests.bats, but provides context on errors + some minor edits
# TODO: Could improve in future with keywords from https://github.com/docker-mailserver/docker-mailserver/pull/3550#issuecomment-1738509088
# Potentially via a helper that allows an optional fixed number of errors to be present if they were intentional
@test '/var/log/mail/mail.log is error free' {
# Postfix: https://serverfault.com/questions/934703/postfix-451-4-3-0-temporary-lookup-failure
_run_in_container grep 'non-null host address bits in' /var/log/mail/mail.log
assert_failure

# Postfix delivery failure: https://github.com/docker-mailserver/docker-mailserver/issues/230
_run_in_container grep 'mail system configuration error' /var/log/mail/mail.log
assert_failure

# Unknown error source: https://github.com/docker-mailserver/docker-mailserver/pull/85
_run_in_container grep -i ': error:' /var/log/mail/mail.log
assert_failure

# Unknown error source: https://github.com/docker-mailserver/docker-mailserver/pull/320
_run_in_container grep -i 'not writable' /var/log/mail/mail.log
assert_failure
_run_in_container grep -i 'permission denied' /var/log/mail/mail.log
assert_failure

# Amavis: https://forum.howtoforge.com/threads/postfix-smtp-error-caused-by-clamav-cant-connect-to-a-unix-socket-var-run-clamav-clamd-ctl.81002/
_run_in_container grep -i '(!)connect' /var/log/mail/mail.log
assert_failure

# Postfix: https://github.com/docker-mailserver/docker-mailserver/pull/2597
_run_in_container grep -i 'using backwards-compatible default setting' /var/log/mail/mail.log
assert_failure

# Postgrey: https://github.com/docker-mailserver/docker-mailserver/pull/612#discussion_r117635774
_run_in_container grep -i 'connect to 127.0.0.1:10023: Connection refused' /var/log/mail/mail.log
assert_failure
}