Compare commits

...

21 Commits

Author SHA1 Message Date
Brennan Kinney 23bb1c8e50
refactor: setup CLI `open-dkim` (#4375)
Refactoring this `setup` CLI command as part of the effort to unify our DKIM feature support between OpenDKIM + Rspamd:
- Adds a `main()` method similar to other setup CLI commands.
- Help text more aligned with equivalent rspamd DKIM setup CLI command.
- DRY some repetition such as hard-coded paths to use variables.
- OpenDKIM config files are created / initialized early on now with `_create_opendkim_configs()`. `while` loop only needs to append entries, so is easier to grok.
- `_create_dkim_key()` to scope just the logic (_and additional notes_) to key generation via `opendkim-genkey`
- Now overall logic with the `while` loop of the script occurs in `_generate_dkim_keys()`:
  - Ownership fixes are now applied after the `while` loop as that seems more appropriate than per iteration.
  - Temporary VHOST config is now removed since it's no longer useful after running.
- Tests adjusted for one new log for adding of default trusted hosts content.

Overall this should be nicer to grok/maintain. Some of this logic will be reused for the unified DKIM generation command in future, which is more likely to shift towards all domains using the same keypair by default with rspamd/opendkim config generated at runtime rather than reliant upon DMS config volume to provide that (_still expected for private key_).

---------

Co-authored-by: Casper <casperklein@users.noreply.github.com>
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2025-03-31 11:27:28 +02:00
beertje44 229ebba1b8
docs: Dovecot Solr - Add compatibility note (#4433)
Co-authored-by: Casper <casperklein@users.noreply.github.com>
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
2025-03-31 11:00:57 +13:00
Christian Schmidt df7a98ec50
chore: Fix broken README link for SRS (#4434) 2025-03-29 12:11:29 +01:00
Georg Lauterbach 5027f4f5b6
release: v15.0.2 (#4432)
* chore: prepare for release of v15.0.2

Signed-off-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>

* Update CHANGELOG.md

---------

Signed-off-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
2025-03-27 00:09:31 +01:00
Moritz Poldrack c2c48b2b83
fix: ensure message content is not modified by header filter (#4429) 2025-03-26 12:24:20 +13:00
Georg Lauterbach 70d645d863
release: v15.0.1 (#4423)
Signed-off-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2025-03-23 01:27:47 +01:00
Brennan Kinney a3571a88c1
fix: DMS state volume must ensure `o+x` permission (#4420) 2025-03-18 23:48:12 +01:00
tranquillity-codes 8ca2bd212c
chore: Gender-neutral language (#4421)
Co-authored-by: itycodes <tranquillitycodes@proton.me>
2025-03-18 19:08:56 +01:00
Georg Lauterbach 0362fa682e
fix: include all files in change detection of Rspamd (#4418) 2025-03-18 00:08:14 +01:00
Brennan Kinney 7c680a0fbc
fix: `start-mailserver.sh` requires `mail_state.sh` to be sourced on restarts (#4417) 2025-03-16 15:34:51 +01:00
Brennan Kinney a156c2c031
docs: Update Dovecot link in `mailserver.env` (#4415) 2025-03-16 21:04:32 +13:00
Lasslos 6b1a566497
docs: Fail2Ban - Add example with required ENV to enable (#4402) 2025-03-06 08:29:39 +01:00
Brennan Kinney 02f068b2b2
fix: Use correct Postfix parameter for `postfix-receive-access.cf` (#4399) 2025-03-05 11:00:06 +13:00
Brennan Kinney d0629f4cb6
chore: Revise utility install scripts + add Smallstep `step` CLI (#4376)
Changes:
- `jaq` should probably live in `/usr/local/bin` with other third-party sourced binaries.
- `swaks` install properly with just `tar`, no `mv` + `rm` needed.
- Added Smallstep `step` CLI. This serves similar purpose to `openssl` commands, but is generally nicer for usage with generation and inspection of certs/keys. I've talked up using in DMS a few times in the past for our TLS helper and unifying DKIM support (_instead of separate OpenDKIM/Rspamd generators_).
- Including `step` for both AMD64 / ARM64 archs needs the alternate naming convention that it's published to GH releases with.
- Added commentary about the `tar` usage. The ownership is a common concern with GH release sources, technically a non-issue when running as `root`
2025-03-03 22:58:42 +01:00
Dmitry R. 1756ba04fb
fix: Support `chmod` on `/var/log/mail/*` when dir is empty (#4391)
Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com>
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2025-03-03 21:28:15 +00:00
dependabot[bot] 807f4f7118
chore(deps): Bump docker/setup-qemu-action from 3.4.0 to 3.6.0 (#4392) 2025-03-03 21:58:58 +01:00
dependabot[bot] 0fbbc44dd3
chore(deps): Bump docker/build-push-action from 6.14.0 to 6.15.0 (#4393) 2025-03-03 20:52:28 +00:00
dependabot[bot] 3c833d8ee8
chore(deps): Bump docker/setup-buildx-action from 3.9.0 to 3.10.0 (#4394) 2025-03-03 20:50:17 +00:00
dependabot[bot] dd595e0a05
chore(deps): Bump docker/metadata-action from 5.6.1 to 5.7.0 (#4395) 2025-03-03 21:47:59 +01:00
Brennan Kinney 5686a4097a
fix: `setup email restrict` configs should only prepend once (#4379)
* fix: `setup email restrict` configs should only prepend once

* chore: Prepend to our custom parameter variant to retain applying to all `smtpd` ports

---------

Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2025-03-01 13:55:13 +01:00
dependabot[bot] 309b5a9086
chore(deps): Bump docker/build-push-action from 6.13.0 to 6.14.0 (#4389)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.13.0 to 6.14.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6.13.0...v6.14.0)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
2025-03-01 12:24:47 +00:00
26 changed files with 330 additions and 137 deletions

View File

@ -71,16 +71,16 @@ jobs:
cache-buildx- cache-buildx-
- name: 'Set up QEMU' - name: 'Set up QEMU'
uses: docker/setup-qemu-action@v3.4.0 uses: docker/setup-qemu-action@v3.6.0
with: with:
platforms: arm64 platforms: arm64
- name: 'Set up Docker Buildx' - name: 'Set up Docker Buildx'
uses: docker/setup-buildx-action@v3.9.0 uses: docker/setup-buildx-action@v3.10.0
# NOTE: AMD64 can build within 2 minutes # NOTE: AMD64 can build within 2 minutes
- name: 'Build images' - name: 'Build images'
uses: docker/build-push-action@v6.13.0 uses: docker/build-push-action@v6.15.0
with: with:
context: . context: .
# Build at least the AMD64 image (which runs against the test suite). # Build at least the AMD64 image (which runs against the test suite).

View File

@ -23,7 +23,7 @@ jobs:
- name: 'Prepare tags' - name: 'Prepare tags'
id: prep id: prep
uses: docker/metadata-action@v5.6.1 uses: docker/metadata-action@v5.7.0
with: with:
images: | images: |
${{ secrets.DOCKER_REPOSITORY }} ${{ secrets.DOCKER_REPOSITORY }}
@ -35,12 +35,12 @@ jobs:
type=semver,pattern={{major}}.{{minor}}.{{patch}} type=semver,pattern={{major}}.{{minor}}.{{patch}}
- name: 'Set up QEMU' - name: 'Set up QEMU'
uses: docker/setup-qemu-action@v3.4.0 uses: docker/setup-qemu-action@v3.6.0
with: with:
platforms: arm64 platforms: arm64
- name: 'Set up Docker Buildx' - name: 'Set up Docker Buildx'
uses: docker/setup-buildx-action@v3.9.0 uses: docker/setup-buildx-action@v3.10.0
# Try get the cached build layers from a prior `generic_build.yml` job. # Try get the cached build layers from a prior `generic_build.yml` job.
# NOTE: Until adopting `type=gha` scoped cache exporter (in `docker/build-push-action`), # NOTE: Until adopting `type=gha` scoped cache exporter (in `docker/build-push-action`),
@ -67,7 +67,7 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: 'Build and publish images' - name: 'Build and publish images'
uses: docker/build-push-action@v6.13.0 uses: docker/build-push-action@v6.15.0
with: with:
context: . context: .
build-args: | build-args: |

View File

@ -38,12 +38,12 @@ jobs:
# Ensures consistent BuildKit version (not coupled to Docker Engine), # Ensures consistent BuildKit version (not coupled to Docker Engine),
# and increased compatibility of the build cache vs mixing buildx drivers. # and increased compatibility of the build cache vs mixing buildx drivers.
- name: 'Set up Docker Buildx' - name: 'Set up Docker Buildx'
uses: docker/setup-buildx-action@v3.9.0 uses: docker/setup-buildx-action@v3.10.0
# Importing from the cache should create the image within approx 30 seconds: # Importing from the cache should create the image within approx 30 seconds:
# NOTE: `qemu` step is not needed as we only test for AMD64. # NOTE: `qemu` step is not needed as we only test for AMD64.
- name: 'Build AMD64 image from cache' - name: 'Build AMD64 image from cache'
uses: docker/build-push-action@v6.13.0 uses: docker/build-push-action@v6.15.0
with: with:
context: . context: .
tags: mailserver-testing:ci tags: mailserver-testing:ci

View File

@ -37,12 +37,12 @@ jobs:
# Ensures consistent BuildKit version (not coupled to Docker Engine), # Ensures consistent BuildKit version (not coupled to Docker Engine),
# and increased compatibility of the build cache vs mixing buildx drivers. # and increased compatibility of the build cache vs mixing buildx drivers.
- name: 'Set up Docker Buildx' - name: 'Set up Docker Buildx'
uses: docker/setup-buildx-action@v3.9.0 uses: docker/setup-buildx-action@v3.10.0
# Importing from the cache should create the image within approx 30 seconds: # Importing from the cache should create the image within approx 30 seconds:
# NOTE: `qemu` step is not needed as we only test for AMD64. # NOTE: `qemu` step is not needed as we only test for AMD64.
- name: 'Build AMD64 image from cache' - name: 'Build AMD64 image from cache'
uses: docker/build-push-action@v6.13.0 uses: docker/build-push-action@v6.15.0
with: with:
context: . context: .
tags: mailserver-testing:ci tags: mailserver-testing:ci

View File

@ -2,10 +2,47 @@
All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased](https://github.com/docker-mailserver/docker-mailserver/compare/v15.0.0...HEAD) ## [Unreleased](https://github.com/docker-mailserver/docker-mailserver/compare/v15.0.2...HEAD)
> **Note**: Changes and additions listed here are contained in the `:edge` image tag. These changes may not be as stable as released changes. > **Note**: Changes and additions listed here are contained in the `:edge` image tag. These changes may not be as stable as released changes.
### Updates
- **Documentation:**
- Added a compatibility note for a Dovecot + Solr 9.8 breaking change ([#4433](https://github.com/docker-mailserver/docker-mailserver/pull/4433))
- **Internal:**
- Refactored `setup config dkim` (`open-dkim`) ([#4375](https://github.com/docker-mailserver/docker-mailserver/pull/4375))
## [v15.0.2](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v15.0.2)
### Fixes
- **Postfix**
- Avoid modifying the message body when filtering sender headers. This regression was introduced from [#4120](https://github.com/docker-mailserver/docker-mailserver/pull/4120) as part of DMS v15.0.0 ([#4429](https://github.com/docker-mailserver/docker-mailserver/pull/4429))
## [v15.0.1](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v15.0.1)
### Added
- **Internal:**
- Added the Smallstep `step` CLI command for future internal usage ([#4376](https://github.com/docker-mailserver/docker-mailserver/pull/4376))
### Fixes
- **Postfix:**
- `setup email restrict` generated configs now only prepend to `dms_smtpd_sender_restrictions` ([#4379](https://github.com/docker-mailserver/docker-mailserver/pull/4379))
- **Rspamd:**
- Change detection support now monitors all files found within the DMS _Config Volume_ Rspamd directory ([#4418](https://github.com/docker-mailserver/docker-mailserver/pull/4418))
- **Internal:**
- A permissions fix for `/var/log/mail` that was [added in DMS v15]((https://github.com/docker-mailserver/docker-mailserver/pull/4374)) no longer encounters an error when no log files are present during a container restart, such as with a `tmpfs` volume mount ([#4391](https://github.com/docker-mailserver/docker-mailserver/pull/4391))
- The DMS _State Volume_ (`/var/mail-state`) will now ensure it's file tree is accessible for services when the volume was created with missing executable bit ([#4420](https://github.com/docker-mailserver/docker-mailserver/pull/4420))
- The DMS _Config Volume_ (`/tmp/docker-mailserver`) now correctly updates permissions on container restarts ([#4417](https://github.com/docker-mailserver/docker-mailserver/pull/4417))
### Updates
- **Internal:**
- Minor improvements to `_install_utils()` in `packages.sh` ([#4376](https://github.com/docker-mailserver/docker-mailserver/pull/4376))
## [v15.0.0](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v15.0.0) ## [v15.0.0](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v15.0.0)
### Breaking ### Breaking

View File

@ -202,7 +202,7 @@ Please read [the SSL page in the documentation][docs-tls] for more information.
Configures the handling of creating mails with forged sender addresses. Configures the handling of creating mails with forged sender addresses.
- **0** => (not recommended) Mail address spoofing allowed. Any logged in user may create email messages with a [forged sender address](https://en.wikipedia.org/wiki/Email_spoofing). - **0** => (not recommended) Mail address spoofing allowed. Any logged in user may create email messages with a [forged sender address](https://en.wikipedia.org/wiki/Email_spoofing).
- 1 => Mail spoofing denied. Each user may only send with his own or his alias addresses. Addresses with [extension delimiters](http://www.postfix.org/postconf.5.html#recipient_delimiter) are not able to send messages. - 1 => Mail spoofing denied. Each user may only send with their own or their alias addresses. Addresses with [extension delimiters](http://www.postfix.org/postconf.5.html#recipient_delimiter) are not able to send messages.
##### ENABLE_SRS ##### ENABLE_SRS

View File

@ -14,18 +14,48 @@ hide:
## Configuration ## Configuration
!!! warning Enabling Fail2Ban support can be done via ENV, but also requires granting at least the `NET_ADMIN` capability to interact with the kernel and ban IP addresses.
DMS must be launched with the `NET_ADMIN` capability in order to be able to install the NFTables rules that actually ban IP addresses. Thus, either include `--cap-add=NET_ADMIN` in the `docker run` command, or the equivalent in the `compose.yaml`: !!! example
```yaml === "Docker Compose"
cap_add:
- NET_ADMIN ```yaml title="compose.yaml"
``` services:
mailserver:
environment:
- ENABLE_FAIL2BAN=1
cap_add:
- NET_ADMIN
```
=== "Docker CLI"
```bash
docker run --rm -it \
--cap-add=NET_ADMIN \
--env ENABLE_FAIL2BAN=1
```
!!! warning "Security risk of adding non-default capabilties"
DMS bundles F2B into the image for convenience to simplify integration and deployment.
The [`NET_ADMIN`][security::cap-net-admin] and [`NET_RAW`][security::cap-net-raw] capabilities are not granted by default to the container root user, as they can be used to compromise security.
If this risk concerns you, it may be wiser to instead prefer only granting these capabilities to a dedicated Fail2Ban container ([example][lsio:f2b-image]).
!!! bug "Running Fail2Ban on Older Kernels" !!! bug "Running Fail2Ban on Older Kernels"
DMS configures F2B to use NFTables, not IPTables (legacy). We have observed that older systems, for example NAS systems, do not support the modern NFTables rules. You will need to configure F2B to use legacy IPTables again, for example with the [``fail2ban-jail.cf``][github-file-f2bjail], see the [section on configuration further down below](#custom-files). DMS configures F2B to use [NFTables][network::nftables], not [IPTables (legacy)][network::iptables-legacy].
We have observed that older systems (for example NAS systems), do not support the modern NFTables rules. You will need to configure F2B to use legacy IPTables again, for example with the [`fail2ban-jail.cf`][github-file-f2bjail], see the [section on configuration further down below](#custom-files).
[security::cap-net-admin]: https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap_net_admin
[security::cap-net-raw]: https://0xn3va.gitbook.io/cheat-sheets/container/escaping/excessive-capabilities#cap_net_raw
[lsio:f2b-image]: https://docs.linuxserver.io/images/docker-fail2ban
[network::nftables]: https://en.wikipedia.org/wiki/Nftables
[network::iptables-legacy]: https://developers.redhat.com/blog/2020/08/18/iptables-the-two-variants-and-their-relationship-with-nftables#two_variants_of_the_iptables_command
### DMS Defaults ### DMS Defaults

View File

@ -146,6 +146,25 @@ docker compose exec mailserver doveadm fts rescan -A
Usually within 15 minutes or so, you should be able to search your mail using the Dovecot FTS feature! :tada: Usually within 15 minutes or so, you should be able to search your mail using the Dovecot FTS feature! :tada:
### Compatibility
Since Solr 9.8.0 was released (Jan 2025), a breaking change [deprecates support for `<lib>` directives][solr::9.8::lib-directive] which is presently used by the Dovecot supplied Solr config (`solr-config-9.xml`) to automatically load additional jars required.
To enable support for `<lib>` directives, add the following ENV to your `solr` container:
```yaml
services:
solr:
environment:
SOLR_CONFIG_LIB_ENABLED: true
```
!!! warning "Solr 10"
From the Solr 10 release onwards, this opt-in ENV will no longer be available.
If Dovecot has not updated their example Solr config ([upstream PR][dovecot::pr::solr-config-lib]), you will need to manually modify the Solr XML config to remove the `<lib>` directives and replace the suggested ENV `SOLR_CONFIG_LIB_ENABLED=true` with `SOLR_MODULES=analysis-extras`.
[docs::user-patches]: ../../config/advanced/override-defaults/user-patches.md [docs::user-patches]: ../../config/advanced/override-defaults/user-patches.md
[docs::dovecot::full-text-search]: ../../config/advanced/full-text-search.md [docs::dovecot::full-text-search]: ../../config/advanced/full-text-search.md
[gh-dms::feature-request::dovecot-solr-package]: https://github.com/docker-mailserver/docker-mailserver/issues/4052 [gh-dms::feature-request::dovecot-solr-package]: https://github.com/docker-mailserver/docker-mailserver/issues/4052
@ -154,3 +173,6 @@ docker compose exec mailserver doveadm fts rescan -A
[dockerfile-solr-uidgid]: https://github.com/apache/solr-docker/blob/9cd850b72309de05169544395c83a85b329d6b86/9.6/Dockerfile#L89-L92 [dockerfile-solr-uidgid]: https://github.com/apache/solr-docker/blob/9cd850b72309de05169544395c83a85b329d6b86/9.6/Dockerfile#L89-L92
[github-solr]: https://github.com/apache/solr [github-solr]: https://github.com/apache/solr
[github-dovecot::core-docs]: https://github.com/dovecot/core/tree/main/doc [github-dovecot::core-docs]: https://github.com/dovecot/core/tree/main/doc
[solr::9.8::lib-directive]: https://issues.apache.org/jira/browse/SOLR-16781
[dovecot::pr::solr-config-lib]: https://github.com/dovecot/core/pull/238

View File

@ -89,10 +89,10 @@ TLS_LEVEL=
# Configures the handling of creating mails with forged sender addresses. # Configures the handling of creating mails with forged sender addresses.
# #
# **0** => (not recommended) Mail address spoofing allowed. Any logged in user may create email messages with a forged sender address (see also https://en.wikipedia.org/wiki/Email_spoofing). # **0** => (not recommended) Mail address spoofing allowed. Any logged in user may create email messages with a forged sender address (see also https://en.wikipedia.org/wiki/Email_spoofing).
# 1 => Mail spoofing denied. Each user may only send with his own or his alias addresses. Addresses with extension delimiters(http://www.postfix.org/postconf.5.html#recipient_delimiter) are not able to send messages. # 1 => Mail spoofing denied. Each user may only send with their own or their alias addresses. Addresses with extension delimiters(http://www.postfix.org/postconf.5.html#recipient_delimiter) are not able to send messages.
SPOOF_PROTECTION= SPOOF_PROTECTION=
# Enables the Sender Rewriting Scheme. SRS is needed if your mail server acts as forwarder. See [postsrsd](https://github.com/roehling/postsrsd/blob/master/README.md#sender-rewriting-scheme-crash-course) for further explanation. # Enables the Sender Rewriting Scheme. SRS is needed if your mail server acts as forwarder. See [postsrsd](https://github.com/roehling/postsrsd/blob/main/README.rst) for further explanation.
# - **0** => Disabled # - **0** => Disabled
# - 1 => Enabled # - 1 => Enabled
ENABLE_SRS=0 ENABLE_SRS=0
@ -508,7 +508,7 @@ DOVECOT_MAILBOX_FORMAT=maildir
# empty => no # empty => no
# yes => Allow bind authentication for LDAP # yes => Allow bind authentication for LDAP
# https://wiki.dovecot.org/AuthDatabase/LDAP/AuthBinds # https://doc.dovecot.org/2.4.0/core/config/auth/databases/ldap.html#authentication-bind
DOVECOT_AUTH_BIND= DOVECOT_AUTH_BIND=
# ----------------------------------------------- # -----------------------------------------------

View File

@ -12,9 +12,17 @@ if [[ -f /etc/dms-settings ]] && [[ $(_get_dms_env_value 'ENABLE_RSPAMD') -eq 1
fi fi
fi fi
KEYSIZE=2048 function _main() {
SELECTOR=mail # Default parameters (updated by `_parse_arguments()`):
DOMAINS= local KEYSIZE=2048
local SELECTOR=mail
local DMS_DOMAINS=
_require_n_parameters_or_print_usage 0 "${@}"
_parse_arguments "${@}"
_generate_dkim_keys
}
function __usage() { function __usage() {
printf '%s' "${PURPLE}OPEN-DKIM${RED}(${YELLOW}8${RED}) printf '%s' "${PURPLE}OPEN-DKIM${RED}(${YELLOW}8${RED})
@ -57,122 +65,171 @@ ${ORANGE}EXAMPLES${RESET}
${ORANGE}EXIT STATUS${RESET} ${ORANGE}EXIT STATUS${RESET}
Exit status is 0 if command was successful. If wrong arguments are provided or arguments contain Exit status is 0 if command was successful. If wrong arguments are provided or arguments contain
errors, the script will exit early with exit status 2. errors, the script will exit early with a non-zero exit status.
" "
} }
_require_n_parameters_or_print_usage 0 "${@}" function _parse_arguments() {
# Parse the command args through iteration:
while [[ ${#} -gt 0 ]]; do
case "${1}" in
while [[ ${#} -gt 0 ]]; do ( 'keysize' )
case "${1}" in if [[ -n ${2:-} ]]; then
( 'keysize' ) KEYSIZE="${2}"
if [[ -n ${2+set} ]]; then _log 'trace' "Keysize set to '${KEYSIZE}'"
KEYSIZE="${2}" else
shift _exit_with_error "No keysize provided after 'keysize' argument"
shift fi
else ;;
_exit_with_error "No keysize provided after 'keysize' argument"
fi
;;
( 'selector' ) ( 'selector' )
if [[ -n ${2+set} ]]; then if [[ -n ${2:-} ]]; then
# shellcheck disable=SC2034 SELECTOR="${2}"
SELECTOR="${2}" _log 'trace' "Selector set to '${SELECTOR}'"
shift else
shift _exit_with_error "No selector provided after 'selector' argument"
else fi
_exit_with_error "No selector provided after 'selector' argument" ;;
fi
;;
( 'domain' ) ( 'domain' )
if [[ -n ${2+set} ]]; then if [[ -n ${2:-} ]]; then
DOMAINS="${2}" DMS_DOMAINS="${2}"
shift _log 'trace' "Domain(s) set to '${DMS_DOMAINS}'"
shift else
else _exit_with_error "No domain(s) provided after 'domain' argument"
_exit_with_error "No domain(s) provided after 'domain' argument" fi
fi ;;
;;
( * ) ( 'help' )
__usage __usage
_exit_with_error "Unknown options '${1}' ${2:+and \'${2}\'}" exit 0
;; ;;
esac ( * )
done __usage
_exit_with_error "Unknown option(s) ${*}"
;;
esac
# Discard these two args (option + value) now that they've been processed:
shift 2
done
}
function _generate_dkim_keys() {
_generate_domains_config
if [[ ! -s ${DATABASE_VHOST} ]]; then
_log 'warn' 'No entries found, no keys to make'
exit 0
fi
# Initialize OpenDKIM configs if necessary:
_create_opendkim_configs
# Generate a keypair per domain and add reference to OpenDKIM configs:
local ENTRY_KEY KEY_TABLE_ENTRY SIGNING_TABLE_ENTRY
while read -r DKIM_DOMAIN; do
_create_dkim_key "${DKIM_DOMAIN}"
# Create / Update OpenDKIM configs with new DKIM key:
ENTRY_KEY="${SELECTOR}._domainkey.${DKIM_DOMAIN}"
KEY_TABLE_ENTRY="${ENTRY_KEY} ${DKIM_DOMAIN}:${SELECTOR}:/etc/opendkim/keys/${DKIM_DOMAIN}/${SELECTOR}.private"
SIGNING_TABLE_ENTRY="*@${DKIM_DOMAIN} ${ENTRY_KEY}"
# If no existing entry, add one:
if ! grep -q "${KEY_TABLE_ENTRY}" "${KEY_TABLE_FILE}"; then
echo "${KEY_TABLE_ENTRY}" >> "${KEY_TABLE_FILE}"
fi
if ! grep -q "${SIGNING_TABLE_ENTRY}" "${SIGNING_TABLE_FILE}"; then
echo "${SIGNING_TABLE_ENTRY}" >> "${SIGNING_TABLE_FILE}"
fi
done < <(_get_valid_lines_from_file "${DATABASE_VHOST}")
# No longer needed, remove:
rm "${DATABASE_VHOST}"
# Ensure ownership is consistent for all content belonging to the base directory,
# During container startup, an internal copy will be made via `_setup_opendkim()`
# with ownership we expect, while this chown is for the benefit of the users ownership.
chown -R "$(stat -c '%U:%G' "${OPENDKIM_BASE_DIR}")" "${OPENDKIM_BASE_DIR}"
}
# Prepare a file with one domain per line (iterated via while loop as DKIM_DOMAIN):
# Depends on methods from `scripts/helpers/postfix.sh`:
DATABASE_VHOST='/tmp/vhost.dkim' DATABASE_VHOST='/tmp/vhost.dkim'
# Prepare a file with one domain per line:
function _generate_domains_config() { function _generate_domains_config() {
local TMP_VHOST='/tmp/vhost.dkim.tmp' local TMP_VHOST='/tmp/vhost.dkim.tmp'
# Generate the default vhost (equivalent to /etc/postfix/vhost), # Generate the default vhost (equivalent to /etc/postfix/vhost),
# unless CLI arg DOMAINS provided an alternative list to use instead: # unless CLI arg DMS_DOMAINS provided an alternative list to use instead:
if [[ -z ${DOMAINS} ]]; then if [[ -z ${DMS_DOMAINS:-} ]]; then
_obtain_hostname_and_domainname _obtain_hostname_and_domainname
# uses TMP_VHOST: # uses TMP_VHOST:
_vhost_collect_postfix_domains _vhost_collect_postfix_domains
else else
tr ',' '\n' <<< "${DOMAINS}" >"${TMP_VHOST}" tr ',' '\n' <<< "${DMS_DOMAINS}" >"${TMP_VHOST}"
fi fi
# uses DATABASE_VHOST + TMP_VHOST: # Uses DATABASE_VHOST + TMP_VHOST:
_create_vhost _create_vhost
} }
_generate_domains_config # `opendkim-genkey` generates two files at the configured `--directory`:
if [[ ! -s ${DATABASE_VHOST} ]]; then # - <selector>.private (Private key, PEM encoded)
_log 'warn' 'No entries found, no keys to make' # - <selector>.txt (Public key, formatted as a TXT record for a RFC 1035 DNS Zone file)
exit 0 function _create_dkim_key() {
fi DKIM_DOMAIN=${1?Expected to be provided a domain}
while read -r DKIM_DOMAIN; do OPENDKIM_DOMAINKEY_DIR="${OPENDKIM_BASE_DIR}/keys/${DKIM_DOMAIN}"
mkdir -p "/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}" mkdir -p "${OPENDKIM_DOMAINKEY_DIR}"
if [[ ! -f "/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}/${SELECTOR}.private" ]]; then DKIM_KEY_FILE="${OPENDKIM_DOMAINKEY_DIR}/${SELECTOR}.private"
_log 'info' "Creating DKIM private key '/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}/${SELECTOR}.private'" if [[ ! -f "${DKIM_KEY_FILE}" ]]; then
_log 'info' "Creating DKIM private key '${DKIM_KEY_FILE}'"
# NOTE:
# --domain only affects a comment in the generated DNS Zone file
# --subdomains is the default,
# --nosubdomains would add `t=s` to the DNS TXT record generated
# http://www.opendkim.org/opendkim-genkey.8.html
opendkim-genkey \ opendkim-genkey \
--bits="${KEYSIZE}" \ --bits="${KEYSIZE}" \
--subdomains \ --subdomains \
--domain="${DKIM_DOMAIN}" \ --domain="${DKIM_DOMAIN}" \
--selector="${SELECTOR}" \ --selector="${SELECTOR}" \
--directory="/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}" --directory="${OPENDKIM_DOMAINKEY_DIR}"
fi fi
}
# fix permissions to use the same user:group as /tmp/docker-mailserver/opendkim/keys OPENDKIM_BASE_DIR='/tmp/docker-mailserver/opendkim'
chown -R "$(stat -c '%U:%G' /tmp/docker-mailserver/opendkim/keys)" "/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}" KEY_TABLE_FILE="${OPENDKIM_BASE_DIR}/KeyTable"
SIGNING_TABLE_FILE="${OPENDKIM_BASE_DIR}/SigningTable"
TRUSTED_HOSTS_FILE="${OPENDKIM_BASE_DIR}/TrustedHosts"
# Create configs if missing:
function _create_opendkim_configs() {
mkdir -p "${OPENDKIM_BASE_DIR}"
local OPENDKIM_CONFIGS=(
"${KEY_TABLE_FILE}"
"${SIGNING_TABLE_FILE}"
"${TRUSTED_HOSTS_FILE}"
)
# write to KeyTable if necessary # Only create if the file doesn't exist (avoids modifying mtime):
KEYTABLEENTRY="${SELECTOR}._domainkey.${DKIM_DOMAIN} ${DKIM_DOMAIN}:${SELECTOR}:/etc/opendkim/keys/${DKIM_DOMAIN}/${SELECTOR}.private" for FILE in "${OPENDKIM_CONFIGS[@]}"; do
if [[ ! -f "/tmp/docker-mailserver/opendkim/KeyTable" ]]; then if [[ ! -f "${FILE}" ]]; then
_log 'debug' 'Creating DKIM KeyTable' _log 'debug' "Creating OpenDKIM config '${FILE}'"
echo "${KEYTABLEENTRY}" >/tmp/docker-mailserver/opendkim/KeyTable touch "${FILE}"
else
if ! grep -q "${KEYTABLEENTRY}" "/tmp/docker-mailserver/opendkim/KeyTable"; then
echo "${KEYTABLEENTRY}" >>/tmp/docker-mailserver/opendkim/KeyTable
fi fi
fi done
# write to SigningTable if necessary # If file exists but is empty, add default hosts to trust:
SIGNINGTABLEENTRY="*@${DKIM_DOMAIN} ${SELECTOR}._domainkey.${DKIM_DOMAIN}" if [[ ! -s "${TRUSTED_HOSTS_FILE}" ]]; then
if [[ ! -f /tmp/docker-mailserver/opendkim/SigningTable ]]; then _log 'debug' 'Adding default trust to OpenDKIM TrustedHosts config'
_log 'debug' 'Creating DKIM SigningTable' echo "127.0.0.1" > "${TRUSTED_HOSTS_FILE}"
echo "*@${DKIM_DOMAIN} ${SELECTOR}._domainkey.${DKIM_DOMAIN}" >/tmp/docker-mailserver/opendkim/SigningTable echo "localhost" >> "${TRUSTED_HOSTS_FILE}"
else
if ! grep -q "${SIGNINGTABLEENTRY}" /tmp/docker-mailserver/opendkim/SigningTable; then
echo "${SIGNINGTABLEENTRY}" >>/tmp/docker-mailserver/opendkim/SigningTable
fi
fi fi
done < <(_get_valid_lines_from_file "${DATABASE_VHOST}") }
# create TrustedHosts if missing _main "${@}"
if [[ -d /tmp/docker-mailserver/opendkim ]] && [[ ! -f /tmp/docker-mailserver/opendkim/TrustedHosts ]]; then
_log 'debug' 'Creating DKIM TrustedHosts'
echo "127.0.0.1" >/tmp/docker-mailserver/opendkim/TrustedHosts
echo "localhost" >>/tmp/docker-mailserver/opendkim/TrustedHosts
fi

View File

@ -68,9 +68,10 @@ smtpd_forbid_bare_newline = yes
# smtpd_forbid_bare_newline_exclusions = $mynetworks # smtpd_forbid_bare_newline_exclusions = $mynetworks
# Custom defined parameters for DMS: # Custom defined parameters for DMS:
# reject_unknown_sender_domain: https://github.com/docker-mailserver/docker-mailserver/issues/3716#issuecomment-1868033234 # Custom sender restrictions overview: https://github.com/docker-mailserver/docker-mailserver/pull/4379#issuecomment-2670365917
# `reject_unknown_sender_domain`: https://github.com/docker-mailserver/docker-mailserver/issues/3716#issuecomment-1868033234
dms_smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unknown_sender_domain dms_smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unknown_sender_domain
# Submission ports 587 and 465 support for SPOOF_PROTECTION=1 # `SPOOF_PROTECTION=1` support requires prepending `reject_authenticated_sender_login_mismatch`
mua_sender_restrictions = reject_authenticated_sender_login_mismatch, $dms_smtpd_sender_restrictions mua_sender_restrictions = reject_authenticated_sender_login_mismatch, $dms_smtpd_sender_restrictions
# Postscreen settings to drop zombies/open relays/spam early # Postscreen settings to drop zombies/open relays/spam early

View File

@ -8,4 +8,5 @@
/^\s*X-Mailer/ IGNORE /^\s*X-Mailer/ IGNORE
/^\s*X-Originating-IP/ IGNORE /^\s*X-Originating-IP/ IGNORE
/^\s*Received: from.*127.0.0.1/ IGNORE /^\s*Received: from.*127.0.0.1/ IGNORE
/^Content-Type:/i PREPEND X-MS-Reactions: disallow /^\s*X-MS-Reactions:/ IGNORE
/^\s*Message-Id:/i PREPEND X-MS-Reactions: disallow

View File

@ -36,20 +36,46 @@ function _pre_installation_steps() {
apt-get "${QUIET}" install --no-install-recommends "${EARLY_PACKAGES[@]}" 2>/dev/null apt-get "${QUIET}" install --no-install-recommends "${EARLY_PACKAGES[@]}" 2>/dev/null
} }
# Install third-party commands to /usr/local/bin
function _install_utils() { function _install_utils() {
local ARCH_A
ARCH_A=$(uname --machine)
# Alternate naming convention support: x86_64 (amd64) / aarch64 (arm64)
# https://en.wikipedia.org/wiki/X86-64#Industry_naming_conventions
local ARCH_B
case "${ARCH_A}" in
( 'x86_64' ) ARCH_B='amd64' ;;
( 'aarch64' ) ARCH_B='arm64' ;;
( * )
_log 'error' "Unsupported arch: '${ARCH_A}'"
return 1
;;
esac
# TIP: `*.tar.gz` releases tend to forget to reset UID/GID ownership when archiving.
# When extracting with `tar` as `root` the archived UID/GID is kept, unless using `--no-same-owner`.
# Likewise when the binary is in a nested location the full archived path
# must be provided + `--strip-components` to extract the file to the target directory.
# Doing this avoids the need for (`mv` + `rm`) or (`--to-stdout` + `chmod +x`)
_log 'debug' 'Installing utils sourced from Github' _log 'debug' 'Installing utils sourced from Github'
_log 'trace' 'Installing jaq' _log 'trace' 'Installing jaq'
local JAQ_TAG='v2.1.0' local JAQ_TAG='v2.1.0'
curl -sSfL "https://github.com/01mf02/jaq/releases/download/${JAQ_TAG}/jaq-$(uname -m)-unknown-linux-gnu" -o /usr/bin/jaq curl -sSfL "https://github.com/01mf02/jaq/releases/download/${JAQ_TAG}/jaq-$(uname -m)-unknown-linux-gnu" -o /usr/local/bin/jaq
chmod +x /usr/bin/jaq chmod +x /usr/local/bin/jaq
_log 'trace' 'Installing step'
local STEP_RELEASE='0.28.2'
curl -sSfL "https://github.com/smallstep/cli/releases/download/v${STEP_RELEASE}/step_linux_${STEP_RELEASE}_${ARCH_B}.tar.gz" \
| tar -xz --directory /usr/local/bin --no-same-owner --strip-components=2 "step_${STEP_RELEASE}/bin/step"
_log 'trace' 'Installing swaks' _log 'trace' 'Installing swaks'
# `perl-doc` is required for `swaks --help` to work:
apt-get "${QUIET}" install --no-install-recommends perl-doc apt-get "${QUIET}" install --no-install-recommends perl-doc
local SWAKS_VERSION='20240103.0' local SWAKS_VERSION='20240103.0'
local SWAKS_RELEASE="swaks-${SWAKS_VERSION}" local SWAKS_RELEASE="swaks-${SWAKS_VERSION}"
curl -sSfL "https://github.com/jetmore/swaks/releases/download/v${SWAKS_VERSION}/${SWAKS_RELEASE}.tar.gz" | tar -xz curl -sSfL "https://github.com/jetmore/swaks/releases/download/v${SWAKS_VERSION}/${SWAKS_RELEASE}.tar.gz" \
mv "${SWAKS_RELEASE}/swaks" /usr/local/bin | tar -xz --directory /usr/local/bin --no-same-owner --strip-components=1 "${SWAKS_RELEASE}/swaks"
rm -r "${SWAKS_RELEASE}"
} }
function _install_postfix() { function _install_postfix() {

View File

@ -43,7 +43,7 @@ function _monitored_files_checksums() {
# Check whether Rspamd is used and if so, monitor it's changes as well # Check whether Rspamd is used and if so, monitor it's changes as well
if [[ ${ENABLE_RSPAMD} -eq 1 ]] && [[ -d ${RSPAMD_DMS_D} ]]; then if [[ ${ENABLE_RSPAMD} -eq 1 ]] && [[ -d ${RSPAMD_DMS_D} ]]; then
readarray -d '' STAGING_FILES_RSPAMD < <(find "${RSPAMD_DMS_D}" -type f -name "*.sh" -print0) readarray -d '' STAGING_FILES_RSPAMD < <(find "${RSPAMD_DMS_D}" -type f -print0)
STAGING_FILES+=("${STAGING_FILES_RSPAMD[@]}") STAGING_FILES+=("${STAGING_FILES_RSPAMD[@]}")
fi fi
fi fi

View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
function _exit_with_error() { function _exit_with_error() {
if [[ -n ${1+set} ]]; then if [[ -n ${1:-} ]]; then
_log 'error' "${1}" _log 'error' "${1}"
else else
_log 'error' "Call to '_exit_with_error' is missing a message to log" _log 'error' "Call to '_exit_with_error' is missing a message to log"

View File

@ -43,12 +43,12 @@ RESET=$(echo -ne '\e[0m')
# message is logged. Likewise when the second argument # message is logged. Likewise when the second argument
# is missing. Both failures will return with exit code '1'. # is missing. Both failures will return with exit code '1'.
function _log() { function _log() {
if [[ -z ${1+set} ]]; then if [[ -z ${1:-} ]]; then
_log 'error' "Call to '_log' is missing a valid log level" _log 'error' "Call to '_log' is missing a valid log level"
return 1 return 1
fi fi
if [[ -z ${2+set} ]]; then if [[ -z ${2:-} ]]; then
_log 'error' "Call to '_log' is missing a message to log" _log 'error' "Call to '_log' is missing a message to log"
return 1 return 1
fi fi
@ -116,7 +116,7 @@ function _log() {
# variables file. If this does not yield a value either, # variables file. If this does not yield a value either,
# use the default log level. # use the default log level.
function _get_log_level_or_default() { function _get_log_level_or_default() {
if [[ -n ${LOG_LEVEL+set} ]]; then if [[ -n ${LOG_LEVEL:-} ]]; then
echo "${LOG_LEVEL}" echo "${LOG_LEVEL}"
elif [[ -e /etc/dms-settings ]] && grep -q -E "^LOG_LEVEL='[a-z]+'" /etc/dms-settings; then elif [[ -e /etc/dms-settings ]] && grep -q -E "^LOG_LEVEL='[a-z]+'" /etc/dms-settings; then
grep '^LOG_LEVEL=' /etc/dms-settings | cut -d "'" -f 2 grep '^LOG_LEVEL=' /etc/dms-settings | cut -d "'" -f 2

View File

@ -131,9 +131,9 @@ function _reload_postfix() {
# 1. No first and second argument is supplied # 1. No first and second argument is supplied
# 2. The second argument is a path to a file that does not exist # 2. The second argument is a path to a file that does not exist
function _replace_by_env_in_file() { function _replace_by_env_in_file() {
if [[ -z ${1+set} ]]; then if [[ -z ${1:-} ]]; then
_dms_panic__invalid_value 'first argument unset' 'utils.sh:_replace_by_env_in_file' _dms_panic__invalid_value 'first argument unset' 'utils.sh:_replace_by_env_in_file'
elif [[ -z ${2+set} ]]; then elif [[ -z ${2:-} ]]; then
_dms_panic__invalid_value 'second argument unset' 'utils.sh:_replace_by_env_in_file' _dms_panic__invalid_value 'second argument unset' 'utils.sh:_replace_by_env_in_file'
elif [[ ! -f ${2} ]]; then elif [[ ! -f ${2} ]]; then
_dms_panic__invalid_value "file '${2}' does not exist" 'utils.sh:_replace_by_env_in_file' _dms_panic__invalid_value "file '${2}' does not exist" 'utils.sh:_replace_by_env_in_file'

View File

@ -181,6 +181,9 @@ if [[ -f /CONTAINER_START ]]; then
# We cannot skip all setup routines because some need to run _after_ # We cannot skip all setup routines because some need to run _after_
# the initial setup (and hence, they cannot be moved to the check stack). # the initial setup (and hence, they cannot be moved to the check stack).
_setup_directory_and_file_permissions _setup_directory_and_file_permissions
# shellcheck source=./startup/setup.d/mail_state.sh
source /usr/local/bin/setup.d/mail_state.sh
_setup_adjust_state_permissions _setup_adjust_state_permissions
else else
_setup _setup

View File

@ -144,5 +144,5 @@ function __log_fixes() {
# Volume permissions should be corrected: # Volume permissions should be corrected:
# https://github.com/docker-mailserver/docker-mailserver-helm/issues/137 # https://github.com/docker-mailserver/docker-mailserver-helm/issues/137
chmod 755 /var/log/mail/ chmod 755 /var/log/mail/
chmod 640 /var/log/mail/* find /var/log/mail/ -type f -exec chmod 640 {} +
} }

View File

@ -23,7 +23,11 @@ function _setup_opendkim() {
# check if any keys are available # check if any keys are available
if [[ -e /tmp/docker-mailserver/opendkim/KeyTable ]]; then if [[ -e /tmp/docker-mailserver/opendkim/KeyTable ]]; then
cp -a /tmp/docker-mailserver/opendkim/* /etc/opendkim/ cp -a /tmp/docker-mailserver/opendkim/* /etc/opendkim/
_log 'trace' "DKIM keys added for: $(find /etc/opendkim/keys/ -maxdepth 1 -type f -printf '%f ')"
local DKIM_DOMAINS
DKIM_DOMAINS=$(find /etc/opendkim/keys/ -maxdepth 1 -type f -printf '%f ')
_log 'trace' "DKIM keys added for: ${DKIM_DOMAINS}"
chown -R opendkim:opendkim /etc/opendkim/ chown -R opendkim:opendkim /etc/opendkim/
chmod -R 0700 /etc/opendkim/keys/ chmod -R 0700 /etc/opendkim/keys/
else else

View File

@ -95,6 +95,11 @@ function _setup_save_states() {
function _setup_adjust_state_permissions() { function _setup_adjust_state_permissions() {
[[ ! -d ${DMS_STATE_DIR} ]] && return 0 [[ ! -d ${DMS_STATE_DIR} ]] && return 0
# Parent directories must have executable bit set to descend the file tree for access,
# as each service running as a non-root user requires this to access their state directory,
# `/var/mail-state` must allow all users `+x`:
chmod +x "${DMS_STATE_DIR}"
# This ensures the user and group of the files from the external mount have their # This ensures the user and group of the files from the external mount have their
# numeric ID values in sync. New releases where the installed packages order changes # numeric ID values in sync. New releases where the installed packages order changes
# can change the values in the Docker image, causing an ownership mismatch. # can change the values in the Docker image, causing an ownership mismatch.

View File

@ -93,13 +93,19 @@ EOF
function _setup_postfix_late() { function _setup_postfix_late() {
_log 'debug' 'Configuring Postfix (late setup)' _log 'debug' 'Configuring Postfix (late setup)'
# These two config files are `access` database tables managed via `setup email restrict`:
# NOTE: Prepends to existing restrictions, thus has priority over other permit/reject policies that follow.
# https://www.postfix.org/postconf.5.html#smtpd_sender_restrictions
# https://www.postfix.org/access.5.html
__postfix__log 'trace' 'Configuring user access' __postfix__log 'trace' 'Configuring user access'
if [[ -f /tmp/docker-mailserver/postfix-send-access.cf ]]; then if [[ -f /tmp/docker-mailserver/postfix-send-access.cf ]]; then
sed -i -E 's|(smtpd_sender_restrictions =)|\1 check_sender_access texthash:/tmp/docker-mailserver/postfix-send-access.cf,|' /etc/postfix/main.cf # Prefer to prepend to our specialized variant instead:
# https://github.com/docker-mailserver/docker-mailserver/pull/4379
sed -i -E 's|^(dms_smtpd_sender_restrictions =)|\1 check_sender_access texthash:/tmp/docker-mailserver/postfix-send-access.cf,|' /etc/postfix/main.cf
fi fi
if [[ -f /tmp/docker-mailserver/postfix-receive-access.cf ]]; then if [[ -f /tmp/docker-mailserver/postfix-receive-access.cf ]]; then
sed -i -E 's|(smtpd_recipient_restrictions =)|\1 check_recipient_access texthash:/tmp/docker-mailserver/postfix-receive-access.cf,|' /etc/postfix/main.cf sed -i -E 's|^(smtpd_recipient_restrictions =)|\1 check_recipient_access texthash:/tmp/docker-mailserver/postfix-receive-access.cf,|' /etc/postfix/main.cf
fi fi
__postfix__log 'trace' 'Configuring relay host' __postfix__log 'trace' 'Configuring relay host'

View File

@ -56,7 +56,7 @@ function __handle_container_name() {
if [[ -n ${1:-} ]] && [[ ${1:-} =~ ^dms-test_ ]]; then if [[ -n ${1:-} ]] && [[ ${1:-} =~ ^dms-test_ ]]; then
printf '%s' "${1}" printf '%s' "${1}"
return 0 return 0
elif [[ -n ${CONTAINER_NAME+set} ]]; then elif [[ -n ${CONTAINER_NAME:-} ]]; then
printf '%s' "${CONTAINER_NAME}" printf '%s' "${CONTAINER_NAME}"
return 0 return 0
else else

View File

@ -17,7 +17,7 @@
# This function is internal and should not be used in tests. # This function is internal and should not be used in tests.
function __initialize_variables() { function __initialize_variables() {
function __check_if_set() { function __check_if_set() {
if [[ ${!1+set} != 'set' ]]; then if [[ -z ${!1:-} ]]; then
echo "ERROR: (helper/setup.sh) '${1:?No variable name given to __check_if_set}' is not set" >&2 echo "ERROR: (helper/setup.sh) '${1:?No variable name given to __check_if_set}' is not set" >&2
exit 1 exit 1
fi fi

View File

@ -234,8 +234,9 @@ function _should_have_correct_mail_headers() {
# but Amavis is changing that. It also changes protocol from SMTP to ESMTP. # but Amavis is changing that. It also changes protocol from SMTP to ESMTP.
assert_line --index 7 --partial 'Received: from localhost (localhost [127.0.0.1])' assert_line --index 7 --partial 'Received: from localhost (localhost [127.0.0.1])'
assert_line --index 8 --partial "by ${EXPECTED_FQDN} (Postfix) with ESMTP id" assert_line --index 8 --partial "by ${EXPECTED_FQDN} (Postfix) with ESMTP id"
assert_line --index 14 --partial 'Message-Id:' assert_line --index 14 'X-MS-Reactions: disallow'
assert_line --index 14 --partial "@${EXPECTED_FQDN}>" assert_line --index 15 --partial 'Message-Id:'
assert_line --index 15 --partial "@${EXPECTED_FQDN}>"
# Mail contents example: # Mail contents example:
# #

View File

@ -62,7 +62,7 @@ function teardown() { _default_teardown ; }
__init_container_without_waiting __init_container_without_waiting
__should_generate_dkim_key 6 __should_generate_dkim_key 7
__assert_outputs_common_dkim_logs __assert_outputs_common_dkim_logs
__should_have_tables_trustedhosts_for_domain __should_have_tables_trustedhosts_for_domain
@ -78,7 +78,7 @@ function teardown() { _default_teardown ; }
# Only mount single config file (postfix-virtual.cf): # Only mount single config file (postfix-virtual.cf):
__init_container_without_waiting "${PWD}/test/config/postfix-virtual.cf:/tmp/docker-mailserver/postfix-virtual.cf:ro" __init_container_without_waiting "${PWD}/test/config/postfix-virtual.cf:/tmp/docker-mailserver/postfix-virtual.cf:ro"
__should_generate_dkim_key 5 __should_generate_dkim_key 6
__assert_outputs_common_dkim_logs __assert_outputs_common_dkim_logs
__should_have_tables_trustedhosts_for_domain __should_have_tables_trustedhosts_for_domain
@ -95,7 +95,7 @@ function teardown() { _default_teardown ; }
# Only mount single config file (postfix-accounts.cf): # Only mount single config file (postfix-accounts.cf):
__init_container_without_waiting "${PWD}/test/config/postfix-accounts.cf:/tmp/docker-mailserver/postfix-accounts.cf:ro" __init_container_without_waiting "${PWD}/test/config/postfix-accounts.cf:/tmp/docker-mailserver/postfix-accounts.cf:ro"
__should_generate_dkim_key 5 __should_generate_dkim_key 6
__assert_outputs_common_dkim_logs __assert_outputs_common_dkim_logs
__should_have_tables_trustedhosts_for_domain __should_have_tables_trustedhosts_for_domain
@ -113,7 +113,7 @@ function teardown() { _default_teardown ; }
__init_container_without_waiting '/tmp/docker-mailserver' __init_container_without_waiting '/tmp/docker-mailserver'
# generate first key (with a custom selector) # generate first key (with a custom selector)
__should_generate_dkim_key 4 '1024' 'domain1.tld' 'mailer' __should_generate_dkim_key 5 '1024' 'domain1.tld' 'mailer'
__assert_outputs_common_dkim_logs __assert_outputs_common_dkim_logs
# generate two additional keys different to the previous one # generate two additional keys different to the previous one
__should_generate_dkim_key 2 '1024' 'domain2.tld,domain3.tld' __should_generate_dkim_key 2 '1024' 'domain2.tld,domain3.tld'
@ -183,15 +183,15 @@ function __assert_logged_dkim_creation() {
function __assert_outputs_common_dkim_logs() { function __assert_outputs_common_dkim_logs() {
refute_output --partial 'No entries found, no keys to make' refute_output --partial 'No entries found, no keys to make'
assert_output --partial 'Creating DKIM KeyTable' assert_output --partial "Creating OpenDKIM config '/tmp/docker-mailserver/opendkim/KeyTable'"
assert_output --partial 'Creating DKIM SigningTable' assert_output --partial "Creating OpenDKIM config '/tmp/docker-mailserver/opendkim/SigningTable'"
assert_output --partial 'Creating DKIM TrustedHosts' assert_output --partial "Creating OpenDKIM config '/tmp/docker-mailserver/opendkim/TrustedHosts'"
} }
function __should_support_creating_key_of_size() { function __should_support_creating_key_of_size() {
local EXPECTED_KEYSIZE=${1:-} local EXPECTED_KEYSIZE=${1:-}
__should_generate_dkim_key 6 "${EXPECTED_KEYSIZE}" __should_generate_dkim_key 7 "${EXPECTED_KEYSIZE}"
__assert_outputs_common_dkim_logs __assert_outputs_common_dkim_logs
__assert_logged_dkim_creation 'localdomain2.com' __assert_logged_dkim_creation 'localdomain2.com'
__assert_logged_dkim_creation 'localhost.localdomain' __assert_logged_dkim_creation 'localhost.localdomain'