Merge branch 'master' into document-tips-multiple-ip-addresses

This commit is contained in:
Brennan Kinney 2024-01-19 14:13:28 +13:00 committed by GitHub
commit 7315a59ea3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
255 changed files with 5480 additions and 3357 deletions

View File

@ -8,6 +8,7 @@ root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
@ -16,21 +17,9 @@ trim_trailing_whitespace = true
# --- Specific ----------------------------------
# -----------------------------------------------
[*.{yaml,yml,sh,bats}]
indent_size = 2
[Makefile]
[{Makefile,.gitmodules}]
indent_style = tab
indent_size = 4
[*.md]
trim_trailing_whitespace = false
# -----------------------------------------------
# --- Git Submodules ----------------------------
# -----------------------------------------------
[{test/bats/**,test/test_helper/**}]
indent_style = none
indent_size = none
end_of_line = none

159
.gitattributes vendored Normal file
View File

@ -0,0 +1,159 @@
# Normalize line endings of all non-binary files to LF upon check-in (`git add` / `git commit`):
* text=auto
#################################################
### General ###################################
#################################################
## GENERIC
### CI + docs/mkdocs.yml
*.yml text
### Documentation (Project, Tests, Docs site)
*.md text
### TLS certs (test/files/) + DHE params (target/shared/)
*.pem text
*.pem.sha512sum text
#################################################
### Project ###################################
#################################################
## BUILD:
.dockerignore text
Dockerfile text eol=lf
Makefile
## EXAMPLE (RUNTIME):
*.env text
*.yaml text
## PROJECT
.all-contributorsrc text export-ignore
.editorconfig text export-ignore
.gitattributes text export-ignore
.gitignore text export-ignore
.gitkeep text export-ignore
.gitmodules text export-ignore
LICENSE text
## SOURCE CODE
*.sh text eol=lf
### acme.json extractor (target/bin/)
*.py text eol=lf
### Only contain scripts (glob for extensionless)
target/bin/** text eol=lf
#################################################
### Config ####################################
#################################################
## CONFIG
### Contains all text files (glob for extensionless)
target/amavis/** text
target/fetchmail/** text
target/getmail/** text
target/opendkim/** text
target/opendmarc/** text
target/postgrey/** text
target/postsrsd/** text
### Generic target/ + test/config/
*.cf text
*.conf text
### Dovecot
*.ext text
*.sieve text
### Dovecot + Rspamd
*.inc text
### Fail2Ban + Postgrey (test/config/)
*.local text
### Postfix
*.pcre text
#################################################
### Tests #####################################
#################################################
## BATS
*.bash text eol=lf
*.bats text eol=lf
## CONFIG (test/config/)
### OpenLDAP image
*.ldif text
### OpenDKIM
*.private text
KeyTable text
SigningTable text
TrustedHosts text
### Postgrey
whitelist_recipients text
## MISC
### test/config/ + test/files/
*.txt text
### test/linting/ (.ecrc.json) + test/files/ (*.acme.json):
*.json text
#################################################
### Documentation Website #####################
#################################################
## DOCUMENTATION
### docs/content/assets/
*.css text
*.png binary
*.svg text -diff
*.woff binary
### docs/overrides/
*.html text
*.ico binary
*.webp binary
#################################################
### Info # #####################################
#################################################
### WHAT IS THIS FILE?
# `.gitattributes` - Pattern-based overrides (Project specific)
# Documentation: https://git-scm.com/docs/gitattributes
#
# Travels with the project and can override the defaults from `.gitconfig`.
# This helps to enforce consistent line endings (CRLF / LF) where needed via
# patterns (_when the git client supports `.gitattributes`_).
# `.gitconfig` - Global Git defaults (Dev environment)
# Documentation: https://git-scm.com/docs/git-config
#
# Git settings `core.autocrlf` and `core.eol` can vary across dev environments.
# Those defaults can introduce subtle bugs due to incompatible line endings.
### WHY SHOULD I CARE?
# The desired result is to ensure the repo contains normalized LF line endings,
# notably avoiding unhelpful noise in diffs or issues incurred from mixed line
# endings. Storing as LF ensures no surprises for line endings during checkout.
# Additionally for checkout to the local working directory, line endings can be
# forced to CRLF or LF per file where appropriate, which ensures the files have
# compatible line endings where software expects a specific kind.
#
# Examples:
# Diffs with nothing visual changed. Line endings appear invisible.
# Tests that compare text from two sources where only line endings differ fail.
# /bin/sh with a shebang fails to run a binary at the given path due to a CRLF.
### ATTRIBUTES
# `text` normalizes the line endings of a file to LF upon commit (CRLF -> LF).
# `text=auto` sets `text` if Git doesn't consider the file as binary data.
# `eol` sets an explicit line ending to write files to the working directory.
# `core.eol` is used for any files not explicitly set with an `eol` attr value.
# `core.eol` uses the native line endings for your platform by default.
# `core.autocrlf` (if set to `true` or `input`) overrides the `core.eol` value.
# `binary` is an alias for `-text -diff`. The file won't be normalized (-text).
# `-diff` indicates to avoid creating a diff. Useful when diffs are unlikely
# to be meaningful, such as generated content (SVG, Source Maps, Lockfiles).
# `export-ignore` excludes matched files and directories during `git archive`,
# which services like Github use to create releases with archived source files.

View File

@ -1,18 +1,10 @@
name: Other
description: Miscellaneous questions and reports
description: Miscellaneous questions and reports for the project (not support)
title: 'other: '
labels:
- meta/help wanted
body:
- type: markdown
attributes:
value: |
Markdown formatting can be used in almost all text fields. The description will tell you if this is not the case for a specific field.
Be as precise as possible, and if in doubt, it's best to add more information that too few.
---
- type: dropdown
id: subject
attributes:
@ -21,13 +13,18 @@ body:
- I would like to contribute to the project
- I would like to configure a not documented mail server use case
- I would like some feedback concerning a use case
- I have questions about TLS/SSL/STARTTLS/OpenSSL
- Other
- Something else that requires developers attention
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
validations:
required: true
attributes:
label: Description
value: |
<!---
Please do not use this form to bypass doing a proper bug report.
The issue tracker is for anything relevant to the project itself, not individual support queries.
If you don't want to fill out a bug report, please ask support questions at our community discussions page: https://github.com/orgs/docker-mailserver/discussions
-->

View File

@ -1,7 +1,9 @@
# Description
<!-- Include a summary of the change.
Please also include relevant motivation and context. -->
<!--
Include a summary of the change.
Please also include relevant motivation and context.
-->
<!-- Link the issue which will be fixed (if any) here: -->
Fixes #
@ -24,3 +26,4 @@ Fixes #
- [ ] I have made corresponding changes to the documentation (README.md or the documentation under `docs/`)
- [ ] If necessary I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] **I have added information about changes made in this PR to `CHANGELOG.md`**

View File

@ -10,78 +10,24 @@ permissions:
pull-requests: write
statuses: write
env:
# Assign commit authorship to official Github Actions bot:
GIT_USER: github-actions[bot]
GIT_EMAIL: 41898282+github-actions[bot]@users.noreply.github.com
BRANCH_NAME: contributors-update
jobs:
add-contributors:
name: 'Add Contributors'
runs-on: ubuntu-22.04
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: 'Checkout New Branch and Push It'
run: |
git checkout -b ${{ env.BRANCH_NAME }}
git push --force https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git HEAD:${{ env.BRANCH_NAME }}
git checkout master
# See https://github.com/marketplace/actions/auto-add-contributors for reference of the action.
#
# This action is not well documented, but it does the job for now. We pin the version in order
# to not have any issues in the future.
- name: 'Update CONTRIBUTORS.md'
uses: BobAnkh/add-contributors@v0.2.2
uses: akhilmhdh/contributors-readme-action@v2.3.6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
ACCESS_TOKEN: ${{secrets.GITHUB_TOKEN}}
BRANCH: ${{ env.BRANCH_NAME }}
COMMIT_MESSAGE: 'docs: update `CONTRIBUTORS.md`'
PATH: /CONTRIBUTORS.md
CONTRIBUTOR: '## Contributors'
COLUMN_PER_ROW: 6
IMG_WIDTH: 100
FONT_SIZE: 14
AVATAR_SHAPE: round
# See https://github.com/marketplace/actions/create-pull-request for reference of the action.
- name: 'Create Pull Request'
uses: peter-evans/create-pull-request@v5.0.2
id: create-pr
with:
token: ${{ secrets.GITHUB_TOKEN }}
base: master
branch: ${{ env.BRANCH_NAME }}
title: 'docs: update `CONTRIBUTORS.md`'
commit-message: 'docs: update `CONTRIBUTORS.md`'
delete-branch: true
committer: ${{ env.GIT_USER }} <${{ env.GIT_EMAIL }}>
author: ${{ env.GIT_USER }} <${{ env.GIT_EMAIL }}>
signoff: true
body: |
Updated `CONTRIBUTORS.md` via the CI workflow: [`contributors.yml`][workflow].
[workflow]: https://github.com/docker-mailserver/docker-mailserver/blob/master/.github/workflows/contributors.yml
# See https://github.com/marketplace/actions/set-commit-status for reference of the action.
#
# GH Actions are limited when it comes to actions triggering other actions. Hence,
# this whole workflow will not trigger a `pull_request` event without a PAT. The lint
# workflow, which is required due to branch protection, is not important for this type
# of PR, so we skip it and pretend it was successful.
- name: 'Set Status for Linting Actions to Success (Skipped)'
uses: myrotvorets/set-commit-status-action@v1.1.7
continue-on-error: true
with:
token: ${{ secrets.GITHUB_TOKEN }}
# Skipped workflows are still assigned a "success" status:
status: success
# This should be the correct commit SHA on ${{ env.BRANCH_NAME }}:
sha: ${{ steps.create-pr.outputs.pull-request-head-sha }}
# Name of status check to add/update:
context: lint
# Optional message/note we can inline to the right of the context name in the UI:
description: Lint skipped. Not relevant.
readme_path: CONTRIBUTORS.md
collaborators: all
use_username: true
commit_message: 'docs: updated `CONTRIBUTORS.md`'
committer_username: github-actions[bot]
committer_email: 41898282+github-actions[bot]@users.noreply.github.com
pr_title_on_protected: 'docs: update `CONTRIBUTORS.md`'
auto_detect_branch_protection: true

View File

@ -25,7 +25,7 @@ jobs:
# The official Github Action for downloading artifacts does not support multi-workflow
- name: 'Download build artifact'
uses: dawidd6/action-download-artifact@v2
uses: dawidd6/action-download-artifact@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
run_id: ${{ github.event.workflow_run.id }}
@ -46,7 +46,7 @@ jobs:
# but presently does not work correctly via split workflow. It is useful in a split workflow as the 1st stage
# no longer indicates if the entire workflow/deployment was successful.
- name: 'Commit Status: Set Workflow Status as Pending'
uses: myrotvorets/set-commit-status-action@v1.1.7
uses: myrotvorets/set-commit-status-action@v2.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
status: pending
@ -56,7 +56,7 @@ jobs:
context: 'Deploy Preview (pull_request => workflow_run)'
- name: 'Send preview build to Netlify'
uses: nwtgck/actions-netlify@v2.0
uses: nwtgck/actions-netlify@v2.1
id: preview
timeout-minutes: 1
env:
@ -106,7 +106,7 @@ jobs:
Built with commit: ${{ env.PR_HEADSHA }}
- name: 'Commit Status: Update deployment status'
uses: myrotvorets/set-commit-status-action@v1.1.7
uses: myrotvorets/set-commit-status-action@v2.0.0
# Always run this step regardless of job failing early:
if: ${{ always() }}
env:

View File

@ -29,7 +29,7 @@ jobs:
NETLIFY_SITE_PREFIX: pullrequest-${{ github.event.pull_request.number }}
NETLIFY_SITE_NAME: dms-doc-previews
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: 'Build with mkdocs-material via Docker'
working-directory: docs
@ -73,7 +73,7 @@ jobs:
tar --zstd -cf artifact.tar.zst pr.env ${{ env.BUILD_DIR }}
- name: 'Upload artifact for workflow transfer'
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: preview-build
path: artifact.tar.zst

View File

@ -28,7 +28,7 @@ jobs:
name: 'Deploy Docs'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: 'Check if deploy is for a `v<major>.<minor>` tag version instead of `edge`'
if: startsWith(github.ref, 'refs/tags/')
@ -79,10 +79,10 @@ jobs:
needs: deploy
steps:
- name: 'Checkout the tagged commit (shallow clone)'
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: 'Checkout the docs deployment branch to a subdirectory'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: gh-pages
path: gh-pages
@ -115,7 +115,7 @@ jobs:
needs: add-version-to-docs
steps:
- name: 'Checkout the docs deployment branch'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: gh-pages

View File

@ -28,7 +28,7 @@ jobs:
build-cache-key: ${{ steps.derive-image-cache-key.outputs.digest }}
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
@ -74,16 +74,16 @@ jobs:
cache-buildx-
- name: 'Set up QEMU'
uses: docker/setup-qemu-action@v2.2.0
uses: docker/setup-qemu-action@v3.0.0
with:
platforms: arm64
- name: 'Set up Docker Buildx'
uses: docker/setup-buildx-action@v2.9.1
uses: docker/setup-buildx-action@v3.0.0
# NOTE: AMD64 can build within 2 minutes
- name: 'Build images'
uses: docker/build-push-action@v4.1.1
uses: docker/build-push-action@v5.1.0
with:
context: .
# Build at least the AMD64 image (which runs against the test suite).

View File

@ -17,13 +17,13 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: recursive
- name: 'Prepare tags'
id: prep
uses: docker/metadata-action@v4.6.0
uses: docker/metadata-action@v5.5.0
with:
images: |
${{ secrets.DOCKER_REPOSITORY }}
@ -35,12 +35,12 @@ jobs:
type=semver,pattern={{major}}.{{minor}}.{{patch}}
- name: 'Set up QEMU'
uses: docker/setup-qemu-action@v2.2.0
uses: docker/setup-qemu-action@v3.0.0
with:
platforms: arm64
- name: 'Set up Docker Buildx'
uses: docker/setup-buildx-action@v2.9.1
uses: docker/setup-buildx-action@v3.0.0
# 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`),
@ -54,30 +54,25 @@ jobs:
cache-buildx-
- name: 'Login to DockerHub'
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: 'Login to GitHub Container Registry'
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: 'Acquire the image version'
id: get-version
shell: bash
run: echo "version=$(<VERSION)" >>"${GITHUB_OUTPUT}"
- name: 'Build and publish images'
uses: docker/build-push-action@v4.1.1
uses: docker/build-push-action@v5.1.0
with:
context: .
build-args: |
DMS_RELEASE=${{ github.ref_type == 'tag' && github.ref_name || 'edge' }}
VCS_REVISION=${{ github.sha }}
VCS_VERSION=${{ steps.get-version.outputs.version }}
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.prep.outputs.tags }}

View File

@ -20,7 +20,7 @@ jobs:
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
# Required to retrieve bats (core + extras):
submodules: recursive
@ -38,12 +38,12 @@ jobs:
# Ensures consistent BuildKit version (not coupled to Docker Engine),
# and increased compatibility of the build cache vs mixing buildx drivers.
- name: 'Set up Docker Buildx'
uses: docker/setup-buildx-action@v2.9.1
uses: docker/setup-buildx-action@v3.0.0
# Importing from the cache should create the image within approx 30 seconds:
# NOTE: `qemu` step is not needed as we only test for AMD64.
- name: 'Build AMD64 image from cache'
uses: docker/build-push-action@v4.1.1
uses: docker/build-push-action@v5.1.0
with:
context: .
tags: mailserver-testing:ci

View File

@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: 'Checkout'
uses: actions/checkout@v3
uses: actions/checkout@v4
# Get the cached build layers from the build job:
# This should always be a cache-hit, thus `restore-keys` fallback is not used.
@ -37,12 +37,12 @@ jobs:
# Ensures consistent BuildKit version (not coupled to Docker Engine),
# and increased compatibility of the build cache vs mixing buildx drivers.
- name: 'Set up Docker Buildx'
uses: docker/setup-buildx-action@v2.9.1
uses: docker/setup-buildx-action@v3.0.0
# Importing from the cache should create the image within approx 30 seconds:
# NOTE: `qemu` step is not needed as we only test for AMD64.
- name: 'Build AMD64 image from cache'
uses: docker/build-push-action@v4.1.1
uses: docker/build-push-action@v5.1.0
with:
context: .
tags: mailserver-testing:ci
@ -55,13 +55,13 @@ jobs:
provenance: false
- name: 'Run the Anchore Grype scan action'
uses: anchore/scan-action@v3.3.6
uses: anchore/scan-action@v3.5.0
id: scan
with:
image: mailserver-testing:ci
fail-build: false
- name: 'Upload vulnerability report'
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ${{ steps.scan.outputs.sarif }}

View File

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Close stale issues
uses: actions/stale@v8
uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 20

View File

@ -1,6 +1,9 @@
name: Lint
on:
# A workflow that creates a PR will not trigger this workflow,
# Providing a manual trigger as a workaround
workflow_dispatch:
pull_request:
push:
branches: [ master ]
@ -13,7 +16,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Hadolint
run: make hadolint

View File

@ -10,7 +10,7 @@ docker run \
--user "$(id -u):$(id -g)" \
--volume "${PWD}:/docs" \
--name "build-docs" \
squidfunk/mkdocs-material:9.1.5 build --strict
squidfunk/mkdocs-material:9.5 build --strict
# Remove unnecessary build artifacts: https://github.com/squidfunk/mkdocs-material/issues/2519
# site/ is the build output folder.

1
.gitignore vendored
View File

@ -3,6 +3,7 @@
#################################################
.env
compose.override.yaml
docs/site/
docker-data/

View File

@ -2,10 +2,248 @@
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/v12.1.0...HEAD)
## [Unreleased](https://github.com/docker-mailserver/docker-mailserver/compare/v13.2.0...HEAD)
> **Note**: Changes and additions listed here are contained in the `:edge` image tag. These changes may not be as stable as released changes.
### Features
- **Authentication with OIDC / OAuth 2.0** 🎉
- DMS now supports authentication via OAuth2 (_via `XOAUTH2` or `OAUTHBEARER` SASL mechanisms_) from capable services (_like Roundcube_).
- This does not replace the need for an `ACCOUNT_PROVISIONER` (`FILE` / `LDAP`), which is required for an account to receive or send mail.
- Successful authentication (_via Dovecot PassDB_) still requires an existing account (_lookup via Dovecot UserDB_).
- **MTA-STS** (_Optional support for mandatory outgoing TLS encryption_)
- If enabled and the outbound recipient has an MTA-STS policy set, TLS is mandatory for delivering to that recipient.
- Enable via the ENV `ENABLE_MTA_STS=1`
- Supported by major email service providers like Gmail, Yahoo and Outlook.
### Updates
- **Tests**:
- Revised testing of service process management (supervisord) to be more robust ([#3780](https://github.com/docker-mailserver/docker-mailserver/pull/3780))
- Refactored mail sending ([#3747](https://github.com/docker-mailserver/docker-mailserver/pull/3747) & [#3772](https://github.com/docker-mailserver/docker-mailserver/pull/3772)):
- This change is a follow-up to [#3732](https://github.com/docker-mailserver/docker-mailserver/pull/3732) from DMS v13.2.
- `swaks` version is now the latest from Github releases instead of the Debian package.
- `_nc_wrapper`, `_send_mail` and related helpers expect the `.txt` filepath extension again.
- `sending.bash` helper methods were refactored to better integrate `swaks` and accommodate different usage contexts.
- `test/files/emails/existing/` files were removed similar to previous removal of SMTP auth files as they became redundant with `swaks`.
- **Internal:**
- tests: Replace `wc -l` with `grep -c` ([#3752](https://github.com/docker-mailserver/docker-mailserver/pull/3752))
- Postfix is now configured with `smtputf8_enable = no` in our default `main.cf` config (_instead of during container startup_). ([#3750](https://github.com/docker-mailserver/docker-mailserver/pull/3750))
- **Rspamd** ([#3726](https://github.com/docker-mailserver/docker-mailserver/pull/3726)):
- symbol scores for SPF, DKIM & DMARC were updated to more closely align with [RFC7489](https://www.rfc-editor.org/rfc/rfc7489#page-24); please note though that complete alignment is undesirable, because other symbols might be added as well, which changes the overall score calculation again, see [this issue](https://github.com/docker-mailserver/docker-mailserver/issues/3690#issuecomment-1866871996)
- **Docs:**
- Revised the SpamAssassin ENV docs to better communicate configuration and their relation to other ENV settings. ([#3756](https://github.com/docker-mailserver/docker-mailserver/pull/3756))
- Detailed how mail received is assigned a spam score by Rspamd and processed accordingly ([#3773](https://github.com/docker-mailserver/docker-mailserver/pull/3773))
### Fixes
- **Setup:**
- `setup` CLI - `setup dkim domain` now creates the keys files with the user owning the key directory ([#3783](https://github.com/docker-mailserver/docker-mailserver/pull/3783))
- **Dovecot:**
- During container startup for Dovecot Sieve, `.sievec` source files compiled to `.svbin` now have their `mtime` adjusted post setup to ensure it is always older than the associated `.svbin` file. This avoids superfluous error logs for sieve scripts that don't actually need to be compiled again ([#3779](https://github.com/docker-mailserver/docker-mailserver/pull/3779))
- **Internal:**
- `.gitattributes`: Always use LF line endings on checkout for files with shell script content ([#3755](https://github.com/docker-mailserver/docker-mailserver/pull/3755))
- Fix missing 'jaq' binary for ARM architecture ([#3766](https://github.com/docker-mailserver/docker-mailserver/pull/3766))
## [v13.2.0](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v13.2.0)
### Security
DMS is now secured against the [recently published spoofing attack "SMTP Smuggling"](https://www.postfix.org/smtp-smuggling.html) that affected Postfix ([#3727](https://github.com/docker-mailserver/docker-mailserver/pull/3727)):
- Postfix upgraded from `3.5.18` to `3.5.23` which provides the [long-term fix with `smtpd_forbid_bare_newline = yes`](https://www.postfix.org/smtp-smuggling.html#long)
- If you are unable to upgrade to this release of DMS, you may follow [these instructions](https://github.com/docker-mailserver/docker-mailserver/issues/3719#issuecomment-1870865118) for applying the [short-term workaround](https://www.postfix.org/smtp-smuggling.html#short).
- This change should not cause compatibility concerns for legitimate mail clients, however if you use software like `netcat` to send mail to DMS (_like our test-suite previously did_) it may now be rejected (_especially with the the short-term workaround `smtpd_data_restrictions = reject_unauth_pipelining`_).
- **NOTE:** This Postfix update also includes the new parameter [`smtpd_forbid_bare_newline_exclusions`](https://www.postfix.org/postconf.5.html#smtpd_forbid_bare_newline_exclusions) which defaults to `$mynetworks` for excluding trusted mail clients excluded from the restriction.
- With our default `PERMIT_DOCKER=none` this is not a concern.
- Presently the Docker daemon config has `user-proxy: true` enabled by default.
- On a host that can be reached by IPv6, this will route to a DMS IPv4 only container implicitly through the Docker network bridge gateway which rewrites the source address.
- If your `PERMIT_DOCKER` setting allows that gateway IP, then it is part of `$mynetworks` and this attack would not be prevented from such connections.
- If this affects your deployment, refer to [our IPv6 docs](https://docker-mailserver.github.io/docker-mailserver/v13.2/config/advanced/ipv6/) for advice on handling IPv6 correctly in Docker. Alternatively [use our `postfix-main.cf`](https://docker-mailserver.github.io/docker-mailserver/v13.2/config/advanced/override-defaults/postfix/) to set `smtpd_forbid_bare_newline_exclusions=` as empty.
### Updates
- The test suite now uses `swaks` instead of `nc`, which has multiple benefits ([#3732](https://github.com/docker-mailserver/docker-mailserver/pull/3732)):
- `swaks` handles pipelining correctly, hence we can now use `reject_unauth_pipelining` in Postfix's configuration.
- `swaks` provides better CLI options that make many files superflous.
- `swaks` can also replace `openssl s_client` and handles authentication on submission ports better.
- **Postfix:**
- We now defer rejection from unauthorized pipelining until the SMTP `DATA` command via `smtpd_data_restrictions` (_i.e. at the end of the mail transfer transaction_) ([#3744](https://github.com/docker-mailserver/docker-mailserver/pull/3744))
- Prevously our configuration only handled this during the client and recipient restriction stages. Postfix will flag this activity when encountered, but the rejection now is handled at `DATA` where unauthorized pipelining would have been valid from this point.
- If you had the Amavis service enabled (default), this restriction was already in place. Otherwise the concerns expressed with `smtpd_data_restrictions = reject_unauth_pipelining` from the security section above apply. We have permitted trusted clients (_`$mynetworks` or authenticated_) to bypass this restriction.
## [v13.1.0](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v13.1.0)
### Added
- **Dovecot:**
- ENV `ENABLE_IMAP` ([#3703](https://github.com/docker-mailserver/docker-mailserver/pull/3703))
- **Tests:**
- You can now use `make run-local-instance` to run a DMS image that was built locally to test changes ([#3663](https://github.com/docker-mailserver/docker-mailserver/pull/3663))
- **Internal**:
- Log a warning when update-check is enabled, but no stable release image is used ([#3684](https://github.com/docker-mailserver/docker-mailserver/pull/3684))
### Updates
- **Documentation:**
- Debugging - Raise awareness in the troubleshooting page for a common misconfiguration when deviating from our advice by using a bare domain ([#3680](https://github.com/docker-mailserver/docker-mailserver/pull/3680))
- Debugging - Raise awareness of temporary downtime during certificate renewal that can cause a failure to deliver local mail ([#3718](https://github.com/docker-mailserver/docker-mailserver/pull/3718))
- **Internal:**
- Postfix configures `virtual_mailbox_maps` and `virtual_transport` during startup instead of using defaults (configured for Dovecot) via our `main.cf` ([#3681](https://github.com/docker-mailserver/docker-mailserver/pull/3681))
- **Rspamd:**
- Upgraded to version `3.7.5`. This was previously inconsistent between our AMD64 (`3.5`) and ARM64 (`3.4`) images ([#3686](https://github.com/docker-mailserver/docker-mailserver/pull/3686))
### Fixed
- **Internal**:
- The container startup welcome log message now references `DMS_RELEASE` ([#3676](https://github.com/docker-mailserver/docker-mailserver/pull/3676))
- `VERSION` was incremented for prior releases to be notified of the v13.0.1 patch release ([#3676](https://github.com/docker-mailserver/docker-mailserver/pull/3676))
- `VERSION` is no longer included in the image ([#3711](https://github.com/docker-mailserver/docker-mailserver/pull/3711))
- Update-check: fix 'read' exit status ([#3688](https://github.com/docker-mailserver/docker-mailserver/pull/3688))
- `ENABLE_QUOTAS=0` no longer tries to remove non-existent config ([#3715](https://github.com/docker-mailserver/docker-mailserver/pull/3715))
- The `postgrey` service now writes logs to the supervisor directory like all other services. Previously this was `/var/log/mail/mail.log` ([#3724](https://github.com/docker-mailserver/docker-mailserver/pull/3724))
- **Rspamd:**
- Switch to official arm64 packages to avoid segfaults ([#3686](https://github.com/docker-mailserver/docker-mailserver/pull/3686))
- **CI / Automation:**
- The lint workflow can now be manually triggered by maintainers ([#3714]https://github.com/docker-mailserver/docker-mailserver/pull/3714)
## [v13.0.1](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v13.0.1)
This patch release fixes two bugs that Rspamd users encountered with the `v13.0.0` release. Big thanks to the those that helped to identify these issues! ❤️
### Fixed
- **Internal:**
- The update check service now queries the latest GH release for a version tag (_instead of from a `VERSION` file at the GH repo_). This should provide more reliable update notifications ([#3666](https://github.com/docker-mailserver/docker-mailserver/pull/3666))
- **Rspamd:**
- The check for correct permission on the private key when signing e-mails with DKIM was flawed. The result was that a false warning was emitted ([#3669](https://github.com/docker-mailserver/docker-mailserver/pull/3669))
- When [`RSPAMD_CHECK_AUTHENTICATED=0`][docs::env-rspamd-check-auth], DKIM signing for outbound e-mail was disabled, which is undesirable ([#3669](https://github.com/docker-mailserver/docker-mailserver/pull/3669)). **Make sure to check the documentation of [`RSPAMD_CHECK_AUTHENTICATED`][docs::env-rspamd-check-auth]**!
[docs::env-rspamd-check-auth]: https://docker-mailserver.github.io/docker-mailserver/v13.0/config/environment/#rspamd_check_authenticated
## [v13.0.0](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v13.0.0)
### Breaking
- **LDAP:**
- ENV `LDAP_SERVER_HOST`, `DOVECOT_URIS`, and `SASLAUTHD_LDAP_SERVER` will now log an error if the LDAP URI scheme is missing. Previously there was an implicit fallback to `ldap://` ([#3522](https://github.com/docker-mailserver/docker-mailserver/pull/3522))
- `ENABLE_LDAP=1` is no longer supported, please use `ACCOUNT_PROVISIONER=LDAP` ([#3507](https://github.com/docker-mailserver/docker-mailserver/pull/3507))
- **Rspamd:**
- The deprecated path for the Rspamd custom commands file (`/tmp/docker-mailserver/rspamd-modules.conf`) now prevents successful startup. The correct path is `/tmp/docker-mailserver/rspamd/custom-commands.conf`.
- **Dovecot:**
- Dovecot mail storage per account in `/var/mail` previously shared the same path for the accounts home directory ([#3335](https://github.com/docker-mailserver/docker-mailserver/pull/3335))
- The home directory now is a subdirectory `home/`. This change better supports sieve scripts.
- **NOTE:** The change has not yet been implemented for `ACCOUNT_PROVISIONER=LDAP`.
- **Postfix:**
- `/etc/postfix/master.cf` has renamed the "smtps" service to "submissions" ([#3235](https://github.com/docker-mailserver/docker-mailserver/pull/3235))
- This is the modern `/etc/services` name for port 465, aligning with the similar "submission" port 587.
- Postfix now defaults to supporting DSNs (_[Delivery Status Notifications](https://github.com/docker-mailserver/docker-mailserver/pull/3572#issuecomment-1751880574)_) only for authenticated users (_via ports 465 + 587_). This is a security measure to reduce spammer abuse of your DMS instance as a backscatter source. ([#3572](https://github.com/docker-mailserver/docker-mailserver/pull/3572))
- If you need to modify this change, please let us know by opening an issue / discussion.
- You can [opt out (_enable DSNs_) via the `postfix-main.cf` override support](https://docker-mailserver.github.io/docker-mailserver/v12.1/config/advanced/override-defaults/postfix/) using the contents: `smtpd_discard_ehlo_keywords =`.
- Likewise for authenticated users, the submission(s) ports (465 + 587) are configured internally via `master.cf` to keep DSNs enabled (_since authentication protects from abuse_).
If necessary, DSNs for authenticated users can be disabled via the `postfix-master.cf` override with the following contents:
```cf
submission/inet/smtpd_discard_ehlo_keywords=silent-discard,dsn
submissions/inet/smtpd_discard_ehlo_keywords=silent-discard,dsn
```
### Added
- **Features:**
- `getmail` as an alternative to `fetchmail` ([#2803](https://github.com/docker-mailserver/docker-mailserver/pull/2803))
- `setup` CLI - `setup fail2ban` gained a new `status <JAIL>` subcommand ([#3455](https://github.com/docker-mailserver/docker-mailserver/pull/3455))
- **Environment Variables:**
- `MARK_SPAM_AS_READ`. When set to `1`, marks incoming spam as "read" to avoid unwanted "new mail" notifications for junk mail ([#3489](https://github.com/docker-mailserver/docker-mailserver/pull/3489))
- `DMS_VMAIL_UID` and `DMS_VMAIL_GID` allow changing the default ID values (`5000:5000`) for the Dovecot vmail user and group ([#3550](https://github.com/docker-mailserver/docker-mailserver/pull/3550))
- `RSPAMD_CHECK_AUTHENTICATED` allows authenticated users to avoid additional security checks by Rspamd ([#3440](https://github.com/docker-mailserver/docker-mailserver/pull/3440))
- **Documentation:**
- Use-case examples / tutorials:
- iOS mail push support ([#3513](https://github.com/docker-mailserver/docker-mailserver/pull/3513))
- Guide for setting up Dovecot Authentication via Lua ([#3579](https://github.com/docker-mailserver/docker-mailserver/pull/3579))
- Guide for integrating with the Crowdsec service ([#3651](https://github.com/docker-mailserver/docker-mailserver/pull/3651))
- Debugging page:
- New compatibility section ([#3404](https://github.com/docker-mailserver/docker-mailserver/pull/3404))
- Now advises how to (re)start DMS correctly ([#3654](https://github.com/docker-mailserver/docker-mailserver/pull/3654))
- Better communicate distinction between DMS FQDN and DMS mail accounts ([#3372](https://github.com/docker-mailserver/docker-mailserver/pull/3372))
- Traefik example now includes `passthrough=true` on implicit ports ([#3568](https://github.com/docker-mailserver/docker-mailserver/pull/3568))
- Rspamd docs have received a variety of revisions ([#3318](https://github.com/docker-mailserver/docker-mailserver/pull/3318), [#3325](https://github.com/docker-mailserver/docker-mailserver/pull/3325), [#3329](https://github.com/docker-mailserver/docker-mailserver/pull/3329))
- IPv6 config examples with content tabs ([#3436](https://github.com/docker-mailserver/docker-mailserver/pull/3436))
- Mention [internet.nl](https://internet.nl/test-mail/) as another testing service ([#3445](https://github.com/docker-mailserver/docker-mailserver/pull/3445))
- `setup alias add ...` CLI help message now includes an example for aliasing to multiple recipients ([#3600](https://github.com/docker-mailserver/docker-mailserver/pull/3600))
- `SPAMASSASSIN_SPAM_TO_INBOX=1`, now emits a debug log to raise awareness that `SA_KILL` will be ignored ([#3360](https://github.com/docker-mailserver/docker-mailserver/pull/3360))
- `CLAMAV_MESSAGE_SIZE_LIMIT` now logs a warning when the value exceeds what ClamAV is capable of supporting (4GiB max scan size [#3332](https://github.com/docker-mailserver/docker-mailserver/pull/3332), 2GiB max file size [#3341](https://github.com/docker-mailserver/docker-mailserver/pull/3341))
- Added note to caution against changing `mydestination` in Postfix's `main.cf` ([#3316](https://github.com/docker-mailserver/docker-mailserver/pull/3316))
- **Internal:**
- Added a wrapper to update Postfix configuration safely ([#3484](https://github.com/docker-mailserver/docker-mailserver/pull/3484), [#3503](https://github.com/docker-mailserver/docker-mailserver/pull/3503))
- Add debug group to `packages.sh` ([#3578](https://github.com/docker-mailserver/docker-mailserver/pull/3578))
- **Tests:**
- Additional linting check for BASH syntax ([#3369](https://github.com/docker-mailserver/docker-mailserver/pull/3369))
### Updates
- **Misc:**
- Changed `setup config dkim` default key size to `2048` (`open-dkim`) ([#3508](https://github.com/docker-mailserver/docker-mailserver/pull/3508))
- **Postfix:**
- Dropped special bits from `maildrop/` and `public/` directory permissions ([#3625](https://github.com/docker-mailserver/docker-mailserver/pull/3625))
- **Rspamd:**
- Adjusted learning of ham ([#3334](https://github.com/docker-mailserver/docker-mailserver/pull/3334))
- Adjusted `antivirus.conf` ([#3331](https://github.com/docker-mailserver/docker-mailserver/pull/3331))
- `logrotate` setup + Rspamd log path + tests log helper fallback path ([#3576](https://github.com/docker-mailserver/docker-mailserver/pull/3576))
- Setup during container startup is now more resilient ([#3578](https://github.com/docker-mailserver/docker-mailserver/pull/3578))
- Changed DKIM default config location ([#3597](https://github.com/docker-mailserver/docker-mailserver/pull/3597))
- Removed the symlink for the `override.d/` directory in favor of using `cp`, integrated into the changedetector service, added a `--force` option for the Rspamd DKIM management, and provided a dedicated helper script for common ENV variables ([#3599](https://github.com/docker-mailserver/docker-mailserver/pull/3599))
- Required permissions are now verified for DKIM private key files ([#3627](https://github.com/docker-mailserver/docker-mailserver/pull/3627))
- **Documentation:**
- Documentation aligned to Compose v2 conventions, `docker-compose` command changed to `docker compose`, `docker-compose.yaml` to `compose.yaml` ([#3295](https://github.com/docker-mailserver/docker-mailserver/pull/3295))
- Restored missing edit button ([#3338](https://github.com/docker-mailserver/docker-mailserver/pull/3338))
- Complete rewrite of the IPv6 page ([#3244](https://github.com/docker-mailserver/docker-mailserver/pull/3244), [#3531](https://github.com/docker-mailserver/docker-mailserver/pull/3531))
- Complete rewrite of the "Update and Cleanup" maintenance page ([#3539](https://github.com/docker-mailserver/docker-mailserver/pull/3539), [#3583](https://github.com/docker-mailserver/docker-mailserver/pull/3583))
- Improved debugging page advice on working with logs ([#3626](https://github.com/docker-mailserver/docker-mailserver/pull/3626), [#3640](https://github.com/docker-mailserver/docker-mailserver/pull/3640))
- Clarified the default for ENV `FETCHMAIL_PARALLEL` ([#3603](https://github.com/docker-mailserver/docker-mailserver/pull/3603))
- Removed port 25 from FAQ entry for mail client ports supporting authenticated submission ([#3496](https://github.com/docker-mailserver/docker-mailserver/pull/3496))
- Updated home path in docs for Dovecot Sieve ([#3370](https://github.com/docker-mailserver/docker-mailserver/pull/3370), [#3650](https://github.com/docker-mailserver/docker-mailserver/pull/3650))
- Fixed path to `rspamd.log` ([#3585](https://github.com/docker-mailserver/docker-mailserver/pull/3585))
- "Optional Config" page now uses consistent lowercase convention for directory names ([#3629](https://github.com/docker-mailserver/docker-mailserver/pull/3629))
- `CONTRIBUTORS.md`: Removed redundant "All Contributors" section ([#3638](https://github.com/docker-mailserver/docker-mailserver/pull/3638))
- **Internal:**
- LDAP config improvements (Removed implicit `ldap://` LDAP URI scheme fallback) ([#3522](https://github.com/docker-mailserver/docker-mailserver/pull/3522))
- Changed style conventions for internal scripts ([#3361](https://github.com/docker-mailserver/docker-mailserver/pull/3361), [#3364](https://github.com/docker-mailserver/docker-mailserver/pull/3364), [#3365](https://github.com/docker-mailserver/docker-mailserver/pull/3365), [#3366](https://github.com/docker-mailserver/docker-mailserver/pull/3366), [#3368](https://github.com/docker-mailserver/docker-mailserver/pull/3368), [#3464](https://github.com/docker-mailserver/docker-mailserver/pull/3464))
- **CI / Automation:**
- `.gitattributes` now ensures files are committed with `eol=lf` ([#3527](https://github.com/docker-mailserver/docker-mailserver/pull/3527))
- Revised the GitHub issue bug report template ([#3317](https://github.com/docker-mailserver/docker-mailserver/pull/3317), [#3381](https://github.com/docker-mailserver/docker-mailserver/pull/3381), [#3435](https://github.com/docker-mailserver/docker-mailserver/pull/3435))
- Clarified that the issue tracker is not for personal support ([#3498](https://github.com/docker-mailserver/docker-mailserver/pull/3498), [#3502](https://github.com/docker-mailserver/docker-mailserver/pull/3502))
- Bumped versions of miscellaneous software (also shoutout to @dependabot) ([#3371](https://github.com/docker-mailserver/docker-mailserver/pull/3371), [#3584](https://github.com/docker-mailserver/docker-mailserver/pull/3584), [#3504](https://github.com/docker-mailserver/docker-mailserver/pull/3504), [#3516](https://github.com/docker-mailserver/docker-mailserver/pull/3516))
- **Tests:**
- Refactored LDAP tests to current conventions ([#3483](https://github.com/docker-mailserver/docker-mailserver/pull/3483))
- Changed OpenLDAP image to `bitnami/openldap` ([#3494](https://github.com/docker-mailserver/docker-mailserver/pull/3494))
- Revised LDAP config + setup ([#3514](https://github.com/docker-mailserver/docker-mailserver/pull/3514))
- Added tests for the helper function `_add_to_or_update_postfix_main()` ([#3505](https://github.com/docker-mailserver/docker-mailserver/pull/3505))
- EditorConfig Checker lint now uses a mount path to `/check` instead of `/ci` ([#3655](https://github.com/docker-mailserver/docker-mailserver/pull/3655))
### Fixed
- **Security:**
- Fixed issue with concatenating `$dmarc_milter` and `$dkim_milter` in `main.cf` ([#3380](https://github.com/docker-mailserver/docker-mailserver/pull/3380))
- Fixed Rspamd DKIM signing for inbound emails ([#3439](https://github.com/docker-mailserver/docker-mailserver/pull/3439), [#3453](https://github.com/docker-mailserver/docker-mailserver/pull/3453))
- OpenDKIM key generation is no longer broken when Rspamd is also enabled ([#3535](https://github.com/docker-mailserver/docker-mailserver/pull/3535))
- **Internal:**
- The "database" files (_for managing users and aliases_) now correctly filters within lookup query ([#3359](https://github.com/docker-mailserver/docker-mailserver/pull/3359))
- `_setup_spam_to_junk()` no longer registered when `SMTP_ONLY=1` ([#3385](https://github.com/docker-mailserver/docker-mailserver/pull/3385))
- Dovecot `fts_xapian` is now compiled from source to match the Dovecot package ABI ([#3373](https://github.com/docker-mailserver/docker-mailserver/pull/3373))
- **CI:**
- Scheduled build now have the correct permissions to run successfully ([#3345](https://github.com/docker-mailserver/docker-mailserver/pull/3345))
- **Documentation:**
- Miscellaneous spelling and wording improvements ([#3324](https://github.com/docker-mailserver/docker-mailserver/pull/3324), [#3330](https://github.com/docker-mailserver/docker-mailserver/pull/3330), [#3337](https://github.com/docker-mailserver/docker-mailserver/pull/3337), [#3339](https://github.com/docker-mailserver/docker-mailserver/pull/3339), [#3344](https://github.com/docker-mailserver/docker-mailserver/pull/3344), [#3367](https://github.com/docker-mailserver/docker-mailserver/pull/3367), [#3411](https://github.com/docker-mailserver/docker-mailserver/pull/3411), [#3443](https://github.com/docker-mailserver/docker-mailserver/pull/3443))
- **Tests:**
- Run `pgrep` within the actual container ([#3553](https://github.com/docker-mailserver/docker-mailserver/pull/3553))
- `lmtp_ip.bats` improved partial failure output ([#3552](https://github.com/docker-mailserver/docker-mailserver/pull/3552))
- Improvements to LDIF test data ([#3506](https://github.com/docker-mailserver/docker-mailserver/pull/3506))
- Normalized for `.gitattributes` + improved `eclint` coverage ([#3566](https://github.com/docker-mailserver/docker-mailserver/pull/3566))
- Fixed ShellCheck linting for BATS tests ([#3347](https://github.com/docker-mailserver/docker-mailserver/pull/3347))
## [v12.1.0](https://github.com/docker-mailserver/docker-mailserver/releases/tag/v12.1.0)
### Added
@ -17,7 +255,7 @@ All notable changes to this project will be documented in this file. The format
- add option to re-enable `reject_unknown_client_hostname` after #3248 ([#3255](https://github.com/docker-mailserver/docker-mailserver/pull/3255))
- add DKIM helper script ([#3286](https://github.com/docker-mailserver/docker-mailserver/pull/3286))
- make `policyd-spf` configurable ([#3246](https://github.com/docker-mailserver/docker-mailserver/pull/3246))
- add 'log' command to setup for Fail2Ban ([#3299](https://github.com/docker-mailserver/docker-mailserver/pull/3299))
- add 'log' command to set up for Fail2Ban ([#3299](https://github.com/docker-mailserver/docker-mailserver/pull/3299))
- `setup` command now expects accounts and aliases to be mutually exclusive ([#3270](https://github.com/docker-mailserver/docker-mailserver/pull/3270))
### Updated
@ -206,7 +444,11 @@ Notable changes are:
### Summary
This release features a lot of small and medium-sized changes, many related to how the image is build and tested during CI. The build now requires Docker Buildkit as the ClamAV Signatures are added via `COPY --link ...` during build-time. Moreover, the build is now multi-stage. `ENABLE_LDAP` is now deprecated.
This release features a lot of small and medium-sized changes, many related to how the image is build and tested during CI. The build now multi-stage based and requires Docker Buildkit, as the ClamAV Signatures are added via `COPY --link ...` during build-time.
### Deprecated
- The environment variable `ENABLE_LDAP` is deprecated and will be removed in [13.0.0]. Use `ACCOUNT_PROVISIONER=LDAP` now.
### Added
@ -233,10 +475,6 @@ This release features a lot of small and medium-sized changes, many related to h
- **build**: adjust build arguments
- **build**: enhance build process
### Deprecated
- The environment variable `ENABLE_LDAP` is deprecated and will be removed in [13.0.0]. Use `ACCOUNT_PROVISIONER=LDAP` now.
### Removed
- **configuration**: remove unnecessary configuration files
@ -303,8 +541,8 @@ In this release the relay-host support saw [significant internal refactoring](ht
1. **Many** minor improvements were made (cleanup & refactoring). Please refer to the section below to get an overview over all improvements. Moreover, there was a lot of cleanup in the scripts and in the tests. The documentation was adjusted accordingly.
2. New environment variables were added:
1. [`CLAMAV_MESSAGE_SIZE_LIMIT`](https://docker-mailserver.github.io/docker-mailserver/v11.0/config/environment/#clamav_message_size_limit)
2. [`TZ`](https://docker-mailserver.github.io/docker-mailserver/v11.0/config/environment/#tz)
1. [`CLAMAV_MESSAGE_SIZE_LIMIT`](https://docker-mailserver.github.io/docker-mailserver/v11.0/config/environment/#clamav_message_size_limit)
2. [`TZ`](https://docker-mailserver.github.io/docker-mailserver/v11.0/config/environment/#tz)
3. SpamAssassin KAM was added with [`ENABLE_SPAMASSASSIN_KAM`](https://docker-mailserver.github.io/docker-mailserver/v11.0/config/environment/#enable_spamassassin_kam).
4. The `fail2ban` command was reworked and can now ban IP addresses as well.
5. There were a few small fixes, especially when it comes to bugs in scripts and service restart loops (no functionality changes, only fixes of existing functionality). When building an image from the Dockerfile - Installation of Postfix on modern Linux distributions should now always succeed.
@ -360,8 +598,7 @@ In this release the relay-host support saw [significant internal refactoring](ht
### Critical Changes
1. This release fixes a critical issue for LDAP users, installing a needed package on Debian 11
on build-time. Moreover, a race-condition was eliminated ([#2341](https://github.com/docker-mailserver/docker-mailserver/pull/2341)).
1. This release fixes a critical issue for LDAP users, installing a needed package on Debian 11 on build-time. Moreover, a race-condition was eliminated ([#2341](https://github.com/docker-mailserver/docker-mailserver/pull/2341)).
2. A resource leak in `check-for-changes.sh` was fixed ([#2401](https://github.com/docker-mailserver/docker-mailserver/pull/2401))
### Other Minor Changes

File diff suppressed because it is too large Load Diff

View File

@ -106,6 +106,14 @@ EOF
# -----------------------------------------------
COPY target/rspamd/local.d/ /etc/rspamd/local.d/
COPY target/rspamd/scores.d/* /etc/rspamd/scores.d/
# -----------------------------------------------
# --- OAUTH2 ------------------------------------
# -----------------------------------------------
COPY target/dovecot/auth-oauth2.conf.ext /etc/dovecot/conf.d
COPY target/dovecot/dovecot-oauth2.conf.ext /etc/dovecot
# -----------------------------------------------
# --- LDAP & SpamAssassin's Cron ----------------
@ -134,9 +142,7 @@ EOF
COPY target/postsrsd/postsrsd /etc/default/postsrsd
COPY target/postgrey/postgrey /etc/default/postgrey
COPY target/postgrey/postgrey.init /etc/init.d/postgrey
RUN <<EOF
chmod 755 /etc/init.d/postgrey
mkdir /var/run/postgrey
chown postgrey:postgrey /var/run/postgrey
curl -Lsfo /etc/postgrey/whitelist_clients https://postgrey.schweikert.ch/pub/postgrey_whitelist_clients
@ -193,6 +199,15 @@ COPY target/opendmarc/opendmarc.conf /etc/opendmarc.conf
COPY target/opendmarc/default-opendmarc /etc/default/opendmarc
COPY target/opendmarc/ignore.hosts /etc/opendmarc/ignore.hosts
# --------------------------------------------------
# --- postfix-mta-sts-daemon -----------------------
# --------------------------------------------------
COPY target/mta-sts-daemon/mta-sts-daemon.yml /etc/mta-sts-daemon.yml
RUN <<EOF
mkdir /var/run/mta-sts
chown -R _mta-sts:root /var/run/mta-sts
EOF
# --------------------------------------------------
# --- Fetchmail, Getmail, Postfix & Let'sEncrypt ---
# --------------------------------------------------
@ -279,8 +294,6 @@ RUN <<EOF
update-locale
EOF
COPY VERSION /
COPY \
target/bin/* \
target/scripts/*.sh \
@ -297,8 +310,8 @@ COPY target/scripts/startup/setup.d /usr/local/bin/setup.d
#
FROM stage-main AS stage-final
ARG DMS_RELEASE=edge
ARG VCS_REVISION=unknown
ARG VCS_VERSION=edge
WORKDIR /
EXPOSE 25 587 143 465 993 110 995 4190
@ -322,11 +335,12 @@ LABEL org.opencontainers.image.title="docker-mailserver"
LABEL org.opencontainers.image.vendor="The Docker Mailserver Organization"
LABEL org.opencontainers.image.authors="The Docker Mailserver Organization on GitHub"
LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.description="A fullstack but simple mail server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.). Only configuration files, no SQL database."
LABEL org.opencontainers.image.description="A fullstack but simple mail server (SMTP, IMAP, LDAP, Anti-spam, Anti-virus, etc.). Only configuration files, no SQL database."
LABEL org.opencontainers.image.url="https://github.com/docker-mailserver"
LABEL org.opencontainers.image.documentation="https://github.com/docker-mailserver/docker-mailserver/blob/master/README.md"
LABEL org.opencontainers.image.source="https://github.com/docker-mailserver/docker-mailserver"
# ARG invalidates cache when it is used by a layer (implicitly affects RUN)
# Thus to maximize cache, keep these lines last:
LABEL org.opencontainers.image.revision=${VCS_REVISION}
LABEL org.opencontainers.image.version=${VCS_VERSION}
LABEL org.opencontainers.image.version=${DMS_RELEASE}
ENV DMS_RELEASE=${DMS_RELEASE}

View File

@ -18,11 +18,7 @@ BATS_PARALLEL_JOBS ?= 2
all: lint build generate-accounts tests clean
build: ALWAYS_RUN
@ DOCKER_BUILDKIT=1 docker build \
--tag $(IMAGE_NAME) \
--build-arg VCS_VERSION=$(shell git rev-parse --short HEAD) \
--build-arg VCS_REVISION=$(shell cat VERSION) \
.
@ docker build --tag $(IMAGE_NAME) .
generate-accounts: ALWAYS_RUN
@ cp test/config/templates/postfix-accounts.cf test/config/postfix-accounts.cf
@ -36,6 +32,22 @@ clean: ALWAYS_RUN
-@ while read -r LINE; do [[ $${LINE} =~ test/.+ ]] && FILES+=("/mnt$${LINE#test}"); done < .gitignore ; \
docker run --rm -v "$(REPOSITORY_ROOT)/test/:/mnt" alpine ash -c "rm -rf $${FILES[@]}"
run-local-instance: ALWAYS_RUN
bash -c 'sleep 8 ; ./setup.sh email add postmaster@example.test 123' &
docker run --rm --interactive --tty --name dms-test_example \
--env OVERRIDE_HOSTNAME=mail.example.test \
--env POSTFIX_INET_PROTOCOLS=ipv4 \
--env DOVECOT_INET_PROTOCOLS=ipv4 \
--env ENABLE_CLAMAV=0 \
--env ENABLE_AMAVIS=0 \
--env ENABLE_RSPAMD=0 \
--env ENABLE_OPENDKIM=0 \
--env ENABLE_OPENDMARC=0 \
--env ENABLE_POLICYD_SPF=0 \
--env ENABLE_SPAMASSASSIN=0 \
--env LOG_LEVEL=trace \
$(IMAGE_NAME)
# -----------------------------------------------
# --- Tests ------------------------------------
# -----------------------------------------------

View File

@ -11,7 +11,7 @@
## :page_with_curl: About
A production-ready fullstack but simple containerized mail server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.). Only configuration files, no SQL database. Keep it simple and versioned. Easy to deploy and upgrade. Originally created by @tomav, this project is now maintained by volunteers since January 2021.
A production-ready fullstack but simple containerized mail server (SMTP, IMAP, LDAP, Anti-spam, Anti-virus, etc.). Only configuration files, no SQL database. Keep it simple and versioned. Easy to deploy and upgrade. Originally created by @tomav, this project is now maintained by volunteers since January 2021.
## :bulb: Documentation
@ -48,3 +48,4 @@ If you have issues, please search through [the documentation][documentation::web
- Support for [LetsEncrypt](https://letsencrypt.org/), manual and self-signed certificates
- A [setup script](https://docker-mailserver.github.io/docker-mailserver/latest/config/setup.sh) for easy configuration and maintenance
- SASLauthd with LDAP authentication
- OAuth2 authentication (_via `XOAUTH2` or `OAUTHBEARER` SASL mechanisms_)

View File

@ -1 +1 @@
12.1.0
13.2.0

View File

@ -9,7 +9,7 @@ services:
# https://docker-mailserver.github.io/docker-mailserver/latest/config/security/understanding-the-ports/
# To avoid conflicts with yaml base-60 float, DO NOT remove the quotation marks.
ports:
- "25:25" # SMTP (explicit TLS => STARTTLS)
- "25:25" # SMTP (explicit TLS => STARTTLS, Authentication is DISABLED => use port 465/587 instead)
- "143:143" # IMAP4 (explicit TLS => STARTTLS)
- "465:465" # ESMTP (implicit TLS)
- "587:587" # ESMTP (explicit TLS => STARTTLS)

View File

@ -34,7 +34,6 @@ Those variables contain the LDAP lookup filters for postfix, using `%s` as the p
A really simple `LDAP_QUERY_FILTER` configuration, using only the _user filter_ and allowing only `admin@*` to spoof any sender addresses.
```yaml
- ENABLE_LDAP=1 # with the :edge tag, use ACCOUNT_PROVISIONER
- LDAP_START_TLS=yes
- ACCOUNT_PROVISIONER=LDAP
- LDAP_SERVER_HOST=ldap.example.org
@ -57,7 +56,7 @@ These variables specify the LDAP filters that dovecot uses to determine if a use
This is split into the following two lookups, both using `%u` as the placeholder for the full login name ([see dovecot documentation for a full list of placeholders](https://doc.dovecot.org/configuration_manual/config_file/config_variables/)). Usually you only need to set `DOVECOT_USER_FILTER`, in which case it will be used for both filters.
- `DOVECOT_USER_FILTER` is used to get the account details (uid, gid, home directory, quota, ...) of a user.
- `DOVECOT_PASS_FILTER` is used to get the password information of the user, and is in pretty much all cases identical to `DOVECOT_USER_FILTER` (which is the default behaviour if left away).
- `DOVECOT_PASS_FILTER` is used to get the password information of the user, and is in pretty much all cases identical to `DOVECOT_USER_FILTER` (which is the default behavior if left away).
If your directory doesn't have the [postfix-book schema](https://github.com/variablenix/ldap-mail-schema/blob/master/postfix-book.schema) installed, then you must change the internal attribute handling for dovecot. For this you have to change the `pass_attr` and the `user_attr` mapping, as shown in the example below:
@ -215,7 +214,6 @@ The changes on the configurations necessary to work with Active Directory (**onl
- ENABLE_POSTGREY=1
# >>> Postfix LDAP Integration
- ENABLE_LDAP=1 # with the :edge tag, use ACCOUNT_PROVISIONER
- ACCOUNT_PROVISIONER=LDAP
- LDAP_SERVER_HOST=ldap.example.org
- LDAP_BIND_DN=cn=admin,ou=users,dc=example,dc=org
@ -284,7 +282,6 @@ The changes on the configurations necessary to work with Active Directory (**onl
# <<< SASL Authentication
# >>> Postfix Ldap Integration
- ENABLE_LDAP=1 # with the :edge tag, use ACCOUNT_PROVISIONER
- ACCOUNT_PROVISIONER=LDAP
- LDAP_SERVER_HOST=<yourLdapContainer/yourLdapServer>
- LDAP_SEARCH_BASE=dc=mydomain,dc=loc

View File

@ -0,0 +1,69 @@
---
title: 'Advanced | Basic OAuth2 Authentication'
---
## Introduction
!!! warning "This is only a supplement to the existing account provisioners"
Accounts must still be managed via the configured [`ACCOUNT_PROVISIONER`][env::account-provisioner] (FILE or LDAP).
Reasoning for this can be found in [#3480][gh-pr::oauth2]. Future iterations on this feature may allow it to become a full account provisioner.
[gh-pr::oauth2]: https://github.com/docker-mailserver/docker-mailserver/pull/3480
[env::account-provisioner]: ../environment.md#account_provisioner
The present OAuth2 support provides the capability for 3rd-party applications such as Roundcube to authenticate with DMS (dovecot) by using a token obtained from an OAuth2 provider, instead of passing passwords around.
## Example (Authentik & Roundcube)
This example assumes you have:
- A working DMS server set up
- An Authentik server set up ([documentation](https://goauthentik.io/docs/installation/))
- A Roundcube server set up (either [docker](https://hub.docker.com/r/roundcube/roundcubemail/) or [bare metal](https://github.com/roundcube/roundcubemail/wiki/Installation))
!!! example "Setup Instructions"
=== "1. Docker Mailserver"
Edit the following values in `mailserver.env`:
```env
# -----------------------------------------------
# --- OAUTH2 Section ----------------------------
# -----------------------------------------------
# empty => OAUTH2 authentication is disabled
# 1 => OAUTH2 authentication is enabled
ENABLE_OAUTH2=1
# Specify the user info endpoint URL of the oauth2 provider
OAUTH2_INTROSPECTION_URL=https://authentik.example.com/application/o/userinfo/
```
=== "2. Authentik"
1. Create a new OAuth2 provider
2. Note the client id and client secret
3. Set the allowed redirect url to the equivalent of `https://roundcube.example.com/index.php/login/oauth` for your RoundCube instance.
=== "3. Roundcube"
Add the following to `oauth2.inc.php` ([documentation](https://github.com/roundcube/roundcubemail/wiki/Configuration)):
```php
$config['oauth_provider'] = 'generic';
$config['oauth_provider_name'] = 'Authentik';
$config['oauth_client_id'] = '<insert client id here>';
$config['oauth_client_secret'] = '<insert client secret here>';
$config['oauth_auth_uri'] = 'https://authentik.example.com/application/o/authorize/';
$config['oauth_token_uri'] = 'https://authentik.example.com/application/o/token/';
$config['oauth_identity_uri'] = 'https://authentik.example.com/application/o/userinfo/';
// Optional: disable SSL certificate check on HTTP requests to OAuth server. For possible values, see:
// http://docs.guzzlephp.org/en/stable/request-options.html#verify
$config['oauth_verify_peer'] = false;
$config['oauth_scope'] = 'email openid profile';
$config['oauth_identity_fields'] = ['email'];
// Boolean: automatically redirect to OAuth login when opening Roundcube without a valid session
$config['oauth_login_redirect'] = false;
```

View File

@ -60,7 +60,7 @@ Enable `ip6tables` support so that Docker will manage IPv6 networking rules as w
```
- `experimental: true` is currently required for `ip6tables: true` to work.
- `userland-proxy` setting [can potentially affect connection behaviour][gh-pull-3244-proxy] for local connections.
- `userland-proxy` setting [can potentially affect connection behavior][gh-pull-3244-proxy] for local connections.
Now restart the daemon if it's running: `systemctl restart docker`.
@ -92,12 +92,14 @@ Next, configure a network with an IPv6 subnet for your container with any of the
networks:
dms-ipv6:
enable_ipv6: true
subnet: fd00:cafe:face:feed::/64
ipam:
config:
- subnet: fd00:cafe:face:feed::/64
```
??? tip "Override the implicit `default` network"
You can optionally avoid the service assignment by [overriding the `default` user-defined network that Docker Compose generates](docker-docs-network-compose-default). Just replace `dms-ipv6` with `default`.
You can optionally avoid the service assignment by [overriding the `default` user-defined network that Docker Compose generates][docker-docs-network-compose-default]. Just replace `dms-ipv6` with `default`.
The Docker Compose `default` bridge is not affected by settings for the default `bridge` (aka `docker0`) in `/etc/docker/daemon.json`.
@ -130,7 +132,7 @@ Next, configure a network with an IPv6 subnet for your container with any of the
!!! warning "This approach is discouraged"
The [`bridge` network is considered legacy][docker-docs-network-bridge-legacy].
The [`bridge` network is considered legacy][docker-docs-network-bridge-legacy].
Add these two extra IPv6 settings to your daemon config. They only apply to the [default `bridge` docker network][docker-docs-ipv6-create-default] aka `docker0` (_which containers are attached to by default when using `docker run`_).

View File

@ -190,7 +190,10 @@ spec:
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
# Required to support SGID via `postdrop` executable
# in `/var/mail-state` for Postfix (maildrop + public dirs):
# https://github.com/docker-mailserver/docker-mailserver/pull/3625
allowPrivilegeEscalation: true
readOnlyRootFilesystem: false
runAsUser: 0
runAsGroup: 0

View File

@ -11,9 +11,9 @@ There are global and user specific filters which are filtering the incoming emai
Global filters are applied to EVERY incoming mail for EVERY email address.
To specify a global Sieve filter provide a `docker-data/dms/config/before.dovecot.sieve` or a `docker-data/dms/config/after.dovecot.sieve` file with your filter rules.
If any filter in this filtering chain discards an incoming mail, the delivery process will stop as well and the mail will not reach any following filters(e.g. global-before stops an incoming spam mail: The mail will get discarded and a user-specific filter won't get applied.)
If any filter in this filtering chain discards an incoming mail, the delivery process will stop as well and the mail will not reach any following filters (e.g. global-before stops an incoming spam mail: The mail will get discarded and a user-specific filter won't get applied.)
To specify a user-defined Sieve filter place a `.dovecot.sieve` file into a virtual user's mail folder e.g. `/var/mail/example.com/user1/.dovecot.sieve`. If this file exists dovecot will apply the filtering rules.
To specify a user-defined Sieve filter place a `.dovecot.sieve` file into a virtual user's mail folder (e.g. `/var/mail/example.com/user1/home/.dovecot.sieve`). If this file exists dovecot will apply the filtering rules.
It's even possible to install a user provided Sieve filter at startup during users setup: simply include a Sieve file in the `docker-data/dms/config/` path for each user login that needs a filter. The file name provided should be in the form `<user_login>.dovecot.sieve`, so for example for `user1@example.com` you should provide a Sieve file named `docker-data/dms/config/user1@example.com.dovecot.sieve`.
@ -69,12 +69,12 @@ It is possible to sort subaddresses such as `user+mailing-lists@example.com` int
require ["envelope", "fileinto", "mailbox", "subaddress", "variables"];
if envelope :detail :matches "to" "*" {
set :lower :upperfirst "tag" "${1}";
if mailboxexists "INBOX.${1}" {
fileinto "INBOX.${1}";
} else {
fileinto :create "INBOX.${tag}";
}
set :lower :upperfirst "tag" "${1}";
if mailboxexists "INBOX.${1}" {
fileinto "INBOX.${1}";
} else {
fileinto :create "INBOX.${tag}";
}
}
```

View File

@ -2,40 +2,52 @@
title: 'Maintenance | Update and Cleanup'
---
## Automatic Update
[`containrrr/watchtower`][watchtower-dockerhub] is a service that monitors Docker images for updates, automatically applying them to running containers.
Docker images are handy but it can become a hassle to keep them updated. Also when a repository is automated you want to get these images when they get out.
!!! example "Automatic image updates + cleanup"
One could setup a complex action/hook-based workflow using probes, but there is a nice, easy to use docker image that solves this issue and could prove useful: [`watchtower`](https://hub.docker.com/r/containrrr/watchtower).
Run a `watchtower` container with access to `docker.sock`, enabling the service to manage Docker:
A Docker Compose example:
```yaml title="compose.yaml"
services:
watchtower:
image: containrrr/watchtower:latest
# Automatic cleanup (removes older image pulls from wasting disk space):
environment:
- WATCHTOWER_CLEANUP=true
volumes:
- /var/run/docker.sock:/var/run/docker.sock
```
```yaml
services:
watchtower:
restart: always
image: containrrr/watchtower:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
```
!!! tip "The image tag used for a container is monitored for updates (eg: `:latest`, `:edge`, `:13`)"
For more details, see the [manual](https://containrrr.github.io/watchtower/)
The automatic update support is **only for updates to that specific image tag**.
## Automatic Cleanup
- Your container will not update to a new major version tag (_unless using `:latest`_).
- Omit the minor or patch portion of the semver tag to receive updates for the omitted portion (_eg: `13` will represent the latest minor + patch release of `v13`_).
When you are pulling new images in automatically, it would be nice to have them cleaned up as well. There is also a docker image for this: [`spotify/docker-gc`](https://hub.docker.com/r/spotify/docker-gc/).
!!! tip "Updating only specific containers"
A Docker Compose example:
By default the `watchtower` service will check every 24 hours for new image updates to pull, based on currently running containers (_**not restricted** to only those running within your `compose.yaml`_).
```yaml
services:
docker-gc:
restart: always
image: spotify/docker-gc:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
```
Images eligible for updates can configured with a [custom `command`][docker-docs-compose-command] that provides a list of container names, or via other supported options (eg: labels). This configuration is detailed in the [`watchtower` docs][watchtower-docs].
For more details, see the [manual](https://github.com/spotify/docker-gc/blob/master/README.md)
!!! info "Manual cleanup"
Or you can just use the [`--cleanup`](https://containrrr.github.io/watchtower/arguments/#cleanup) option provided by `containrrr/watchtower`.
`watchtower` also supports running on-demand with `docker run` or `compose.yaml` via the `--run-once` option.
You can alternatively invoke cleanup of Docker storage directly with:
- [`docker image prune --all`][docker-docs-prune-image]
- [`docker system prune --all`][docker-docs-prune-system] (_also removes unused containers, networks, build cache_).
If you omit the `--all` option, this will instead only remove ["dangling" content][docker-prune-dangling] (_eg: Orphaned images_).
[watchtower-dockerhub]: https://hub.docker.com/r/containrrr/watchtower
[watchtower-cleanup]: https://containrrr.github.io/watchtower/arguments/#cleanup
[watchtower-docs]: https://containrrr.dev/watchtower/
[docker-docs-compose-command]: https://docs.docker.com/compose/compose-file/05-services/#command
[docker-docs-prune-image]: https://docs.docker.com/engine/reference/commandline/image_prune/
[docker-docs-prune-system]: https://docs.docker.com/engine/reference/commandline/system_prune/
[docker-prune-dangling]: https://stackoverflow.com/questions/45142528/what-is-a-dangling-image-and-what-is-an-unused-image/60756668#60756668

View File

@ -12,7 +12,7 @@ This is a list of all configuration files and directories which are optional or
- **sieve-pipe:** directory for sieve pipe scripts. (Docs: [Sieve][docs-sieve])
- **opendkim:** DKIM directory. Auto-configurable via [`setup.sh config dkim`][docs-setupsh]. (Docs: [DKIM][docs-dkim])
- **ssl:** SSL Certificate directory if `SSL_TYPE` is set to `self-signed` or `custom`. (Docs: [SSL][docs-ssl])
- **Rspamd:** Override directory for custom settings when using Rspamd (Docs: [Rspamd][docs-rspamd-override-d])
- **rspamd:** Override directory for custom settings when using Rspamd (Docs: [Rspamd][docs-rspamd-override-d])
## Files
@ -33,9 +33,9 @@ This is a list of all configuration files and directories which are optional or
- **ldap-aliases.cf:** Configuration for the virtual alias mapping `virtual_alias_maps`. See the [`setup-stack.sh`][github-commit-setup-stack.sh-L411] script.
- **ldap-domains.cf:** Configuration for the virtual domain mapping `virtual_mailbox_domains`. See the [`setup-stack.sh`][github-commit-setup-stack.sh-L411] script.
- **whitelist_clients.local:** Whitelisted domains, not considered by postgrey. Enter one host or domain per line.
- **spamassassin-rules.cf:** Antispam rules for Spamassassin. (Docs: [FAQ - SpamAssassin Rules][docs-faq-spamrules])
- **spamassassin-rules.cf:** Anti-spam rules for Spamassassin. (Docs: [FAQ - SpamAssassin Rules][docs-faq-spamrules])
- **fail2ban-fail2ban.cf:** Additional config options for `fail2ban.cf`. (Docs: [Fail2Ban][docs-fail2ban])
- **fail2ban-jail.cf:** Additional config options for fail2ban's jail behaviour. (Docs: [Fail2Ban][docs-fail2ban])
- **fail2ban-jail.cf:** Additional config options for fail2ban's jail behavior. (Docs: [Fail2Ban][docs-fail2ban])
- **amavis.cf:** replaces the `/etc/amavis/conf.d/50-user` file
- **dovecot.cf:** replaces `/etc/dovecot/local.conf`. (Docs: [Override Dovecot Defaults][docs-override-dovecot])
- **dovecot-quotas.cf:** list of custom quotas per mailbox. (Docs: [Accounts][docs-accounts-quota])

View File

@ -107,7 +107,7 @@ The `PERMIT_DOCKER` variable in the `mailserver.env` file allows to specify trus
#### Use the slip4netns network driver
The second workaround is slightly more complicated because the `compose.yaml` has to be modified.
As shown in the [fail2ban section](../../security/fail2ban/#podman-with-slirp4netns-port-driver) the `slirp4netns` network driver has to be enabled.
As shown in the [fail2ban section](../security/fail2ban.md#podman-with-slirp4netns-port-driver) the `slirp4netns` network driver has to be enabled.
This network driver enables podman to correctly resolve IP addresses but it is not compatible with
user defined networks which might be a problem depending on your setup.

View File

@ -35,14 +35,67 @@ DKIM requires a public/private key pair to enable **signing (_via private key_)*
### Generating Keys
You'll need to repeat this process if you add any new domains.
You should have:
- At least one [email account setup][docs-accounts-add]
- Attached a [volume for config][docs-volumes-config] to persist the generated files to local storage
!!! warning "RSA Key Sizes >= 4096 Bit"
!!! example "Creating DKIM Keys"
Keys of 4096 bits could be denied by some mail servers. According to [RFC 6376][rfc-6376], keys are [preferably between 512 and 2048 bits][github-issue-dkimlength].
DKIM keys can be generated with good defaults by running:
```bash
docker exec -it <CONTAINER NAME> setup config dkim
```
If you need to generate your keys with different settings, check the `help` output for supported config options and examples:
```bash
docker exec -it <CONTAINER NAME> setup config dkim help
```
As described by the help output, you may need to use the `domain` option explicitly when you're using LDAP or Rspamd.
??? info "Changing the key size"
The keypair generated for using with DKIM presently defaults to RSA-2048. This is a good size but you can lower the security to `1024-bit`, or increase it to `4096-bit` (_discouraged as that is excessive_).
To generate a key with different size (_for RSA 1024-bit_) run:
```sh
setup config dkim keysize 1024
```
!!! warning "RSA Key Sizes >= 4096 Bit"
According to [RFC 8301][rfc-8301], keys are preferably between 1024 and 2048 bits. Keys of size 4096-bit or larger may not be compatible to all systems your mail is intended for.
You [should not need a key length beyond 2048-bit][github-issue-dkimlength]. If 2048-bit does not meet your security needs, you may want to instead consider adopting key rotation or switching from RSA to ECC keys for DKIM.
??? note "You may need to specify mail domains explicitly"
Required when using LDAP and Rspamd.
`setup config dkim` will generate DKIM keys for what is assumed as the primary mail domain (_derived from the FQDN assigned to DMS, minus any subdomain_).
When the DMS FQDN is `mail.example.com` or `example.com`, by default this command will generate DKIM keys for `example.com` as the primary domain for your users mail accounts (eg: `hello@example.com`).
The DKIM generation does not have support to query LDAP for additionanl mail domains it should know about. If the primary mail domain is not sufficient, then you must explicitly specify any extra domains via the `domain` option:
```sh
# ENABLE_OPENDKIM=1 (default):
setup config dkim domain 'example.com,another-example.com'
# ENABLE_RSPAMD=1 + ENABLE_OPENDKIM=0:
setup config dkim domain example.com
setup config dkim domain another-example.com
```
!!! info "OpenDKIM with `ACCOUNT_PROVISIONER=FILE`"
When DMS uses this configuration, it will by default also detect mail domains (_from accounts added via `setup email add`_), generating additional DKIM keys.
DKIM is currently supported by either OpenDKIM or Rspamd:
@ -50,68 +103,27 @@ DKIM is currently supported by either OpenDKIM or Rspamd:
OpenDKIM is currently [enabled by default][docs-env-opendkim].
The command `docker exec <CONTAINER NAME> setup config dkim help` details supported config options, along with some examples.
!!! example "Creating a DKIM key"
Generate the DKIM files with:
```sh
docker exec -ti <CONTAINER NAME> setup config dkim
```
Your new DKIM key(s) and OpenDKIM config files have been added to `/tmp/docker-mailserver/opendkim/`.
??? note "LDAP accounts need to specify domains explicitly"
The command is unable to infer the domains from LDAP user accounts, you must specify them:
```sh
setup config dkim domain 'example.com,example.io'
```
??? tip "Changing the key size"
The private key presently defaults to RSA-4096. To create an RSA 2048-bit key run:
```sh
setup config dkim keysize 2048
```
After running `setup config dkim`, your new DKIM key files (_and OpenDKIM config_) have been added to `/tmp/docker-mailserver/opendkim/`.
!!! info "Restart required"
After restarting DMS, outgoing mail will now be signed with your new DKIM key(s) :tada:
You'll need to repeat this process if you add any new domains.
=== "Rspamd"
Opt-in via [`ENABLE_RSPAMD=1`][docs-env-rspamd] (_and disable the default OpenDKIM: `ENABLE_OPENDKIM=0`_).
Requires opt-in via [`ENABLE_RSPAMD=1`][docs-env-rspamd] (_and disable the default OpenDKIM: `ENABLE_OPENDKIM=0`_).
Rspamd provides DKIM support through two separate modules:
1. [Verifying DKIM signatures from inbound mail][rspamd-docs-dkim-checks] is enabled by default.
2. [Signing outbound mail with your DKIM key][rspamd-docs-dkim-signing] needs additional setup (key + dns + config).
!!! example "Creating DKIM Keys"
You can simply run
```bash
docker exec -ti <CONTAINER NAME> setup config dkim help
```
which provides you with an overview of what the script can do. Just running
```bash
docker exec -ti <CONTAINER NAME> setup config dkim
```
will execute the helper script with default parameters.
??? warning "Using Multiple Domains"
Unlike the current script for OpenDKIM, the Rspamd script will **not** create keys for all domains DMS is managing, but only for the one it assumes to be the main domain (derived from DMS' domain name). Moreover, the default `dkim_signing.conf` configuration file that DMS ships will also only contain one domain. If you have multiple domains, you need to run the command `docker exec -ti <CONTAINER NAME> setup config dkim domain <DOMAIN>` multiple times to create all the keys for all domains, and then provide a custom `dkim_signing.conf` (for which an example is shown below).
If you have multiple domains, you need to:
- Create a key wth `docker exec -it <CONTAINER NAME> setup config dkim domain <DOMAIN>` for each domain DMS should sign outgoing mail for.
- Provide a custom `dkim_signing.conf` (for which an example is shown below), as the default config only supports one domain.
!!! info "About the Helper Script"
@ -121,7 +133,9 @@ DKIM is currently supported by either OpenDKIM or Rspamd:
---
In case you have not already provided a default DKIM signing configuration, the script will create one and write it to `/etc/rspamd/override.d/dkim_signing.conf`. If this file already exist, it will not be overwritten. When you're already using [the `rspamd/override.d/` directory][docs-rspamd-override-d], the file is created inside your volume and therefore persisted correctly. If you are not using `rspamd/override.d/`, you will need to persist the file yourself (otherwise it is lost on container restart).
In case you have not already provided a default DKIM signing configuration, the script will create one and write it to `/etc/rspamd/override.d/dkim_signing.conf`. If this file already exists, it will not be overwritten.
When you're already using [the `rspamd/override.d/` directory][docs-rspamd-config-dropin], the file is created inside your volume and therefore persisted correctly. If you are not using `rspamd/override.d/`, you will need to persist the file yourself (otherwise it is lost on container restart).
An example of what a default configuration file for DKIM signing looks like can be found by expanding the example below.
@ -142,6 +156,13 @@ DKIM is currently supported by either OpenDKIM or Rspamd:
use_esld = true;
check_pubkey = true; # you want to use this in the beginning
selector = "mail";
# The path location is searched for a DKIM key with these variables:
# - `$domain` is sourced from the MIME mail message `From` header
# - `$selector` is configured for `mail` (as a default fallback)
path = "/tmp/docker-mailserver/dkim/keys/$domain/$selector.private";
# domain specific configurations can be provided below:
domain {
example.com {
path = "/tmp/docker-mailserver/rspamd/dkim/mail.private";
@ -188,9 +209,7 @@ DKIM is currently supported by either OpenDKIM or Rspamd:
When `check_pubkey = true;` is set, Rspamd will query the DNS record for each DKIM selector, verifying each public key matches the private key configured.
If there is a mismatch, a warning will be emitted to the Rspamd log `/var/log/supervisor/rspamd.log`.
[docs-rspamd-override-d]: ../security/rspamd.md#manually
If there is a mismatch, a warning will be emitted to the Rspamd log `/var/log/mail/rspamd.log`.
### DNS Record { #dkim-dns }
@ -221,11 +240,13 @@ When mail signed with your DKIM key is sent from your mail server, the receiver
??? info "`<selector>.txt` - Formatting the `TXT` record value correctly"
This file was generated for use within a [DNS zone file][dns::wikipedia-zonefile]. DNS `TXT` records values that are longer than 255 characters need to be split into multiple parts. This is why the public key has multiple parts wrapped within double-quotes between `(` and `)`.
This file was generated for use within a [DNS zone file][dns::wikipedia-zonefile]. The file name uses the DKIM selector it was generated with (default DKIM selector is `mail`, which creates `mail.txt`_).
A DNS web-interface may handle this internally instead, while [others may not, but expect the input as a single line][dns::webui-dkim]_). You'll need to manually format the value as described below.
For your DNS setup, DKIM support needs to create a `TXT` record to store the public key for mail clients to use. `TXT` records with values that are longer than 255 characters need to be split into multiple parts. This is why the generated `<selector>.txt` file (_containing your public key for use with DKIM_) has multiple value parts wrapped within double-quotes between `(` and `)`.
Your DNS record file (eg: `mail.txt`) should look similar to this:
A DNS web-interface may handle this separation internally instead, and [could expect the value provided all as a single line][dns::webui-dkim] instead of split. When that is required, you'll need to manually format the value as described below.
Your generated DNS record file (`<selector>.txt`) should look similar to this:
```txt
mail._domainkey IN TXT ( "v=DKIM1; k=rsa; "
@ -243,7 +264,7 @@ When mail signed with your DKIM key is sent from your mail server, the receiver
To test that your new DKIM record is correct, query it with the `dig` command. The `TXT` value response should be a single line split into multiple parts wrapped in double-quotes:
```console
$ dig +short TXT dkim-rsa._domainkey.example.com
$ dig +short TXT mail._domainkey.example.com
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQMMqhb1S52Rg7VFS3EC6JQIMxNDdiBmOKZvY5fiVtD3Z+yd9ZV+V8e4IARVoMXWcJWSR6xkloitzfrRtJRwOYvmrcgugOalkmM0V4Gy/2aXeamuiBuUc4esDQEI3egmtAsHcVY1XCoYfs+9VqoHEq3vdr3UQ8zP/l+FP5UfcaJFCK/ZllqcO2P1GjIDVSHLdPpRHbMP/tU1a9mNZ5QMZBJ/JuJK/s+2bp8gpxKn8rh1akSQjlynlV9NI+7J3CC7CUf3bGvoXIrb37C/lpJehS39" "KNtcGdaRufKauSfqx/7SxA0zyZC+r13f7ASbMaQFzm+/RRusTqozY/p/MsWx8QIDAQAB"
```
@ -251,7 +272,7 @@ When mail signed with your DKIM key is sent from your mail server, the receiver
[MxToolbox has a DKIM Verifier][mxtoolbox-dkim-verifier] that you can use to check your DKIM DNS record(s).
When using Rspamd, we recommend you turn on `check_pubkey = true;` in `dkim_signing.conf`. Rspamd will then check whether your private key matches your public key, and you can check possible mismatches by looking at `/var/log/supervisor/rspamd.log`.
When using Rspamd, we recommend you turn on `check_pubkey = true;` in `dkim_signing.conf`. Rspamd will then check whether your private key matches your public key, and you can check possible mismatches by looking at `/var/log/mail/rspamd.log`.
## DMARC
@ -328,10 +349,9 @@ volumes:
[docs-env-opendkim]: ../environment.md#enable_opendkim
[docs-env-rspamd]: ../environment.md#enable_rspamd
[docs-rspamd-config-dropin]: ../security/rspamd.md#manually
[docs-rspamd-config-declarative]: ../security/rspamd.md#with-the-help-of-a-custom-file
[cloudflare-dkim-dmarc-spf]: https://www.cloudflare.com/learning/email-security/dmarc-dkim-spf/
[rfc-6376]: https://tools.ietf.org/html/rfc6376
[github-issue-dkimlength]: https://github.com/docker-mailserver/docker-mailserver/issues/1854
[rfc-8301]: https://datatracker.ietf.org/doc/html/rfc8301#section-3.2
[github-issue-dkimlength]: https://github.com/docker-mailserver/docker-mailserver/issues/1854#issuecomment-806280929
[rspamd-docs-dkim-checks]: https://www.rspamd.com/doc/modules/dkim.html
[rspamd-docs-dkim-signing]: https://www.rspamd.com/doc/modules/dkim_signing.html
[dns::example-webui]: https://www.vultr.com/docs/introduction-to-vultr-dns/

View File

@ -0,0 +1,30 @@
---
title: 'Best practices | MTA-STS'
hide:
- toc # Hide Table of Contents for this page
---
MTA-STS is an optional mechanism for a domain to signal support for STARTTLS.
- It can be used to prevent man-in-the-middle-attacks from hiding STARTTLS support that would force DMS to send outbound mail through an insecure connection.
- MTA-STS is an alternative to DANE without the need of DNSSEC.
- MTA-STS is supported by some of the biggest mail providers like Google Mail and Outlook.
## Supporting MTA-STS for outbound mail
Enable this feature via the ENV setting [`ENABLE_MTA_STS=1`](../environment.md#enable_mta_sts).
!!! warning "If you have configured DANE"
Enabling MTA-STS will by default override DANE if both are configured for a domain.
This can be partially addressed by configuring a dane-only policy resolver before the MTA-STS entry in `smtp_tls_policy_maps`. See the [`postfix-mta-sts-resolver` documentation][postfix-mta-sts-resolver::dane] for further details.
[postfix-mta-sts-resolver::dane]: https://github.com/Snawoot/postfix-mta-sts-resolver#warning-mta-sts-policy-overrides-dane-tls-authentication
## Supporting MTA-STS for inbound mail
While this feature in DMS supports ensuring STARTTLS is used when mail is sent to another mail server, you may setup similar for mail servers sending mail to DMS.
This requires configuring your DNS and hosting the MTA-STS policy file via a webserver. A good introduction can be found on [dmarcian.com](https://dmarcian.com/mta-sts/).

View File

@ -14,6 +14,27 @@ This page contains valuable information when it comes to resolving issues you en
- Check that all published DMS ports are actually open and not blocked by your ISP / hosting provider.
- SSL errors are likely the result of a wrong setup on the user side and not caused by DMS itself.
- Ensure that you have correctly started DMS. Many problems related to configuration are due to this.
!!! danger "Correctly starting DMS"
Use the [`--force-recreate`][docker-docs::force-recreate] option to avoid configuration mishaps: `docker compose up --force-recreate`
Alternatively, always use `docker compose down` to stop DMS. **Do not** rely on `CTRL + C`, `docker compose stop`, or `docker compose restart`.
---
DMS setup scripts are run when a container starts, but may fail to work properly if you do the following:
- Stopping a container with commands like: `docker stop` or `docker compose up` stopped via `CTRL + C` instead of `docker compose down`.
- Restarting a container.
Volumes persist data across container instances, however the same container instance will keep internal changes not stored in a volume until the container is removed.
Due to this, DMS setup scripts may modify configuration it has already modified in the past.
- This is brittle as some changes are naive by assuming they are applied to the original configs from the image.
- Volumes in `compose.yaml` are expected to persist any important data. Thus it should be safe to throwaway the container created each time, avoiding this config problem.
### Mail sent from DMS does not arrive at destination
@ -25,26 +46,43 @@ Some service providers block outbound traffic on port 25. Common hosting provide
These links may advise how the provider can unblock the port through additional services offered, or via a support ticket request.
### Mail sent to DMS does not get delivered to user
Common logs related to this are:
- `warning: do not list domain domain.fr in BOTH mydestination and virtual_mailbox_domains`
- `Recipient address rejected: User unknown in local recipient table`
If your logs look like this, you likely have [assigned the same FQDN to the DMS `hostname` and your mail accounts][gh-issues::dms-fqdn-misconfigured] which is not supported by default. You can either adjust your DMS `hostname` or follow [this FAQ advice][docs::faq-bare-domain]
It is also possible that [DMS services are temporarily unavailable][gh-issues::dms-services-unavailable] when configuration changes are detected, producing the 2nd error. Certificate updates may be a less obvious trigger.
## Steps for Debugging DMS
1. **Increase log verbosity**: Very helpful for troubleshooting problems during container startup. Set the environment variable [`LOG_LEVEL`][docs-environment-log-level] to `debug` or `trace`.
2. **Use error logs as a search query**: Try [finding an _existing issue_][gh-issues] or _search engine result_ from any errors in your container log output. Often you'll find answers or more insights. If you still need to open an issue, sharing links from your search may help us assist you. The mail server log can be acquired by running `docker log <CONTAINER NAME>` (_or `docker logs -f <CONTAINER NAME>` if you want to follow the log_).
3. **Understand the basics of mail servers**: Especially for beginners, make sure you read our [Introduction][docs-introduction] and [Usage][docs-usage] articles.
4. **Search the whole FAQ**: Our [FAQ][docs-faq] contains answers for common problems. Make sure you go through the list.
5. **Reduce the scope**: Ensure that you can run a basic setup of DMS first. Then incrementally restore parts of your original configuration until the problem is reproduced again. If you're new to DMS, it is common to find the cause is misunderstanding how to configure a minimal setup.
3. **Inspect the logs of the service that is failing**: We provide a dedicated paragraph on this topic [further down below](#logs).
4. **Understand the basics of mail servers**: Especially for beginners, make sure you read our [Introduction][docs-introduction] and [Usage][docs-usage] articles.
5. **Search the whole FAQ**: Our [FAQ][docs-faq] contains answers for common problems. Make sure you go through the list.
6. **Reduce the scope**: Ensure that you can run a basic setup of DMS first. Then incrementally restore parts of your original configuration until the problem is reproduced again. If you're new to DMS, it is common to find the cause is misunderstanding how to configure a minimal setup.
### Debug a running container
To get a shell inside the container run: `docker exec -it <CONTAINER NAME> bash`.
#### General
If you need more flexibility than `docker logs` offers, within the container `/var/log/mail/mail.log` and `/var/log/supervisor/` are the most useful locations to get relevant DMS logs. Use the `tail` or `cat` commands to view their contents.
To install additional software:
To get a shell inside the container run: `docker exec -it <CONTAINER NAME> bash`. To install additional software, run:
1. `apt-get update` to update repository metadata.
2. `apt-get install <PACKAGE>`
2. `apt-get install <PACKAGE>` to install a package, e.g., `apt-get install neovim` if you want to use NeoVim instead of `nano` (which is shipped by default).
For example a text editor you can use in the terminal: `apt-get install nano`
#### Logs
If you need more flexibility than what the `docker logs` command offers, then the most useful locations to get relevant DMS logs within the container are:
- `/var/log/mail/<SERVICE>.log`
- `/var/log/supervisor/<SERVICE>.log`
You may use `nano` (a text editor) to edit files, while `less` (a file viewer) and `tail`/`cat` are useful tools to inspect the contents of logs.
## Compatibility
@ -67,10 +105,11 @@ This could be from outdated software, or running a system that isn't able to pro
### System
- **macOS:** DMS has limited support for macOS. Often an issue encountered is due to permissions related to the `volumes` config in `compose.yaml`. You may have luck [trying `gRPC FUSE`][gh-macos-support] as the file sharing implementation; [`VirtioFS` is the successor][docker-macos-virtiofs] but presently appears incompatible with DMS.
- **Kernel:** Some systems provide [kernels with modifications (_replacing defaults and backporting patches_)][network::kernels-modified] to support running legacy software or kernels, complicating compatibility. This can be commonly experienced with products like NAS.
- **CGroups v2:** Hosts running older kernels (prior to 5.2) and systemd (prior to v244) are not likely to leverage cgroup v2, or have not defaulted to the cgroup v2 `unified` hierarchy. Not meeting this baseline may influence the behaviour of your DMS container, even with the latest Docker Engine installed.
- **CGroups v2:** Hosts running older kernels (prior to 5.2) and systemd (prior to v244) are not likely to leverage cgroup v2, or have not defaulted to the cgroup v2 `unified` hierarchy. Not meeting this baseline may influence the behavior of your DMS container, even with the latest Docker Engine installed.
- **Container runtime:** Docker and Podman for example have subtle differences. DMS docs are primarily focused on Docker, but we try to document known issues where relevant.
- **Rootless containers:** Introduces additional differences in behaviour or requirements:
- **Rootless containers:** Introduces additional differences in behavior or requirements:
- cgroup v2 is required for supporting rootless containers.
- Differences such as for container networking which may further affect support for IPv6 and preserving the client IP (Remote address). Example with Docker rootless are [binding a port to a specific interface][docker-rootless-interface] and the choice of [port forwarding driver][docs-rootless-portdriver].
@ -79,13 +118,20 @@ This could be from outdated software, or running a system that isn't able to pro
[network::kernels-modified]: https://github.com/docker-mailserver/docker-mailserver/pull/2662#issuecomment-1168435970
[network::kernel-nftables]: https://unix.stackexchange.com/questions/596493/can-nftables-and-iptables-ip6tables-rules-be-applied-at-the-same-time-if-so-wh/596497#596497
[docs-faq]: ../faq.md
[docs-environment-log-level]: ./environment.md#log_level
[docs-faq]: ../faq.md
[docs::faq-bare-domain]: ../faq.md#can-i-use-a-nakedbare-domain-ie-no-hostname
[docs-ipv6]: ./advanced/ipv6.md
[docs-introduction]: ../introduction.md
[docs-rootless-portdriver]: ./security/fail2ban.md#running-inside-a-rootless-container
[docs-usage]: ../usage.md
[gh-issues]: https://github.com/docker-mailserver/docker-mailserver/issues
[gh-issues::dms-fqdn-misconfigured]: https://github.com/docker-mailserver/docker-mailserver/issues/3679#issuecomment-1837609043
[gh-issues::dms-services-unavailable]: https://github.com/docker-mailserver/docker-mailserver/issues/3679#issuecomment-1848083358
[gh-macos-support]: https://github.com/docker-mailserver/docker-mailserver/issues/3648#issuecomment-1822774080
[gh-discuss-roundcube-fail2ban]: https://github.com/orgs/docker-mailserver/discussions/3273#discussioncomment-5654603
[docker-rootless-interface]: https://github.com/moby/moby/issues/45742
[docs-rootless-portdriver]: ./security/fail2ban.md#running-inside-a-rootless-container
[docker-macos-virtiofs]: https://www.docker.com/blog/speed-boost-achievement-unlocked-on-docker-desktop-4-6-for-mac/
[docker-docs::force-recreate]: https://docs.docker.com/compose/reference/up/

View File

@ -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.
@ -42,14 +54,22 @@ The log-level will show everything in its class and above.
Configures the provisioning source of user accounts (including aliases) for user queries and authentication by services managed by DMS (_Postfix and Dovecot_).
User provisioning via OIDC is planned for the future, see [this tracking issue](https://github.com/docker-mailserver/docker-mailserver/issues/2713).
!!! tip "OAuth2 Support"
Presently DMS supports OAuth2 only as an supplementary authentication method.
- A third-party service must provide a valid token for the user which Dovecot validates with the authentication service provider. To enable this feature reference the [OAuth2 configuration example guide][docs::auth::oauth2-config-guide].
- User accounts must be provisioned to receive mail via one of the supported `ACCOUNT_PROVISIONER` providers.
- User provisioning via OIDC is planned for the future, see [this tracking issue](https://github.com/docker-mailserver/docker-mailserver/issues/2713).
[docs::auth::oauth2-config-guide]: ./advanced/auth-oauth2.md
- **empty** => use FILE
- LDAP => use LDAP authentication
- OIDC => use OIDC authentication (**not yet implemented**)
- FILE => use local files (this is used as the default)
A second container for the ldap service is necessary (e.g. [docker-openldap](https://github.com/osixia/docker-openldap))
A second container for the ldap service is necessary (e.g. [`bitnami/openldap`](https://hub.docker.com/r/bitnami/openldap/)).
##### PERMIT_DOCKER
@ -96,6 +116,15 @@ This enables DNS block lists in _Postscreen_. If you want to know which lists we
- **0** => DNS block lists are disabled
- 1 => DNS block lists are enabled
##### ENABLE_MTA_STS
Enables MTA-STS support for outbound mail.
- **0** => Disabled
- 1 => Enabled
See [MTA-STS](best-practices/mta-sts.md) for further explanation.
##### ENABLE_OPENDKIM
Enables the OpenDKIM service.
@ -119,9 +148,14 @@ Enabled `policyd-spf` in Postfix's configuration. You will likely want to set th
##### ENABLE_POP3
- **empty** => POP3 service disabled
- **0** => POP3 service disabled
- 1 => Enables POP3 service
##### ENABLE_IMAP
- 0 => Disabled
- **1** => Enabled
##### ENABLE_CLAMAV
- **0** => ClamAV is disabled
@ -211,9 +245,9 @@ Provide any valid URI. Examples:
- `lmtps:inet:<host>:<port>` (secure lmtp with starttls)
- `lmtp:<kopano-host>:2003` (use kopano as mailstore)
##### POSTFIX\_MAILBOX\_SIZE\_LIMIT
##### POSTFIX_MAILBOX_SIZE_LIMIT
Set the mailbox size limit for all users. If set to zero, the size will be unlimited (default).
Set the mailbox size limit for all users. If set to zero, the size will be unlimited (default). Size is in bytes.
- **empty** => 0 (no limit)
@ -224,9 +258,9 @@ Set the mailbox size limit for all users. If set to zero, the size will be unlim
See [mailbox quota][docs-accounts-quota].
##### POSTFIX\_MESSAGE\_SIZE\_LIMIT
##### POSTFIX_MESSAGE_SIZE_LIMIT
Set the message size limit for all users. If set to zero, the size will be unlimited (not recommended!)
Set the message size limit for all users. If set to zero, the size will be unlimited (not recommended!). Size is in bytes.
- **empty** => 10240000 (~10 MB)
@ -299,16 +333,32 @@ Note: More information at <https://dovecot.org/doc/dovecot-example.conf>
##### MOVE_SPAM_TO_JUNK
When enabled, e-mails marked with the
1. `X-Spam: Yes` header added by Rspamd
2. `X-Spam-Flag: YES` header added by SpamAssassin (requires [`SPAMASSASSIN_SPAM_TO_INBOX=1`](#spamassassin_spam_to_inbox))
will be automatically moved to the Junk folder (with the help of a Sieve script).
- 0 => Spam messages will be delivered in the mailbox.
- **1** => Spam messages will be delivered in the `Junk` folder.
Routes mail identified as spam into the recipient(s) Junk folder (_via a Dovecot Sieve script_).
!!! info
Mail is received as spam when it has been marked with either header:
- `X-Spam: Yes` (_added by Rspamd_)
- `X-Spam-Flag: YES` (_added by SpamAssassin - requires [`SPAMASSASSIN_SPAM_TO_INBOX=1`](#spamassassin_spam_to_inbox)_)
##### MARK_SPAM_AS_READ
- **0** => disabled
- 1 => Spam messages will be marked as read
Enable to treat received spam as "read" (_avoids notification to MUA client of new mail_).
!!! info
Mail is received as spam when it has been marked with either header:
- `X-Spam: Yes` (_added by Rspamd_)
- `X-Spam-Flag: YES` (_added by SpamAssassin - requires [`SPAMASSASSIN_SPAM_TO_INBOX=1`](#spamassassin_spam_to_inbox)_)
#### Rspamd
##### ENABLE_RSPAMD
@ -338,6 +388,19 @@ The purpose of this setting is to opt-out of starting an internal Redis instance
- 0 => Disabled
- 1 => Enabled
##### RSPAMD_CHECK_AUTHENTICATED
This settings controls whether checks should be performed on emails coming from authenticated users (i.e. most likely outgoing emails). The default value is `0` in order to align better with SpamAssassin. **We recommend** reading through [the Rspamd documentation on scanning outbound emails][rspamd-scanning-outbound] though to decide for yourself whether you need and want this feature.
!!! note "Not all checks and actions are disabled"
DKIM signing of e-mails will still happen.
- **0** => No checks will be performed for authenticated users
- 1 => All default checks will be performed for authenticated users
[rspamd-scanning-outbound]: https://rspamd.com/doc/tutorials/scanning_outbound.html
##### RSPAMD_GREYLISTING
Controls whether the [Rspamd Greylisting module][rspamd-greylisting-module] is enabled. This module can further assist in avoiding spam emails by [greylisting] e-mails with a certain spam score.
@ -473,63 +536,170 @@ Changes the interval in which log files are rotated.
- **0** => SpamAssassin is disabled
- 1 => SpamAssassin is enabled
##### SPAMASSASSIN_SPAM_TO_INBOX
??? info "SpamAssassin analyzes incoming mail and assigns a spam score"
- 0 => Spam messages will be bounced (_rejected_) without any notification (_dangerous_).
- **1** => Spam messages will be delivered to the inbox and tagged as spam using `SA_SPAM_SUBJECT`.
Integration with Amavis involves processing mail based on the assigned spam score via [`SA_TAG`, `SA_TAG2` and `SA_KILL`][amavis-docs::spam-score].
These settings have equivalent ENV supported by DMS for easy adjustments, as documented below.
[amavis-docs::spam-score]: https://www.ijs.si/software/amavisd/amavisd-new-docs.html#tagkill
##### ENABLE_SPAMASSASSIN_KAM
[KAM](https://mcgrail.com/template/projects#KAM1) is a 3rd party SpamAssassin ruleset, provided by the McGrail Foundation. If SpamAssassin is enabled, KAM can be used in addition to the default ruleset.
- **0** => KAM disabled
- 1 => KAM enabled
[KAM](https://mcgrail.com/template/projects#KAM1) is a 3rd party SpamAssassin ruleset, provided by the McGrail Foundation. If SpamAssassin is enabled, KAM can be used in addition to the default ruleset.
##### SPAMASSASSIN_SPAM_TO_INBOX
- 0 => (_Amavis action: `D_BOUNCE`_): Spam messages will be bounced (_rejected_) without any notification (_dangerous_).
- **1** => (_Amavis action: `D_PASS`_): Spam messages will be delivered to the inbox.
!!! note
The Amavis action configured by this setting:
- Influences the behavior of the [`SA_KILL`](#sa_kill) setting.
- Applies to the Amavis config parameters `$final_spam_destiny` and `$final_bad_header_destiny`.
!!! note "This ENV setting is related to"
- [`MOVE_SPAM_TO_JUNK=1`](#move_spam_to_junk)
- [`MARK_SPAM_AS_READ=1`](#mark_spam_as_read)
- [`SA_SPAM_SUBJECT`](#sa_spam_subject)
##### SA_TAG
- **2.0** => add spam info headers if at, or above that level
- **2.0** => add 'spam info' headers at, or above this spam score
Note: this SpamAssassin setting needs `ENABLE_SPAMASSASSIN=1`
Mail is not yet considered spam at this spam score, but for purposes like diagnostics it can be useful to identify mail with a spam score at a lower bound than `SA_TAG2`.
??? example "`X-Spam` headers appended to mail"
Send a simple mail to a local DMS account `hello@example.com`:
```bash
docker exec dms swaks --server 0.0.0.0 --to hello@example.com --body 'spam'
```
Inspecting the raw mail you will notice several `X-Spam` headers were added to the mail like this:
```
X-Spam-Flag: NO
X-Spam-Score: 4.162
X-Spam-Level: ****
X-Spam-Status: No, score=4.162 tagged_above=2 required=4
tests=[BODY_SINGLE_WORD=1, DKIM_ADSP_NXDOMAIN=0.8,
NO_DNS_FOR_FROM=0.379, NO_RECEIVED=-0.001, NO_RELAYS=-0.001,
PYZOR_CHECK=1.985] autolearn=no autolearn_force=no
```
!!! info "The `X-Spam-Score` is `4.162`"
High enough for `SA_TAG` to trigger adding these headers, but not high enough for `SA_TAG2` (_which would set `X-Spam-Flag: YES` instead_).
##### SA_TAG2
- **6.31** => add 'spam detected' headers at that level
- **6.31** => add 'spam detected' headers at, or above this level
Note: this SpamAssassin setting needs `ENABLE_SPAMASSASSIN=1`
When a spam score is high enough, mark mail as spam (_Appends the mail header: `X-Spam-Flag: YES`_).
!!! info "Interaction with other ENV"
- [`SA_SPAM_SUBJECT`](#sa_spam_subject) modifies the mail subject to better communicate spam mail to the user.
- [`MOVE_SPAM_TO_JUNK=1`](#move_spam_to_junk): The mail is still delivered, but to the recipient(s) junk folder instead. This feature reduces the usefulness of `SA_SPAM_SUBJECT`.
##### SA_KILL
- **10.0** => triggers spam evasive actions
- **10.0** => quarantine + triggers action to handle spam
!!! note "This SpamAssassin setting needs `ENABLE_SPAMASSASSIN=1`"
Controls the spam score threshold for triggering an action on mail that has a high spam score.
By default, DMS is configured to quarantine spam emails.
??? tip "Choosing an appropriate `SA_KILL` value"
If emails are quarantined, they are compressed and stored in a location dependent on the `ONE_DIR` setting above. To inhibit this behaviour and deliver spam emails, set this to a very high value e.g. `100.0`.
The value should be high enough to be represent confidence in mail as spam:
If `ONE_DIR=1` (default) the location is `/var/mail-state/lib-amavis/virusmails/`, or if `ONE_DIR=0`: `/var/lib/amavis/virusmails/`. These paths are inside the docker container.
- Too low: The action taken may prevent legitimate mail (ham) that was incorrectly detected as spam from being delivered successfully.
- Too high: Allows more spam to bypass the `SA_KILL` trigger (_how to treat mail with high confidence that it is actually spam_).
Experiences from DMS users with these settings has been [collected here][gh-issue::sa-tunables-insights], along with [some direct configuration guides][gh-issue::sa-tunables-guides] (_under "Resources for references"_).
[gh-issue::sa-tunables-insights]: https://github.com/docker-mailserver/docker-mailserver/pull/3058#issuecomment-1420268148
[gh-issue::sa-tunables-guides]: https://github.com/docker-mailserver/docker-mailserver/pull/3058#issuecomment-1416547911
??? info "Trigger action"
DMS will configure Amavis with either of these actions based on the DMS [`SPAMASSASSIN_SPAM_TO_INBOX`](#spamassassin_spam_to_inbox) ENV setting:
- `D_PASS` (**default**):
- Accept mail and deliver it to the recipient(s), despite the high spam score. A copy is still stored in quarantine.
- This is a good default to start with until you are more confident in an `SA_KILL` threshold that won't accidentally discard / bounce legitimate mail users are expecting to arrive but is detected as spam.
- `D_BOUNCE`:
- Additionally sends a bounce notification (DSN).
- The [DSN is suppressed][amavis-docs::actions] (_no bounce sent_) when the spam score exceeds the Amavis `$sa_dsn_cutoff_level` config setting (default: `10`). With the DMS `SA_KILL` default also being `10`, no DSN will ever be sent.
- `D_REJECT` / `D_DISCARD`:
- These two aren't configured by DMS, but are valid alternative action values if configuring Amavis directly.
??? note "Quarantined mail"
When mail has a spam score that reaches the `SA_KILL` threshold:
- [It will be quarantined][amavis-docs::quarantine] regardless of the `SA_KILL` action to perform.
- With `D_PASS` the delivered mail also appends an `X-Quarantine-ID` mail header. The ID value of this header is part of the quarantined file name.
If emails are quarantined, they are compressed and stored at a location dependent on the [`ONE_DIR`](#one_dir) setting:
- `ONE_DIR=1` (default): `/var/mail-state/lib-amavis/virusmails/`
- `ONE_DIR=0`: `/var/lib/amavis/virusmails/`
!!! tip
Easily list mail stored in quarantine with `find` and the quarantine path:
```bash
find /var/lib/amavis/virusmails -type f
```
[amavis-docs::actions]: https://www.ijs.si/software/amavisd/amavisd-new-docs.html#actions
[amavis-docs::quarantine]: https://www.ijs.si/software/amavisd/amavisd-new-docs.html#quarantine
##### SA_SPAM_SUBJECT
- **\*\*\*SPAM\*\*\*** => add tag to subject if spam detected
Adds a prefix to the subject header when mail is marked as spam (_via [`SA_TAG2`](#sa_tag2)_).
Note: this SpamAssassin setting needs `ENABLE_SPAMASSASSIN=1`. Add the SpamAssassin score to the subject line by inserting the keyword \_SCORE\_: **\*\*\*SPAM(\_SCORE\_)\*\*\***.
- **`'***SPAM*** '`** => A string value to use as a mail subject prefix.
- `undef` => Opt-out of modifying the subject for mail marked as spam.
??? example "Including trailing white-space"
Add trailing white-space by quote wrapping the value: `SA_SPAM_SUBJECT='[SPAM] '`
??? example "Including the associated spam score"
The [`_SCORE_` tag][sa-docs::score-tag] will be substituted with the SpamAssassin score: `SA_SPAM_SUBJECT=***SPAM(_SCORE_)***`.
[sa-docs::score-tag]: https://spamassassin.apache.org/full/4.0.x/doc/Mail_SpamAssassin_Conf.html#rewrite_header-subject-from-to-STRING
##### SA_SHORTCIRCUIT_BAYES_SPAM
- **1** => will activate SpamAssassin short circuiting for bayes spam detection.
This will uncomment the respective line in ```/etc/spamassasin/local.cf```
This will uncomment the respective line in `/etc/spamassasin/local.cf`
Note: activate this only if you are confident in your bayes database for identifying spam.
!!! warning
Activate this only if you are confident in your bayes database for identifying spam.
##### SA_SHORTCIRCUIT_BAYES_HAM
- **1** => will activate SpamAssassin short circuiting for bayes ham detection
This will uncomment the respective line in ```/etc/spamassasin/local.cf```
This will uncomment the respective line in `/etc/spamassasin/local.cf`
Note: activate this only if you are confident in your bayes database for identifying ham.
!!! warning
Activate this only if you are confident in your bayes database for identifying ham.
#### Fetchmail
@ -544,8 +714,10 @@ Note: activate this only if you are confident in your bayes database for identif
##### FETCHMAIL_PARALLEL
**0** => `fetchmail` runs with a single config file `/etc/fetchmailrc`
**1** => `/etc/fetchmailrc` is split per poll entry. For every poll entry a separate fetchmail instance is started to allow having multiple imap idle configurations defined.
- **0** => `fetchmail` runs with a single config file `/etc/fetchmailrc`
- 1 => `/etc/fetchmailrc` is split per poll entry. For every poll entry a separate fetchmail instance is started to [allow having multiple imap idle connections per server][fetchmail-imap-workaround] (_when poll entries reference the same IMAP server_).
[fetchmail-imap-workaround]: https://otremba.net/wiki/Fetchmail_(Debian)#Immediate_Download_via_IMAP_IDLE
Note: The defaults of your fetchmailrc file need to be at the top of the file. Otherwise it won't be added correctly to all separate `fetchmail` instances.
#### Getmail
@ -561,12 +733,20 @@ Enable or disable `getmail`.
- **5** => `getmail` The number of minutes for the interval. Min: 1; Max: 30; Default: 5.
#### OAUTH2
##### ENABLE_OAUTH2
- **empty** => OAUTH2 authentication is disabled
- 1 => OAUTH2 authentication is enabled
##### OAUTH2_INTROSPECTION_URL
- => Specify the user info endpoint URL of the oauth2 provider (_eg: `https://oauth2.example.com/userinfo/`_)
#### LDAP
##### ENABLE_LDAP
Deprecated. See [`ACCOUNT_PROVISIONER`](#account_provisioner).
##### LDAP_START_TLS
- **empty** => no
@ -575,8 +755,8 @@ Deprecated. See [`ACCOUNT_PROVISIONER`](#account_provisioner).
##### LDAP_SERVER_HOST
- **empty** => mail.example.com
- => Specify the dns-name/ip-address where the ldap-server is listening, or an URI like `ldaps://mail.example.com`
- NOTE: If you going to use DMS in combination with `compose.yaml` you can set the service name here
- => Specify the `<dns-name>` / `<ip-address>` where the LDAP server is reachable via a URI like: `ldaps://mail.example.com`.
- Note: You must include the desired URI scheme (`ldap://`, `ldaps://`, `ldapi://`).
##### LDAP_SEARCH_BASE
@ -650,9 +830,8 @@ The following variables overwrite the default values for ```/etc/dovecot/dovecot
##### DOVECOT_URIS
- **empty** => same as `LDAP_SERVER_HOST`
- => Specify a space separated list of LDAP uris.
- Note: If the protocol is missing, `ldap://` will be used.
- Note: This deprecates `DOVECOT_HOSTS` (as it didn't allow to use LDAPS), which is currently still supported for backwards compatibility.
- => Specify a space separated list of LDAP URIs.
- Note: You must include the desired URI scheme (`ldap://`, `ldaps://`, `ldapi://`).
##### DOVECOT_LDAP_VERSION
@ -745,7 +924,7 @@ Note: This postgrey setting needs `ENABLE_POSTGREY=1`
##### SASLAUTHD_LDAP_SERVER
- **empty** => same as `LDAP_SERVER_HOST`
- Note: since version 10.0.0, you can specify a protocol here (like ldaps://); this deprecates SASLAUTHD_LDAP_SSL.
- Note: You must include the desired URI scheme (`ldap://`, `ldaps://`, `ldapi://`).
##### SASLAUTHD_LDAP_START_TLS

View File

@ -8,10 +8,6 @@ Rspamd is a ["fast, free and open-source spam filtering system"][rspamd-homepage
If you want to have a look at the default configuration files for Rspamd that DMS packs, navigate to [`target/rspamd/` inside the repository][dms-default-configuration]. Please consult the [section "The Default Configuration"](#the-default-configuration) section down below for a written overview.
!!! note "AMD64 vs ARM64"
We are currently doing a best-effort installation of Rspamd for ARM64 (from the Debian backports repository for Debian 11). The current version difference as of 23rd Apr 2023: AMD64 is at version 3.5 | ARM64 is at version 3.4.
[rspamd-homepage]: https://rspamd.com/
[dms-default-configuration]: https://github.com/docker-mailserver/docker-mailserver/tree/master/target/rspamd
@ -21,18 +17,64 @@ The following environment variables are related to Rspamd:
1. [`ENABLE_RSPAMD`](../environment.md#enable_rspamd)
2. [`ENABLE_RSPAMD_REDIS`](../environment.md#enable_rspamd_redis)
3. [`RSPAMD_GREYLISTING`](../environment.md#rspamd_greylisting)
4. [`RSPAMD_HFILTER`](../environment.md#rspamd_hfilter)
5. [`RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE`](../environment.md#rspamd_hfilter_hostname_unknown_score)
6. [`RSPAMD_LEARN`](../environment.md#rspamd_learn)
7. [`MOVE_SPAM_TO_JUNK`](../environment.md#move_spam_to_junk)
3. [`RSPAMD_CHECK_AUTHENTICATED`](../environment.md#rspamd_check_authenticated)
4. [`RSPAMD_GREYLISTING`](../environment.md#rspamd_greylisting)
5. [`RSPAMD_HFILTER`](../environment.md#rspamd_hfilter)
6. [`RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE`](../environment.md#rspamd_hfilter_hostname_unknown_score)
7. [`RSPAMD_LEARN`](../environment.md#rspamd_learn)
8. [`MOVE_SPAM_TO_JUNK`][docs-spam-to-junk]
9. [`MARK_SPAM_AS_READ`](../environment.md#mark_spam_as_read)
With these variables, you can enable Rspamd itself and you can enable / disable certain features related to Rspamd.
With these variables, you can enable Rspamd itself, and you can enable / disable certain features related to Rspamd.
[docs-spam-to-junk]: ../environment.md#move_spam_to_junk
## The Default Configuration
### Mode of Operation
!!! tip "Attention"
Read this section carefully if you want to understand how Rspamd is integrated into DMS and how it works (on a surface level).
Rspamd is integrated as a milter into DMS. When enabled, Postfix's `main.cf` configuration file includes the parameter `rspamd_milter = inet:localhost:11332`, which is added to `smtpd_milters`. As a milter, Rspamd can inspect incoming and outgoing e-mails.
Each mail is assigned what Rspamd calls symbols: when an e-mail matches a specific criterion, the mail receives a symbol. Afterwards, Rspamd applies a _spam score_ (as usual with anti-spam software) to the e-mail.
- The score itself is calculated by adding the values of the individual symbols applied earlier. The higher the spam score is, the more likely the e-mail is spam.
- Symbol values can be negative (i.e., these symbols indicate the mail is legitimate, maybe because [SPF and DKIM][docs-dkim-dmarc-spf] are verified successfully) or the symbol can be positive (i.e., these symbols indicate the e-mail is spam, maybe because the e-mail contains a lot of links).
Rspamd then adds (a few) headers to the e-mail based on the spam score. Most important are `X-Spamd-Result`, which contains an overview of which symbols were applied. It could look like this:
```txt
X-Spamd-Result default: False [-2.80 / 11.00]; R_SPF_NA(1.50)[no SPF record]; R_DKIM_ALLOW(-1.00)[example.com:s=dtag1]; DWL_DNSWL_LOW(-1.00)[example.com:dkim]; RWL_AMI_LASTHOP(-1.00)[192.0.2.42:from]; DMARC_POLICY_ALLOW(-1.00)[example.com,none]; RWL_MAILSPIKE_EXCELLENT(-0.40)[192.0.2.42:from]; FORGED_SENDER(0.30)[noreply@example.com,some-reply-address@bounce.example.com]; RCVD_IN_DNSWL_LOW(-0.10)[192.0.2.42:from]; MIME_GOOD(-0.10)[multipart/mixed,multipart/related,multipart/alternative,text/plain]; MIME_TRACE(0.00)[0:+,1:+,2:+,3:+,4:~,5:~,6:~]; RCVD_COUNT_THREE(0.00)[3]; RCPT_COUNT_ONE(0.00)[1]; REPLYTO_DN_EQ_FROM_DN(0.00)[]; ARC_NA(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; RCVD_TLS_LAST(0.00)[]; DKIM_TRACE(0.00)[example.com:+]; HAS_ATTACHMENT(0.00)[]; TO_DN_NONE(0.00)[]; FROM_NEQ_ENVFROM(0.00)[noreply@example.com,some-reply-address@bounce.example.com]; FROM_HAS_DN(0.00)[]; REPLYTO_DOM_NEQ_FROM_DOM(0.00)[]; PREVIOUSLY_DELIVERED(0.00)[receiver@anotherexample.com]; ASN(0.00)[asn:3320, ipnet:192.0.2.0/24, country:DE]; MID_RHS_MATCH_FROM(0.00)[]; MISSING_XM_UA(0.00)[]; HAS_REPLYTO(0.00)[some-reply-address@dms-reply.example.com]
```
And then there is a corresponding `X-Rspamd-Action` header, which shows the overall result and the action that is taken. In our example, it would be:
```txt
X-Rspamd-Action no action
```
Since the score is `-2.80`, nothing will happen and the e-mail is not classified as spam. Our custom [`actions.conf`][rspamd-actions-config] defines what to do at certain scores:
1. At a score of 4, the e-mail is to be _greylisted_;
2. At a score of 6, the e-mail is _marked with a header_ (`X-Spam: Yes`);
3. At a score of 7, the e-mail will additionally have their _subject re-written_ (appending a prefix like `[SPAM]`);
4. At a score of 11, the e-mail is outright _rejected_.
---
There is more to spam analysis than meets the eye: we have not covered the [Bayes training and filters][rspamc-docs-bayes] here, nor have we talked about [Sieve rules for e-mails that are marked as spam][docs-spam-to-junk].
Even the calculation of the score with the individual symbols has been presented to you in a simplified manner. But with the knowledge from above, you're equipped to read on and use Rspamd confidently. Keep on reading to understand the integration even better - you will want to know about your anti-spam software, not only to keep the bad e-mail out, but also to make sure the good e-mail arrive properly!
[docs-dkim-dmarc-spf]: ../best-practices/dkim_dmarc_spf.md
[rspamd-actions-config]: https://github.com/docker-mailserver/docker-mailserver/blob/master/target/rspamd/local.d/actions.conf
[rspamc-docs-bayes]: https://rspamd.com/doc/configuration/statistic.html
### Workers
The proxy worker operates in [self-scan mode][rspamd-docs-proxy-self-scan-mode]. This simplifies the setup as we do not require a normal worker. You can easily change this though by [overriding the configuration by DMS](#providing-custom-settings-overriding-settings).
DMS does not set a default password for the controller worker. You may want to do that yourself. In setups where you already have an authentication provider in front of the Rspamd webpage, you may want to [set the `secure_ip ` option to `"0.0.0.0/0"` for the controller worker](#with-the-help-of-a-custom-file) to disable password authentication inside Rspamd completely.
@ -41,9 +83,9 @@ DMS does not set a default password for the controller worker. You may want to d
### Persistence with Redis
When Rspamd is enabled, we implicitly also start an instance of Redis in the container. Redis is configured to persist it's data via RDB snapshots to disk in the directory `/var/lib/redis` (_which is a symbolic link to `/var/mail-state/lib-redis/` when [`ONE_DIR=1`](../environment.md#one_dir) and a volume is mounted to `/var/mail-state/`_). With the volume mount the snapshot will restore the Redis data across container restarts, and provide a way to keep backup.
When Rspamd is enabled, we implicitly also start an instance of Redis in the container. Redis is configured to persist its data via RDB snapshots to disk in the directory `/var/lib/redis` (_which is a symbolic link to `/var/mail-state/lib-redis/` when [`ONE_DIR=1`](../environment.md#one_dir) and a volume is mounted to `/var/mail-state/`_). With the volume mount the snapshot will restore the Redis data across container restarts, and provide a way to keep backup.
Redis uses `/etc/redis/redis.conf` for configuration. We adjust this file when enabling the internal Redis service. If you have an external instance of Redis to use, the internal Redis service can be opt-out via setting the ENV [`ENABLE_RSPAMD_REDIS=0`](../environment.md#enable_rspamd_redis) (_link also details required changes to the DMS rspamd config_).
Redis uses `/etc/redis/redis.conf` for configuration. We adjust this file when enabling the internal Redis service. If you have an external instance of Redis to use, the internal Redis service can be opt-out via setting the ENV [`ENABLE_RSPAMD_REDIS=0`](../environment.md#enable_rspamd_redis) (_link also details required changes to the DMS Rspamd config_).
### Web Interface
@ -67,6 +109,10 @@ DMS does not supply custom values for DNS servers to Rspamd. If you need to use
This setting is enabled to not allow spam to proceed just because DNS requests did not succeed. It could deny legitimate e-mails to pass though too in case your DNS setup is incorrect or not functioning properly.
### Logs
You can find the Rspamd logs at `/var/log/mail/rspamd.log`, and the corresponding logs for [Redis](#persistence-with-redis), if it is enabled, at `/var/log/supervisor/rspamd-redis.log`. We recommend inspecting these logs (with `docker exec -it <CONTAINER NAME> less /var/log/mail/rspamd.log`) in case Rspamd does not work as expected.
### Modules
You can find a list of all Rspamd modules [on their website][rspamd-docs-modules].
@ -75,13 +121,13 @@ You can find a list of all Rspamd modules [on their website][rspamd-docs-modules
#### Disabled By Default
DMS disables certain modules (clickhouse, elastic, neural, reputation, spamassassin, url_redirector, metric_exporter) by default. We believe these are not required in a standard setup, and they would otherwise needlessly use system resources.
DMS disables certain modules (`clickhouse`, `elastic`, `neural`, `reputation`, `spamassassin`, `url_redirector`, `metric_exporter`) by default. We believe these are not required in a standard setup, and they would otherwise needlessly use system resources.
#### Anti-Virus (ClamAV)
You can choose to enable ClamAV, and Rspamd will then use it to check for viruses. Just set the environment variable `ENABLE_CLAMAV=1`.
#### RBLs (Realtime Blacklists) / DNSBLs (DNS-based Blacklists)
#### RBLs (Real-time Blacklists) / DNSBLs (DNS-based Blacklists)
The [RBL module](https://rspamd.com/doc/modules/rbl.html) is enabled by default. As a consequence, Rspamd will perform DNS lookups to a variety of blacklists. Whether an RBL or a DNSBL is queried depends on where the domain name was obtained: RBL servers are queried with IP addresses extracted from message headers, DNSBL server are queried with domains and IP addresses extracted from the message body \[[source][rbl-vs-dnsbl]\].
@ -101,14 +147,17 @@ DMS brings sane default settings for Rspamd. They are located at `/etc/rspamd/lo
!!! question "What is [`docker-data/dms/config/`][docs-dms-config-volume]?"
If you want to overwrite the default settings and / or provide your own settings, you can place files at `docker-data/dms/config/rspamd/override.d/` (a directory that is linked to `/etc/rspamd/override.d/`, if it exists) to override Rspamd and DMS default settings. This directory will not do a complete file override, but a [forced override of the specific settings in that file][rspamd-docs-override-dir].
If you want to overwrite the default settings and / or provide your own settings, you can place files at `docker-data/dms/config/rspamd/override.d/`. Files from this directory are copied to `/etc/rspamd/override.d/` during startup. These files [forcibly override][rspamd-docs-override-dir] Rspamd and DMS default settings.
!!! question "What is the [`local.d` directory and how does it compare to `override.d`][rspamd-docs-config-directories]?"
!!! warning "Clashing Overrides"
Note that when also [using the `rspamd-commands` file](#with-the-help-of-a-custom-file), files in `override.d` may be overwritten in case you adjust them manually and with the help of the file.
Note that when also [using the `custom-commands.conf` file](#with-the-help-of-a-custom-file), files in `override.d` may be overwritten in case you adjust them manually and with the help of the file.
[rspamd-docs-override-dir]: https://www.rspamd.com/doc/faq.html#what-are-the-locald-and-overrided-directories
[docs-dms-config-volume]: ../../faq.md#what-about-the-docker-datadmsconfig-directory
[rspamd-docs-config-directories]: https://rspamd.com/doc/faq.html#what-are-the-locald-and-overrided-directories
### With the Help of a Custom File
@ -125,7 +174,7 @@ where `COMMAND` can be:
3. `set-option-for-module`: sets the value for option `ARGUMENT2` to `ARGUMENT3` inside module `ARGUMENT1`
4. `set-option-for-controller`: set the value of option `ARGUMENT1` to `ARGUMENT2` for the controller worker
5. `set-option-for-proxy`: set the value of option `ARGUMENT1` to `ARGUMENT2` for the proxy worker
6. `set-common-option`: set the option `ARGUMENT1` that [defines basic Rspamd behaviour][rspamd-docs-basic-options] to value `ARGUMENT2`
6. `set-common-option`: set the option `ARGUMENT1` that [defines basic Rspamd behavior][rspamd-docs-basic-options] to value `ARGUMENT2`
7. `add-line`: this will add the complete line after `ARGUMENT1` (with all characters) to the file `/etc/rspamd/override.d/<ARGUMENT1>`
!!! example "An Example Is [Shown Down Below](#adjusting-and-extending-the-very-basic-configuration)"

View File

@ -161,8 +161,9 @@ Obtain a Cloudflare API token:
dns_cloudflare_api_token = YOUR_CLOUDFLARE_TOKEN_HERE
```
- As this is sensitive data, you should restrict access to it with `chmod 600` and `chown 0:0`.
- Store the file in a folder if you like, such as `docker-data/certbot/secrets/`.
- As this is sensitive data, you should restrict access to it with `chmod 600` and `chown 0:0`.
- Store the file in a folder if you like, such as `docker-data/certbot/secrets/`.
5. Your `compose.yaml` should include the following:
```yaml
@ -594,7 +595,7 @@ This setup only comes with one caveat: The domain has to be configured on anothe
container_name: mailserver
hostname: mail.example.com
volumes:
- ./docker-data/traefik/acme.json:/etc/letsencrypt/acme.json:ro
- ./docker-data/traefik/acme.json:/etc/letsencrypt/acme.json:ro
environment:
SSL_TYPE: letsencrypt
SSL_DOMAIN: mail.example.com
@ -605,26 +606,26 @@ This setup only comes with one caveat: The domain has to be configured on anothe
image: docker.io/traefik:latest #v2.5
container_name: docker-traefik
ports:
- "80:80"
- "443:443"
- "80:80"
- "443:443"
command:
- --providers.docker
- --entrypoints.http.address=:80
- --entrypoints.http.http.redirections.entryPoint.to=https
- --entrypoints.http.http.redirections.entryPoint.scheme=https
- --entrypoints.https.address=:443
- --entrypoints.https.http.tls.certResolver=letsencrypt
- --certificatesresolvers.letsencrypt.acme.email=admin@example.com
- --certificatesresolvers.letsencrypt.acme.storage=/acme.json
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http
- --providers.docker
- --entrypoints.http.address=:80
- --entrypoints.http.http.redirections.entryPoint.to=https
- --entrypoints.http.http.redirections.entryPoint.scheme=https
- --entrypoints.https.address=:443
- --entrypoints.https.http.tls.certResolver=letsencrypt
- --certificatesresolvers.letsencrypt.acme.email=admin@example.com
- --certificatesresolvers.letsencrypt.acme.storage=/acme.json
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=http
volumes:
- ./docker-data/traefik/acme.json:/acme.json
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./docker-data/traefik/acme.json:/acme.json
- /var/run/docker.sock:/var/run/docker.sock:ro
whoami:
image: docker.io/traefik/whoami:latest
labels:
- "traefik.http.routers.whoami.rule=Host(`mail.example.com`)"
- "traefik.http.routers.whoami.rule=Host(`mail.example.com`)"
```
### Self-Signed Certificates

View File

@ -78,6 +78,10 @@ We use `make` to run commands.
When writing tests, ensure that parallel set tests still pass when run in parallel. You need to account for other tests running in parallel that may interfere with your own tests logic.
!!! tip
You may use `make run-local-instance` to run a version of the image built locally to test and edit your changes in a running DMS instance.
### An Example
In this example, you've made a change to the Rspamd feature support (_or adjusted it's tests_). First verify no regressions have been introduced by running it's specific test file:
@ -85,10 +89,10 @@ In this example, you've made a change to the Rspamd feature support (_or adjuste
```console
$ make clean generate-accounts test/rspamd
rspamd.bats
✓ [Rspamd] Postfix's main.cf was adjusted [12]
✓ [Rspamd] normal mail passes fine [44]
✓ [Rspamd] detects and rejects spam [122]
✓ [Rspamd] detects and rejects virus [189]
✓ [Rspamd] Postfix's main.cf was adjusted [12]
✓ [Rspamd] normal mail passes fine [44]
✓ [Rspamd] detects and rejects spam [122]
✓ [Rspamd] detects and rejects virus [189]
```
As your feature work progresses your change for Rspamd also affects ClamAV. As your change now spans more than just the Rspamd test file, you could run multiple test files serially:
@ -96,16 +100,17 @@ As your feature work progresses your change for Rspamd also affects ClamAV. As y
```console
$ make clean generate-accounts test/rspamd,clamav
rspamd.bats
✓ [Rspamd] Postfix's main.cf was adjusted [12]
✓ [Rspamd] normal mail passes fine [44]
✓ [Rspamd] detects and rejects spam [122]
✓ [Rspamd] detects and rejects virus [189]
✓ [Rspamd] Postfix's main.cf was adjusted [12]
✓ [Rspamd] normal mail passes fine [44]
✓ [Rspamd] detects and rejects spam [122]
✓ [Rspamd] detects and rejects virus [189]
clamav.bats
✓ [ClamAV] log files exist at /var/log/mail directory [68]
✓ [ClamAV] should be identified by Amavis [67]
✓ [ClamAV] freshclam cron is enabled [76]
✓ [ClamAV] env CLAMAV_MESSAGE_SIZE_LIMIT is set correctly [63]
✓ [ClamAV] rejects virus [60]
✓ [ClamAV] log files exist at /var/log/mail directory [68]
✓ [ClamAV] should be identified by Amavis [67]
✓ [ClamAV] freshclam cron is enabled [76]
✓ [ClamAV] env CLAMAV_MESSAGE_SIZE_LIMIT is set correctly [63]
✓ [ClamAV] rejects virus [60]
```
You're almost finished with your change before submitting it as a PR. It's a good idea to run the full parallel set those individual tests belong to (_especially if you've modified any tests_):
@ -113,13 +118,15 @@ You're almost finished with your change before submitting it as a PR. It's a goo
```console
$ make clean generate-accounts tests/parallel/set1
default_relay_host.bats
✓ [Relay] (ENV) 'DEFAULT_RELAY_HOST' should configure 'main.cf:relayhost' [88]
✓ [Relay] (ENV) 'DEFAULT_RELAY_HOST' should configure 'main.cf:relayhost' [88]
spam_virus/amavis.bats
✓ [Amavis] SpamAssassin integration should be active [1165]
✓ [Amavis] SpamAssassin integration should be active [1165]
spam_virus/clamav.bats
✓ [ClamAV] log files exist at /var/log/mail directory [73]
✓ [ClamAV] should be identified by Amavis [67]
✓ [ClamAV] freshclam cron is enabled [76]
✓ [ClamAV] log files exist at /var/log/mail directory [73]
✓ [ClamAV] should be identified by Amavis [67]
✓ [ClamAV] freshclam cron is enabled [76]
...
```
@ -127,7 +134,6 @@ Even better, before opening a PR run the full test suite:
```console
$ make clean tests
...
```
[BATS]: https://github.com/bats-core/bats-core

View File

@ -0,0 +1,74 @@
---
title: 'Tutorials | Crowdsec'
---
!!! quote "What is Crowdsec?"
Crowdsec is an open source software that detects and blocks attackers using log analysis.
It has access to a global community-wide IP reputation database.
[Source](https://www.crowdsec.net)
## Installation
Crowdsec supports multiple [installation methods][crowdsec-installation-docs], however this page will use the docker installation.
### Docker mailserver
In your `compose.yaml` for the DMS service, add a bind mount volume for `/var/log/mail`. This is to share the DMS logs to a separate crowdsec container.
!!! example
```yaml
services:
mailserver:
- /docker-data/dms/mail-logs/:/var/log/mail/
```
### Crowdsec
The crowdsec container should also bind mount the same host path for the DMS logs that was added in the DMS example above.
```yaml
services:
image: crowdsecurity/crowdsec
restart: unless-stopped
ports:
- "8080:8080"
- "6060:6060"
volumes:
- /docker-data/dms/mail-logs/:/var/log/dms:ro
- ./acquis.d:/etc/crowdsec/acquis.d
- crowdsec-db:/var/lib/crowdsec/data/
environment:
# These collection contains parsers and scenarios for postfix and dovecot
COLLECTIONS: crowdsecurity/postfix crowdsecurity/dovecot
TZ: Europe/Paris
volumes:
crowdsec-db:
```
## Configuration
Configure crowdsec to read and parse DMS logs file.
!!! example
Create the file `dms.yml` in `./acquis.d/`
```yaml
---
source: file
filenames:
- /var/log/dms/mail.log
labels:
type: syslog
```
!!! warning Bouncers
Crowdsec on its own is just a detection software, the remediation is done by components called bouncers.
This page does not explain how to install or configure a bouncer. It can be found in [crowdsec documentation][crowdsec-bouncer-docs].
[crowdsec-installation-docs]: https://doc.crowdsec.net/docs/getting_started/install_crowdsec
[crowdsec-bouncer-docs]: https://doc.crowdsec.net/docs/bouncers/intro

View File

@ -10,7 +10,7 @@ You'll need to retrieve the git submodules prior to building your own Docker ima
```sh
git submodule update --init --recursive
docker build -t <YOUR CUSTOM IMAGE NAME> .
docker build --tag <YOUR CUSTOM IMAGE NAME> .
```
Or, you can clone and retrieve the submodules in one command:
@ -21,19 +21,26 @@ git clone --recurse-submodules https://github.com/docker-mailserver/docker-mails
### About Docker
#### Version
#### Minimum supported version
We make use of build-features that require a recent version of Docker. Depending on your distribution, please have a look at [the official installation documentation for Docker](https://docs.docker.com/engine/install/) to get the latest version. Otherwise, you may encounter issues, for example with the `--link` flag for a [`#!dockerfile COPY`](https://docs.docker.com/engine/reference/builder/#copy) command.
We make use of build features that require a recent version of Docker. v23.0 or newer is advised, but earlier releases may work.
#### Environment
- To get the latest version for your distribution, please have a look at [the official installation documentation for Docker](https://docs.docker.com/engine/install/).
- If you are using a version of Docker prior to v23.0, you will need to enable BuildKit via the ENV [`DOCKER_BUILDKIT=1`](https://docs.docker.com/build/buildkit/#getting-started).
If you are not using `make` to build the image, note that you will need to provide `DOCKER_BUILDKIT=1` to the `docker build` command for the build to succeed.
#### Build Arguments (Optional)
#### Build Arguments
The `Dockerfile` includes several build [`ARG`][docker-docs::builder-arg] instructions that can be configured:
The `Dockerfile` takes additional, so-called build arguments. These are
- `DOVECOT_COMMUNITY_REPO`: Install Dovecot from the community repo instead of from Debian (default = 1)
- `DMS_RELEASE`: The image version (default = edge)
- `VCS_REVISION`: The git commit hash used for the build (default = unknown)
1. `VCS_VERSION`: the image version (default = edge)
2. `VCS_REVISION`: the image revision (default = unknown)
!!! note
When using `make` to build the image, these are filled with proper values. You can build the image without supplying these arguments just fine though.
- `DMS_RELEASE` (_when not `edge`_) will be used to check for updates from our GH releases page at runtime due to the default feature [`ENABLE_UPDATE_CHECK=1`][docs::env-update-check].
- Both `DMS_RELEASE` and `VCS_REVISION` are also used with `opencontainers` metadata [`LABEL`][docker-docs::builder-label] instructions.
[docs::env-update-check]: https://docker-mailserver.github.io/docker-mailserver/latest/config/environment/#enable_update_check
[docker-docs::builder-arg]: https://docs.docker.com/engine/reference/builder/#using-arg-variables
[docker-docs::builder-label]: https://docs.docker.com/engine/reference/builder/#label

View File

@ -72,14 +72,15 @@ Feel free to add your configuration if you achieved the same goal using differen
- "traefik.tcp.services.smtp.loadbalancer.server.port=25"
- "traefik.tcp.services.smtp.loadbalancer.proxyProtocol.version=1"
- "traefik.tcp.routers.smtp-ssl.rule=HostSNI(`*`)"
- "traefik.tcp.routers.smtp-ssl.tls=false"
- "traefik.tcp.routers.smtp-ssl.entrypoints=smtp-ssl"
- "traefik.tcp.routers.smtp-ssl.tls.passthrough=true"
- "traefik.tcp.routers.smtp-ssl.service=smtp-ssl"
- "traefik.tcp.services.smtp-ssl.loadbalancer.server.port=465"
- "traefik.tcp.services.smtp-ssl.loadbalancer.proxyProtocol.version=1"
- "traefik.tcp.routers.imap-ssl.rule=HostSNI(`*`)"
- "traefik.tcp.routers.imap-ssl.entrypoints=imap-ssl"
- "traefik.tcp.routers.imap-ssl.service=imap-ssl"
- "traefik.tcp.routers.imap-ssl.tls.passthrough=true"
- "traefik.tcp.services.imap-ssl.loadbalancer.server.port=10993"
- "traefik.tcp.services.imap-ssl.loadbalancer.proxyProtocol.version=2"
- "traefik.tcp.routers.sieve.rule=HostSNI(`*`)"

View File

@ -0,0 +1,162 @@
---
title: 'Examples | Use Cases | Lua Authentication'
---
## Introduction
Dovecot has the ability to let users create their own custom user provisioning and authentication providers in [Lua](https://en.wikipedia.org/wiki/Lua_(programming_language)#Syntax). This allows any data source that can be approached from Lua to be used for authentication, including web servers. It is possible to do more with Dovecot and Lua, but other use cases fall outside of the scope of this documentation page.
!!! warning "Community contributed guide"
Dovecot authentication via Lua scripting is not officially supported in DMS. No assistance will be provided should you encounter any issues.
DMS provides the required packages to support this guide. Note that these packages will be removed should they introduce any future maintenance burden.
The example in this guide relies on the current way in which DMS works with Dovecot configuration files. Changes to this to accommodate new authentication methods such as OpenID Connect will likely break this example in the future. This guide is updated on a best-effort base.
Dovecot's Lua support can be used for user provisioning (userdb functionality) and/or password verification (passdb functionality). Consider using other userdb and passdb options before considering Lua, since Lua does require the use of additional (unsupported) program code that might require maintenance when updating DMS.
Each implementation of Lua-based authentication is custom. Therefore it is impossible to write documentation that covers every scenario. Instead, this page describes a single example scenario. If that scenario is followed, you will learn vital aspects that are necessary to kickstart your own Lua development:
- How to override Dovecot's default configuration to disable parts that conflict with your scenario.
- How to make Dovecot use your Lua script.
- How to add your own Lua script and any libraries it uses.
- How to debug your Lua script.
## The example scenario
This scenario starts with [DMS being configured to use LDAP][docs::auth-ldap] for mailbox identification, user authorization and user authentication. In this scenario, [Nextcloud](https://nextcloud.com/) is also a service that uses the same LDAP server for user identification, authorization and authentication.
The goal of this scenario is to have Dovecot not authenticate the user against LDAP, but against Nextcloud using an [application password](https://docs.nextcloud.com/server/latest/user_manual/en/session_management.html#managing-devices). The idea behind this is that a compromised mailbox password does not compromise the user's account entirely. To make this work, Nextcloud is configured to [deny the use of account passwords by clients](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/config_sample_php_parameters.html#token-auth-enforced) and to [disable account password reset through mail verification](https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/config_sample_php_parameters.html#lost-password-link).
If the application password is configured correctly, an adversary can only use it to access the user's mailbox on DMS, and CalDAV and CardDAV data on Nextcloud. File access through WebDAV can be disabled for the application password used to access mail. Having CalDAV and CardDAV compromised by the same password is a minor setback. If an adversary gets access to a Nextcloud application password through a device of the user, it is likely that the adversary also gets access to the user's calendars and contact lists anyway (locally or through the same account settings used for mail and CalDAV/CardDAV synchronization). The user's stored files in Nextcloud, the LDAP account password and any other services that rely on it would still be protected. A bonus is that a user is able to revoke and renew the mailbox password in Nextcloud for whatever reason, through a friendly user interface with all the security measures with which the Nextcloud instance is configured (e.g. verification of the current account password).
A drawback of this method is that any (compromised) Nextcloud application password can be used to access the user's mailbox. This introduces a risk that a Nextcloud application password used for something else (e.g. WebDAV file access) is compromised and used to access the user's mailbox. Discussion of that risk and possible mitigations fall outside of the scope of this scenario.
To answer the questions asked earlier for this specific scenario:
1. Do I want to use Lua to identify mailboxes and verify that users are are authorized to use mail services? **No. Provisioning is done through LDAP.**
1. Do I want to use Lua to verify passwords that users authenticate with for IMAP/POP3/SMTP in their mail clients? **Yes. Password authentication is done through Lua against Nextcloud.**
1. If the answer is 'yes' to question 1 or 2: are there other methods that better facilitate my use case instead of custom scripts which rely on me being a developer and not just a user? **No. Only HTTP can be used to authenticate against Nextcloud, which is not supported natively by Dovecot or DMS.**
While it is possible to extend the authentication methods which Nextcloud can facilitate with [Nextcloud apps](https://apps.nextcloud.com/), there is currently a mismatch between what DMS supports and what Nextcloud applications can provide. This might change in the future. For now, Lua will be used to bridge the gap between DMS and Nextcloud for authentication only (Dovecot passdb), while LDAP will still be used to identify mailboxes and verify authorization (Dovecot userdb).
## Modify Dovecot's configuration
???+ example "Add to DMS volumes in `compose.yaml`"
```yaml
# All new volumes are marked :ro to configure them as read-only, since their contents are not changed from inside the container
volumes:
# Configuration override to disable LDAP authentication
- ./docker-data/dms/config/dovecot/auth-ldap.conf.ext:/etc/dovecot/conf.d/auth-ldap.conf.ext:ro
# Configuration addition to enable Lua authentication
- ./docker-data/dms/config/dovecot/auth-lua-httpbasic.conf:/etc/dovecot/conf.d/auth-lua-httpbasic.conf:ro
# Directory containing Lua scripts
- ./docker-data/dms/config/dovecot/lua/:/etc/dovecot/lua/:ro
```
Create a directory for Lua scripts:
```bash
mkdir -p ./docker-data/dms/config/dovecot/lua
```
Create configuration file `./docker-data/dms/config/dovecot/auth-ldap.conf.ext` for LDAP user provisioning:
```
userdb {
driver = ldap
args = /etc/dovecot/dovecot-ldap.conf.ext
}
```
Create configuration file `./docker-data/dms/config/dovecot/auth-lua-httpbasic.conf` for Lua user authentication:
```
passdb {
driver = lua
args = file=/etc/dovecot/lua/auth-httpbasic.lua blocking=yes
}
```
That is all for configuring Dovecot.
## Create the Lua script
Create Lua file `./docker-data/dms/config/dovecot/lua/auth-httpbasic.lua` with contents:
```lua
local http_url = "https://nextcloud.example.com/remote.php/dav/"
local http_method = "PROPFIND"
local http_status_ok = 207
local http_status_failure = 401
local http_header_forwarded_for = "X-Forwarded-For"
package.path = package.path .. ";/etc/dovecot/lua/?.lua"
local base64 = require("base64")
local http_client = dovecot.http.client {
timeout = 1000;
max_attempts = 1;
debug = false;
}
function script_init()
return 0
end
function script_deinit()
end
function auth_passdb_lookup(req)
local auth_request = http_client:request {
url = http_url;
method = http_method;
}
auth_request:add_header("Authorization", "Basic " .. (base64.encode(req.user .. ":" .. req.password)))
auth_request:add_header(http_header_forwarded_for, req.remote_ip)
local auth_response = auth_request:submit()
local resp_status = auth_response:status()
local reason = auth_response:reason()
local returnStatus = dovecot.auth.PASSDB_RESULT_INTERNAL_FAILURE
local returnDesc = http_method .. " - " .. http_url .. " - " .. resp_status .. " " .. reason
if resp_status == http_status_ok
then
returnStatus = dovecot.auth.PASSDB_RESULT_OK
returnDesc = "nopassword=y"
elseif resp_status == http_status_failure
then
returnStatus = dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH
returnDesc = ""
end
return returnStatus, returnDesc
end
```
Replace the hostname in the URL to the actual hostname of Nextcloud.
Dovecot [provides an HTTP client for use in Lua](https://doc.dovecot.org/admin_manual/lua/#dovecot.http.client). Aside of that, Lua by itself is pretty barebones. It chooses library compactness over included functionality. You can see that in that a separate library is referenced to add support for Base64 encoding, which is required for [HTTP basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication). This library (also a Lua script) is not included. It must be downloaded and stored in the same directory:
```bash
cd ./docker-data/dms/config/dovecot/lua
curl -JLO https://raw.githubusercontent.com/iskolbin/lbase64/master/base64.lua
```
Only use native (pure Lua) libraries as dependencies if possible, such as `base64.lua` from the example. This ensures maximum compatibility. Performance is less of an issue since Lua scripts written for Dovecot probably won't be long or complex, and there won't be a lot of data processing by Lua itself.
## Debugging a Lua script
To see which Lua version is used by Dovecot if you plan to do something that is version dependent, run:
```bash
docker exec CONTAINER_NAME strings /usr/lib/dovecot/libdovecot-lua.so|grep '^LUA_'
```
While Dovecot logs the status of authentication attempts for any passdb backend, Dovecot will also log Lua scripting errors and messages sent to Dovecot's [Lua API log functions](https://doc.dovecot.org/admin_manual/lua/#dovecot.i_debug). The combined DMS log (including that of Dovecot) can be viewed using `docker logs CONTAINER_NAME`. If the log is too noisy (_due to other processes in the container also logging to it_), `docker exec CONTAINER_NAME cat /var/log/mail/mail.log` can be used to view the log of Dovecot and Postfix specifically.
If working with HTTP in Lua, setting `debug = true;` when initiating `dovecot.http.client` will create debug log messages for every HTTP request and response.
Note that Lua runs compiled bytecode, and that scripts will be compiled when they are initially started. Once compiled, the bytecode is cached and changes in the Lua script will not be processed automatically. Dovecot will reload its configuration and clear its cached Lua bytecode when running `docker exec CONTAINER_NAME dovecot reload`. A (changed) Lua script will be compiled to bytecode the next time it is executed after running the Dovecot reload command.
[docs::auth-ldap]: ../../config/advanced/auth-ldap.md
[docs::dovecot-override-configuration]: ../../config/advanced/override-defaults/dovecot.md#override-configuration
[docs::dovecot-add-configuration]: ../../config/advanced/override-defaults/dovecot.md#add-configuration
[docs::faq-alter-running-dms-instance-without-container-relaunch]: ../../faq.md#how-to-alter-a-running-dms-instance-without-relaunching-the-container

View File

@ -30,7 +30,6 @@ We can create aliases with `./setup.sh`, like this:
If you want to send emails from outside the mail server you have to authenticate somehow (with a username and password). One way of doing it is described in [this discussion][github-issue-1247]. However if there are many user accounts, it is better to use authentication with LDAP. The settings for this on `mailserver.env` are:
```env
ENABLE_LDAP=1 # with the :edge tag, use ACCOUNT_PROVISIONER
ACCOUNT_PROVISIONER=LDAP
LDAP_START_TLS=yes
LDAP_SERVER_HOST=ldap.example.org

View File

@ -61,7 +61,7 @@ Take care to test localized names work well as well.
This information is provided by the community.
It presently lacks references to confirm the behaviour. If any information is incorrect please let us know! :smile:
It presently lacks references to confirm the behavior. If any information is incorrect please let us know! :smile:
[docs-config-overrides-dovecot]: ../../config/advanced/override-defaults/dovecot.md#override-configuration

View File

@ -0,0 +1,232 @@
---
title: 'Advanced | iOS Mail Push Support'
---
## Introduction
iOS Mail currently does not support the IMAP idle extension. Therefore users can only either check manually or configure intervals for fetching mails in their mail account preferences when using the default configuration.
To support mail push Dovecot needs to advertise the `XAPPLEPUSHSERVICE` IMAP extension as well as sending the actual push notifications to the Apple Push Notification service (APNs) which will forward them to the device.
This can be done with two components:
- A Dovecot plugin (`dovecot-xaps-plugin`) which is triggered whenever a mail is created or moved from/to a mail folder.
- A daemon service (`dovecot-xaps-daemon`) that manages both the device registrations as well as sending notifications to the APNs.
## Prerequisites
- An Apple developer account to create the required Apple Push Notification service certificate.
- Knowledge creating Docker images, using the command-line, and creating shell scripts.
## Limitations
- You need to maintain a custom `docker-mailserver` image.
- Push support is limited to the INBOX folder. Changes to other folders will not be pushed to the device regardless of the configuration settings.
- You currently cannot use the same account UUID on multiple devices. This means that if you use the same backup on multiple devices (e.g. old phone / new phone) only one of them will get the notification. Use different backups or recreate the mail account.
## Privacy concerns
- The service does not send any part of the actual message to Apple.
- The information sent contains the device UUID to notify and the (on-device) account UUID which was generated by the iOS mail application when creating the account.
- Upon receiving the notification, the iOS mail application will connect to the IMAP server given by the provided account UUID and fetch the mail to notify the user.
- Apple therefore does not know the mail address for which the mail was received, only that a specific account on a specific device should be notified that a new mail or that a mail was moved to the INBOX folder.
## Installation
Both components will be built using Docker and included into a custom `docker-mailserver` image. Afterwards the required configuration is added to `docker-data/dms/config`. The registration data is stored in `/var/mail-state/lib-xapsd`.
1. Create a Dockerfile to build a `docker-mailserver` image that includes the [`dovecot-xaps-plugin`](https://github.com/freswa/dovecot-xaps-plugin) as well as the [`dovecot-xaps-daemon`](https://github.com/freswa/dovecot-xaps-daemon). This is required to ensure that the Dovecot plugin is built against the same Dovecot version. The `:edge` tag is used here, but you might want to use a released version instead.
```dockerfile
FROM mailserver/docker-mailserver:edge AS dovecot-plugin-xaps
WORKDIR /tmp/dovecot-xaps-plugin
RUN <<EOF
apt-get update
apt-get -y --no-install-recommends install git cmake make build-essential dovecot-dev
git clone --single-branch --depth=1 https://github.com/freswa/dovecot-xaps-plugin.git .
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make install
EOF
# Use an older Go version as Go >= 1.20 causes this issue: https://github.com/freswa/dovecot-xaps-daemon/issues/24#issuecomment-1483876081
# Note that the underlying issue are non-standard-compliant Apple http servers which might get fixed at some point
FROM golang:1.19-alpine AS dovecot-xaps-daemon
ENV GOPROXY=https://proxy.golang.org,direct
ENV CGO_ENABLED=0
WORKDIR /go/dovecot-xaps-daemon
RUN <<EOF
apk add --no-cache --virtual build-dependencies git
git clone --single-branch --depth=1 https://github.com/freswa/dovecot-xaps-daemon .
go build ./cmd/xapsd
EOF
FROM mailserver/docker-mailserver:edge
COPY --from=dovecot-plugin-xaps /usr/lib/dovecot/modules/*_xaps_* /usr/lib/dovecot/modules/
COPY --from=dovecot-xaps-daemon /go/dovecot-xaps-daemon/xapsd /usr/bin/xapsd
# create a non-root user for the daemon process as well as configuration and run state directories
RUN <<EOF
adduser --quiet --system --group --disabled-password --home /var/mail-state/lib-xapsd --no-create-home xapsd
mkdir -p /var/run/xapsd /etc/xapsd
EOF
```
2. Build the new image:
```sh
docker build -t yourname/docker-mailserver .
```
3. Modify your `compose.yaml` to use the newly created image:
```yaml
services:
mailserver:
image: yourname/docker-mailserver:latest
```
4. Recreate the container:
```sh
docker compose down
docker compose up -d
```
5. Create a hash of your Apple developer account password using the provided `xapsd -pass` command:
```sh
docker exec -it mailserver xapsd -pass
```
6. Add configuration for both components:
- Create a folder named `xaps` in `docker-data/dms/config`.
- Create a file named `xapsd.yaml` in `docker-data/dms/config/xaps`.
- Replace `appleId` and `appleIdHashedPassword` with your actual credentials. For reference see also [here](https://github.com/freswa/dovecot-xaps-daemon/blob/master/configs/xapsd/xapsd.yaml).
- The service will use the provided username/hash combination to automatically request a new certificate from Apple as well as renewing an older certificate if needed.
```yaml title="xapsd.yaml"
# set the loglevel to either
# trace, debug, error, fatal, info, panic or warn
# Default: info
loglevel: info
# xapsd creates a json file to store the registration persistent on disk.
# This sets the location of the file.
databaseFile: /var/mail-state/lib-xapsd/database.json
# xapsd listens on a socket for http/https requests from the dovecot plugin.
# This sets the address and port number of the listen socket.
listenAddr: '127.0.0.1'
port: 11619
# xapsd is able to listen on a HTTPS Socket to allow HTTP/2 to be used
# SSL is enabled implicitly when certfile and keyfile exist
# !!! only use HTTPS for connection pooling with a proxy e.g. nginx or HaProxy
# !!! direct usage with the plugin is discouraged and unsupported
tlsCertfile:
tlsKeyfile:
tlsListenAddr:
tlsPort: 11620
# Notifications that are not initiated by new messages are not sent immediately for two reasons:
# 1. When you move/copy/delete messages you most likely move/copy/delete more messages within a short period of time.
# 2. You don't need your mailboxes to synchronize immediately since they are automatically synchronized when opening
# the app
# If a new message comes and the move/copy/delete notification is still on hold it will be sent with the notification
# for the new message.
# This sets the interval to check for delayed messages.
checkInterval: 20
# Set the time how long notifications for not-new messages should be delayed until they are sent.
# Whenever checkInterval runs, it checks if "delay" <= "waiting time" and sends the notification if the expression is
# true.
delay: 30
# To retrieve certificates from Apple, we need to login with a valid Apple ID
# The accounts email must be given in cleartext, but the password has to
# be hashed before sending it. To not leak working credentials on running servers,
# we do not accept the cleartext password here.
appleId: foo@example.com
# use `xaps -pass` to calculate the hash of the apple id password
appleIdHashedPassword: bar
```
- Create a file named `95-xaps.conf` in `docker-data/dms/config/xaps`. For reference see also [here](https://github.com/freswa/dovecot-xaps-plugin/blob/master/xaps.conf).
```txt title="95-xaps.conf"
protocol imap {
mail_plugins = $mail_plugins notify push_notification xaps_push_notification xaps_imap
}
protocol lda {
mail_plugins = $mail_plugins notify push_notification xaps_push_notification
}
protocol lmtp {
mail_plugins = $mail_plugins notify push_notification xaps_push_notification
}
plugin {
# xaps_config contains xaps specific configuration parameters
# url: protocol, hostname and port under which xapsd listens
# user_lookup: Use if you want to determine the username used for PNs from environment variables provided by
# login mechanism. Value is variable name to look up.
# max_retries: maximum num of retries the http client connects to the xaps daemon
# timeout_msecs http timeout of the http connection
xaps_config = url=http://127.0.0.1:11619 user_lookup=theattribute max_retries=6 timeout_msecs=5000
push_notification_driver = xaps
}
```
- Create a supervisord file named `xapsd.conf` in `docker-data/dms/config/xaps` with the following content:
```txt title="xapsd.conf"
[program:xapsd]
startsecs=0
autostart=false
autorestart=true
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
user=xapsd
command=/usr/bin/xapsd
pidfile=/var/run/xapsd/xapsd.pid
```
- Create or update your `user-patches.sh` in `docker-data/dms/config` to move the files to their final location as well as starting the daemon service:
```sh title="user-patches.sh"
#!/bin/bash
# Copy the configs to internal locations:
cp /tmp/docker-mailserver/xaps/95-xaps.conf /etc/dovecot/conf.d/95-xaps.conf
cp /tmp/docker-mailserver/xaps/xapsd.yaml /etc/xapsd/xapsd.yaml
cp /tmp/docker-mailserver/xaps/xapsd.conf /etc/supervisor/conf.d/xapsd.conf
# Setup data persistence and ensure ownership is always for xapsd:
mkdir -p /var/mail-state/lib-xapsd
chown -R xapsd:xapsd /var/mail-state/lib-xapsd
# Start the xaps daemon:
supervisorctl update
supervisorctl start xapsd
```
7. Recreate the container again to apply the new configuration:
```sh
docker compose down
docker compose up -d
```
8. Recreate your mail account on your iOS device and check the logs in `/var/log/supervisor/dovecot.log` and `/var/log/supervisor/xapsd.log` for any errors.
## Other configuration options
Both device registration and notifications send a username to the daemon to lookup the device. While the registration and other IMAP operations in Dovecot will send the Dovecot username, LMTP will send the provided authentication username.
The format of that username is specified by the `auth_username_format` Dovecot setting. If you are not using mail addresses as Dovecot usernames - e.g. when using LDAP - you can either change the `auth_username_format` or add the mail address as property to the user account and use the lookup feature (see below).
```sh title="user-patches.sh"
sed -i -r "s|^#?(auth_username_format =).*|\1 %Ln|" /etc/dovecot/conf.d/10-auth.conf
```
You can also use notifications for Dovecot alias mailboxes. Depending on your server configuration, this might require to add the original Dovecot username as [Dovecot attribute](https://doc.dovecot.org/configuration_manual/authentication/user_database_extra_fields/) to the login user as well as changing the `user_lookup=theattribute` in `95-xaps.conf` to perform the lookup of that attribute.

View File

@ -12,7 +12,7 @@ Mails are stored in `/var/mail/${domain}/${username}`. Since `v9.0.0` it is poss
### How are IMAP mailboxes (_aka IMAP Folders_) set up?
`INBOX` is setup by default with the special IMAP folders `Drafts`, `Sent`, `Junk` and `Trash`. You can learn how to modify or add your own folders (_including additional special folders like `Archive`_) by visiting our docs page [_Customizing IMAP Folders_](../examples/use-cases/imap-folders) for more information.
`INBOX` is setup by default with the special IMAP folders `Drafts`, `Sent`, `Junk` and `Trash`. You can learn how to modify or add your own folders (_including additional special folders like `Archive`_) by visiting our docs page [_Customizing IMAP Folders_](./examples/use-cases/imap-folders.md) for more information.
### How do I update DMS?
@ -128,7 +128,7 @@ find "${PWD}/docker-data/dms-backups/" -type f -mtime +30 -delete
### I Want to Know More About the Ports
See [this part of the documentation](../config/security/understanding-the-ports/) for further details and best practice advice, **especially regarding security concerns**.
See [this part of the documentation](./config/security/understanding-the-ports.md) for further details and best practice advice, **especially regarding security concerns**.
### How can I configure my email client?
@ -143,7 +143,7 @@ imap port: 143 or 993 with STARTTLS/SSL (recommended)
imap path prefix: INBOX
# SMTP
smtp port: 25 or 587/465 with STARTTLS/SSL (recommended)
smtp port: 587 or 465 with STARTTLS/SSL (recommended)
username: <user1@example.com>
password: <mypassword>
```
@ -210,7 +210,7 @@ baduser@example.com devnull
### What kind of SSL certificates can I use?
Both RSA and ECDSA certs are supported. You can provide your own cert files manually, or mount a `letsencrypt` generated directory (_with alternative support for Traefik's `acme.json`_). Check out the [`SSL_TYPE` documentation](../config/environment/#ssl_type) for more details.
Both RSA and ECDSA certs are supported. You can provide your own cert files manually, or mount a `letsencrypt` generated directory (_with alternative support for Traefik's `acme.json`_). Check out the [`SSL_TYPE` documentation](./config/environment.md#ssl_type) for more details.
### I just moved from my old mail server to DMS, but "it doesn't work"?
@ -378,18 +378,7 @@ When you run DMS with the ENV variable `ONE_DIR=1` (default), this directory wil
#### How can I manage my custom SpamAssassin rules?
Antispam rules are managed in `docker-data/dms/config/spamassassin-rules.cf`.
#### What are acceptable `SA_SPAM_SUBJECT` values?
For no subject set `SA_SPAM_SUBJECT=undef`.
For a trailing white-space subject one can define the whole variable with quotes in `compose.yaml`:
```yaml
environment:
- "SA_SPAM_SUBJECT=[SPAM] "
```
Anti-spam rules are managed in `docker-data/dms/config/spamassassin-rules.cf`.
#### Why are SpamAssassin `x-headers` not inserted into my `subdomain.example.com` subdomain emails?
@ -479,58 +468,39 @@ The following configuration works nicely:
file: ./docker-data/dms/cron/sa-learn
```
With the default settings, SpamAssassin will require 200 mails trained for spam (for example with the method explained above) and 200 mails trained for ham (using the same command as above but using `--ham` and providing it with some ham mails). Until you provided these 200+200 mails, SpamAssassin will not take the learned mails into account. For further reference, see the [SpamAssassin Wiki](https://wiki.apache.org/spamassassin/BayesNotWorking).
With the default settings, SpamAssassin will require 200 mails trained for spam (for example with the method explained above) and 200 mails trained for ham (using the same command as above but using `--ham` and providing it with some ham mails).
- Until you provided these 200+200 mails, SpamAssassin will not take the learned mails into account.
- For further reference, see the [SpamAssassin Wiki](https://wiki.apache.org/spamassassin/BayesNotWorking).
#### How do I have more control about what SpamAssassin is filtering?
By default, SPAM and INFECTED emails are put to a quarantine which is not very straight forward to access. Several config settings are affecting this behavior:
This is related to Amavis processing the mail after SpamAssassin has analyzed it and assigned a spam score.
First, make sure you have the proper thresholds set:
- DMS provides some [common SA tunables via ENV][docs::env::sa_env].
- Additional configuration can be managed with the DMS config volume by providing `docker-data/dms/config/amavis.cf`.
```conf
SA_TAG=-100000.0
SA_TAG2=3.75
SA_KILL=100000.0
```
#### How can I send quarantined mail to a mailbox?
- The very negative value in `SA_TAG` makes sure, that all emails have the SpamAssassin headers included.
- `SA_TAG2` is the actual threshold to set the YES/NO flag for spam detection.
- `SA_KILL` needs to be very high, to make sure nothing is bounced at all (`SA_KILL` superseeds `SPAMASSASSIN_SPAM_TO_INBOX`)
SPAM and INFECTED emails that [reach the `SA_KILL` threshold are archived into quarantine][docs::env::sa_kill].
Make sure everything (including SPAM) is delivered to the inbox and not quarantined:
```conf
SPAMASSASSIN_SPAM_TO_INBOX=1
```
Use `MOVE_SPAM_TO_JUNK=1` or create a sieve script which puts spam to the Junk folder:
```sieve
require ["comparator-i;ascii-numeric","relational","fileinto"];
if header :contains "X-Spam-Flag" "YES" {
fileinto "Junk";
} elsif allof (
not header :matches "x-spam-score" "-*",
header :value "ge" :comparator "i;ascii-numeric" "x-spam-score" "3.75" ) {
fileinto "Junk";
}
```
Create a dedicated mailbox for emails which are infected/bad header and everything amavis is blocking by default and put its address into `docker-data/dms/config/amavis.cf`
Instead of a quarantine folder, you can use a dedicated mailbox instead. Create an account like `quarantine@example.com` and create `docker-data/dms/config/amavis.cf`:
```cf
$clean_quarantine_to = "amavis\@example.com";
$virus_quarantine_to = "amavis\@example.com";
$banned_quarantine_to = "amavis\@example.com";
$bad_header_quarantine_to = "amavis\@example.com";
$spam_quarantine_to = "amavis\@example.com";
$clean_quarantine_to = "quarantine\@example.com";
$virus_quarantine_to = "quarantine\@example.com";
$banned_quarantine_to = "quarantine\@example.com";
$bad_header_quarantine_to = "quarantine\@example.com";
$spam_quarantine_to = "quarantine\@example.com";
```
[fail2ban-customize]: ./config/security/fail2ban.md
[docs-maintenance]: ./config/advanced/maintenance/update-and-cleanup.md
[docs-override-postfix]: ./config/advanced/override-defaults/postfix.md
[docs-userpatches]: ./config/advanced/override-defaults/user-patches.md
[docs-optional-configuration]: ./config/advanced/optional-config.md
[docs::env::sa_env]: ./config/environment.md#spamassassin
[docs::env::sa_kill]: ./config/environment.md#sa_kill
[github-comment-baredomain]: https://github.com/docker-mailserver/docker-mailserver/issues/3048#issuecomment-1432358353
[github-comment-override-hostname]: https://github.com/docker-mailserver/docker-mailserver/issues/1731#issuecomment-753968425
[github-issue-95]: https://github.com/docker-mailserver/docker-mailserver/issues/95
@ -541,4 +511,3 @@ $spam_quarantine_to = "amavis\@example.com";
[github-issue-1792]: https://github.com/docker-mailserver/docker-mailserver/pull/1792
[hanscees-userpatches]: https://github.com/hanscees/dockerscripts/blob/master/scripts/tomav-user-patches.sh
[mail-state-folders]: https://github.com/docker-mailserver/docker-mailserver/blob/c7e498194546416fb7231cb03254e77e085d18df/target/scripts/startup/misc-stack.sh#L24-L33
[docs-optional-configuration]: ./config/advanced/optional-config.md

View File

@ -14,7 +14,7 @@ This documentation provides you not only with the basic setup and configuration
## About
`docker-mailserver`, or DMS for short, is a production-ready fullstack but simple mail server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.). It employs only configuration files, no SQL database. The image is focused around the slogan "Keep it simple and versioned".
`docker-mailserver`, or DMS for short, is a production-ready fullstack but simple mail server (SMTP, IMAP, LDAP, Anti-spam, Anti-virus, etc.). It employs only configuration files, no SQL database. The image is focused around the slogan "Keep it simple and versioned".
## Contents
@ -24,9 +24,9 @@ If you're completely new to mail servers or you want to read up on them, check o
There is also a script - [`setup.sh`][github-file-setupsh] - supplied with this project. It supports you in configuring and administrating your server. Information on how to get it and how to use it is available [on a dedicated page][docs-setupsh].
[docs-introduction]: ./introduction/
[docs-usage]: ./usage/
[docs-examples]: ./examples/tutorials/basic-installation/
[docs-introduction]: ./introduction.md
[docs-usage]: ./usage.md
[docs-examples]: ./examples/tutorials/basic-installation.md
[github-file-setupsh]: https://github.com/docker-mailserver/docker-mailserver/blob/master/setup.sh
[docs-setupsh]: ./config/setup.sh/
@ -59,10 +59,10 @@ You might also want to check out:
DMS employs a variety of tests. If you want to know more about our test suite, view our [testing docs][docs-tests].
[docs-tests]: ./contributing/tests/
[docs-tests]: ./contributing/tests.md
### Contributing
We are always happy to welcome new contributors. For guidelines and entrypoints please have a look at the [Contributing section][docs-contributing].
[docs-contributing]: ./contributing/issues-and-pull-requests/
[docs-contributing]: ./contributing/issues-and-pull-requests.md

View File

@ -43,10 +43,10 @@ Here's where DMS's toolchain fits within the delivery chain:
```txt
docker-mailserver is here:
┏━━━━━━━┓
Sending an email: MUA ---> MTA ---> (MTA relays) ---> ┫ MTA ╮ ┃
Fetching an email: MUA <------------------------------ MDA
┗━━━━━━━┛
┏━━━━━━━┓
Sending an email: MUA ---> MTA ---> (MTA relays) ---> ┫ MTA ╮ ┃
Fetching an email: MUA <------------------------------ MDA
┗━━━━━━━┛
```
??? example "An Example"
@ -86,18 +86,18 @@ When it comes to the specifics of email exchange, we have to look at protocols a
The following picture gives a visualization of the interplay of all components and their [respective ports][docs-understandports]:
```txt
┏━━━━━━━━━━ Submission ━━━━━━━━━━━━┓┏━━━━━━━━━━━━━ Transfer/Relay ━━━━━━━━━━━┓
┏━━━━━━━━━━ Submission ━━━━━━━━━━━━┓┏━━━━━━━━━━━━━ Transfer/Relay ━━━━━━━━━━━┓
┌─────────────────────┐ ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
MUA ----- STARTTLS ------> ┤(587) MTA ╮ (25)├ <-- cleartext ---> ┊ Third-party MTA ┊
----- implicit TLS --> ┤(465) │ | └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘
----- cleartext -----> ┤(25) │ |
|┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄|
MUA <---- STARTTLS ------- (143) MDA |
<---- implicit TLS --- (993) |
└─────────────────────┘
┌─────────────────────┐ ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
MUA ----- STARTTLS -------> ┤(587) MTA ╮ (25)├ <-- cleartext ---> ┊ Third-party MTA ┊
----- implicit TLS ---> ┤(465) │ | └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘
----- cleartext ------> ┤(25) │ |
|┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄|
MUA <---- STARTTLS -------- (143) MDA |
<---- implicit TLS ---- (993) |
└─────────────────────┘
┗━━━━━━━━━━ Retrieval ━━━━━━━━━━━━━┛
┗━━━━━━━━━━ Retrieval ━━━━━━━━━━━━━┛
```
If you're new to email infrastructure, both that table and the schema may be confusing.
@ -124,7 +124,7 @@ My MTA will thus have to support two kinds of Submission:
- Inbound Submission (third-party email has been submitted & relayed, then is accepted "inside" by the MTA)
```txt
━━━ Outbound Submission ━━━┓
┏━━━ Outbound Submission ━━━┓
┌────────────────────┐ ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
Me ---------------> ┤ ├ -----------------> ┊ ┊
@ -132,7 +132,7 @@ Me ---------------> ┤ ├ -----------------> ┊
│ ├ <-----------------
└────────────────────┘ └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘
┗━━━━━━━━━━ Inbound Submission ━━━━━━━━━━┛
┗━━━━━━━━━━ Inbound Submission ━━━━━━━━━━┛
```
#### Outbound Submission
@ -168,7 +168,7 @@ Granted it's still very difficult enforcing encryption between MTAs (Transfer/Re
Overall, DMS's default configuration for SMTP looks like this:
```txt
━━━ Outbound Submission ━━━┓
┏━━━ Outbound Submission ━━━┓
┌────────────────────┐ ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
Me -- cleartext --> ┤(25) (25)├ --- cleartext ---> ┊ ┊
@ -177,7 +177,7 @@ Me -- STARTTLS ---> ┤(587) │ ┊
│ (25)├ <---cleartext ----
└────────────────────┘ └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘
┗━━━━━━━━━━ Inbound Submission ━━━━━━━━━━┛
┗━━━━━━━━━━ Inbound Submission ━━━━━━━━━━┛
```
### Retrieval - IMAP

View File

@ -1,6 +1,6 @@
# Site specific:
site_name: 'Docker Mailserver'
site_description: 'A fullstack but simple mail-server (SMTP, IMAP, LDAP, Antispam, Antivirus, etc.) using Docker.'
site_description: 'A fullstack but simple mail-server (SMTP, IMAP, LDAP, Anti-spam, Anti-virus, etc.) using Docker.'
site_author: 'docker-mailserver (Github Organization)'
copyright: '<p>&copy <a href="https://github.com/docker-mailserver"><em>Docker Mailserver Organization</em></a><br/><span>This project is licensed under the MIT license.</span></p>'
@ -86,8 +86,8 @@ markdown_extensions:
- pymdownx.inlinehilite
- pymdownx.tilde
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg
- pymdownx.highlight:
extend_pygments_lang:
- name: yml
@ -122,8 +122,9 @@ nav:
- 'Environment Variables': config/environment.md
- 'User Management': config/user-management.md
- 'Best Practices':
- 'DKIM, DMARC & SPF': config/best-practices/dkim_dmarc_spf.md
- 'Auto-discovery': config/best-practices/autodiscover.md
- 'DKIM, DMARC & SPF': config/best-practices/dkim_dmarc_spf.md
- 'MTA-STS': config/best-practices/mta-sts.md
- 'Security':
- 'Understanding the Ports': config/security/understanding-the-ports.md
- 'SSL/TLS': config/security/ssl.md
@ -142,6 +143,7 @@ nav:
- 'Postfix': config/advanced/override-defaults/postfix.md
- 'Modifications via Script': config/advanced/override-defaults/user-patches.md
- 'LDAP Authentication': config/advanced/auth-ldap.md
- 'OAuth2 Authentication': config/advanced/auth-oauth2.md
- 'Email Filtering with Sieve': config/advanced/mail-sieve.md
- 'Email Gathering with Fetchmail': config/advanced/mail-fetchmail.md
- 'Email Gathering with Getmail': config/advanced/mail-getmail.md
@ -159,11 +161,14 @@ nav:
- 'Tutorials':
- 'Basic Installation': examples/tutorials/basic-installation.md
- 'Mailserver behind Proxy': examples/tutorials/mailserver-behind-proxy.md
- 'Crowdsec': examples/tutorials/crowdsec.md
- 'Building your own Docker image': examples/tutorials/docker-build.md
- 'Blog Posts': examples/tutorials/blog-posts.md
- 'Use Cases':
- 'Forward-Only Mail-Server with LDAP': examples/use-cases/forward-only-mailserver-with-ldap-authentication.md
- 'Customize IMAP Folders': examples/use-cases/imap-folders.md
- 'iOS Mail Push Support': examples/use-cases/ios-mail-push-support.md
- 'Lua Authentication': examples/use-cases/auth-lua.md
- 'FAQ' : faq.md
- 'Contributing':
- 'General Information': contributing/general.md

View File

@ -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)
@ -113,10 +119,16 @@ ENABLE_OPENDMARC=1
# - **1** => Enabled
ENABLE_POLICYD_SPF=1
# 1 => Enables POP3 service
# empty => disables POP3
# Enables POP3 service
# - **0** => Disabled
# - 1 => Enabled
ENABLE_POP3=
# Enables IMAP service
# - 0 => Disabled
# - **1** => Enabled
ENABLE_IMAP=1
# Enables ClamAV, and anti-virus scanner.
# 1 => Enabled
# **0** => Disabled
@ -142,6 +154,15 @@ ENABLE_RSPAMD_REDIS=
# 1 => enabled
RSPAMD_LEARN=0
# This settings controls whether checks should be performed on emails coming
# from authenticated users (i.e. most likely outgoing emails). The default value
# is `0` in order to align better with SpamAssassin. We recommend reading
# through https://rspamd.com/doc/tutorials/scanning_outbound.html though to
# decide for yourself whether you need and want this feature.
#
# Note that DKIM signing of e-mails will still happen.
RSPAMD_CHECK_AUTHENTICATED=0
# Controls whether the Rspamd Greylisting module is enabled.
# This module can further assist in avoiding spam emails by greylisting
# e-mails with a certain spam score.
@ -233,7 +254,7 @@ VIRUSMAILS_DELETE_DELAY=
# `lmtp:<kopano-host>:2003` (use kopano as mailstore)
POSTFIX_DAGENT=
# Set the mailbox size limit for all users. If set to zero, the size will be unlimited (default).
# Set the mailbox size limit for all users. If set to zero, the size will be unlimited (default). Size is in bytes.
#
# empty => 0
POSTFIX_MAILBOX_SIZE_LIMIT=
@ -243,7 +264,7 @@ POSTFIX_MAILBOX_SIZE_LIMIT=
# 1 => Dovecot quota is enabled
ENABLE_QUOTAS=1
# Set the message size limit for all users. If set to zero, the size will be unlimited (not recommended!)
# Set the message size limit for all users. If set to zero, the size will be unlimited (not recommended!). Size is in bytes.
#
# empty => 10240000 (~10 MB)
POSTFIX_MESSAGE_SIZE_LIMIT=
@ -333,6 +354,12 @@ POSTFIX_REJECT_UNKNOWN_CLIENT_HOSTNAME=0
# Note: More details at http://www.postfix.org/postconf.5.html#inet_protocols
POSTFIX_INET_PROTOCOLS=all
# Enables MTA-STS support for outbound mail.
# More details: https://docker-mailserver.github.io/docker-mailserver/latest/config/advanced/mail-mta-sts/
# - **0** ==> MTA-STS disabled
# - 1 => MTA-STS enabled
ENABLE_MTA_STS=0
# Choose TCP/IP protocols for dovecot to use
# **all** => Listen on all interfaces
# ipv4 => Listen only on IPv4 interfaces. Most likely you want this behind Docker.
@ -347,9 +374,6 @@ DOVECOT_INET_PROTOCOLS=all
ENABLE_SPAMASSASSIN=0
# deliver spam messages in the inbox (eventually tagged using SA_SPAM_SUBJECT)
SPAMASSASSIN_SPAM_TO_INBOX=1
# KAM is a 3rd party SpamAssassin ruleset, provided by the McGrail Foundation.
# If SpamAssassin is enabled, KAM can be used in addition to the default ruleset.
# - **0** => KAM disabled
@ -358,20 +382,29 @@ SPAMASSASSIN_SPAM_TO_INBOX=1
# Note: only has an effect if `ENABLE_SPAMASSASSIN=1`
ENABLE_SPAMASSASSIN_KAM=0
# deliver spam messages to the inbox (tagged using SA_SPAM_SUBJECT)
SPAMASSASSIN_SPAM_TO_INBOX=1
# spam messages will be moved in the Junk folder (SPAMASSASSIN_SPAM_TO_INBOX=1 required)
MOVE_SPAM_TO_JUNK=1
# add spam info headers if at, or above that level:
# spam messages wil be marked as read
MARK_SPAM_AS_READ=0
# add 'spam info' headers at, or above this level
SA_TAG=2.0
# add 'spam detected' headers at that level
# add 'spam detected' headers at, or above this level
SA_TAG2=6.31
# triggers spam evasive actions
SA_KILL=10.0
# add tag to subject if spam detected
SA_SPAM_SUBJECT=***SPAM*****
# The value `undef` opts-out of this feature. The value shown below is the default.
# NOTE: By default spam is delivered to a junk folder, reducing the value of adding a subject prefix.
# NOTE: If not using Docker Compose, other CRI may require the single quotes removed.
#SA_SPAM_SUBJECT='***SPAM*** '
# -----------------------------------------------
# --- Fetchmail Section -------------------------
@ -381,6 +414,10 @@ ENABLE_FETCHMAIL=0
# The interval to fetch mail in seconds
FETCHMAIL_POLL=300
# Use multiple fetchmail instances (1 per poll entry in fetchmail.cf)
# Supports multiple IMAP IDLE connections when a server is used across multiple poll entries
# https://otremba.net/wiki/Fetchmail_(Debian)#Immediate_Download_via_IMAP_IDLE
FETCHMAIL_PARALLEL=0
# Enable or disable `getmail`.
#
@ -391,24 +428,31 @@ ENABLE_GETMAIL=0
# The number of minutes for the interval. Min: 1; Max: 30.
GETMAIL_POLL=5
# -----------------------------------------------
# --- OAUTH2 Section ----------------------------
# -----------------------------------------------
# empty => OAUTH2 authentication is disabled
# 1 => OAUTH2 authentication is enabled
ENABLE_OAUTH2=
# Specify the user info endpoint URL of the oauth2 provider
# Example: https://oauth2.example.com/userinfo/
OAUTH2_INTROSPECTION_URL=
# -----------------------------------------------
# --- LDAP Section ------------------------------
# -----------------------------------------------
# A second container for the ldap service is necessary (i.e. https://github.com/osixia/docker-openldap)
# with the :edge tag, use ACCOUNT_PROVISIONER=LDAP
# empty => LDAP authentication is disabled
# 1 => LDAP authentication is enabled
ENABLE_LDAP=
# A second container for the ldap service is necessary (i.e. https://hub.docker.com/r/bitnami/openldap/)
# empty => no
# yes => LDAP over TLS enabled for Postfix
LDAP_START_TLS=
# If you going to use the mailserver in combination with Docker Compose you can set the service name here
# empty => mail.domain.com
# Specify the dns-name/ip-address where the ldap-server
# empty => mail.example.com
# Specify the `<dns-name>` / `<ip-address>` where the LDAP server is reachable via a URI like: `ldaps://mail.example.com`.
# Note: You must include the desired URI scheme (`ldap://`, `ldaps://`, `ldapi://`).
LDAP_SERVER_HOST=
# empty => ou=people,dc=domain,dc=com
@ -495,7 +539,7 @@ SASLAUTHD_MECHANISMS=
SASLAUTHD_MECH_OPTIONS=
# empty => Use value of LDAP_SERVER_HOST
# Note: since version 10.0.0, you can specify a protocol here (like ldaps://); this deprecates SASLAUTHD_LDAP_SSL.
# Note: You must include the desired URI scheme (`ldap://`, `ldaps://`, `ldapi://`).
SASLAUTHD_LDAP_SERVER=
# empty => Use value of LDAP_BIND_DN

View File

@ -1,7 +1,7 @@
use strict;
@local_domains_maps = (
read_hash('/etc/postfix/vhost')
read_hash('/etc/postfix/vhost')
);
1; # ensure a defined return

View File

@ -33,6 +33,9 @@ ${ORANGE}EXAMPLES${RESET}
${LWHITE}./setup.sh alias add alias@example.com recipient@example.com${RESET}
Add the alias 'alias@example.com' for the mail account 'recipient@example.com'.
${LWHITE}./setup.sh alias add alias@example.com 'recipient@example.com, another-recipient@example.com'${RESET}
Multiple recipients are separated by comma.
${ORANGE}EXIT STATUS${RESET}
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 1.

View File

@ -4,11 +4,15 @@
source /usr/local/bin/helpers/index.sh
if [[ -f /etc/dms-settings ]] && [[ $(_get_dms_env_value 'ENABLE_RSPAMD') -eq 1 ]]; then
/usr/local/bin/rspamd-dkim "${@}"
exit
if [[ $(_get_dms_env_value 'ENABLE_OPENDKIM') -eq 1 ]]; then
log 'error' "You enabled Rspamd and OpenDKIM - OpenDKIM will be implicitly used for DKIM keys"
else
/usr/local/bin/rspamd-dkim "${@}"
exit
fi
fi
KEYSIZE=4096
KEYSIZE=2048
SELECTOR=mail
DOMAINS=
@ -16,37 +20,40 @@ function __usage() {
printf '%s' "${PURPLE}OPEN-DKIM${RED}(${YELLOW}8${RED})
${ORANGE}NAME${RESET}
open-dkim - configure DomainKeys Identified Mail (DKIM)
open-dkim - Configure DKIM (DomainKeys Identified Mail)
${ORANGE}SYNOPSIS${RESET}
./setup.sh config dkim [ OPTIONS${RED}...${RESET} ]
setup config dkim [ OPTIONS${RED}...${RESET} ]
${ORANGE}DESCRIPTION${RESET}
Configures DKIM keys. OPTIONS can be used to configure a more complex setup.
LDAP setups require these options.
Creates DKIM keys and configures them within DMS for OpenDKIM.
OPTIONS can be used when your requirements are not met by the defaults.
When not using 'ACCOUNT_PROVISIONER=FILE' (default), you may need to explicitly
use the 'domain' option to generate DKIM keys for your mail account domains.
${ORANGE}OPTIONS${RESET}
${BLUE}Generic Program Information${RESET}
help Print the usage information.
help Print the usage information.
${BLUE}Configuration adjustments${RESET}
keysize Set the size of the keys to be generated. Possible are 1024, 2048 and 4096 (default).
selector Set a manual selector (default is 'mail') for the key. (${LCYAN}ATTENTION${RESET}: NOT IMPLEMENTED YET!)
domain Provide the domain(s) for which keys are to be generated.
keysize Set the size of the keys to be generated.
Possible values: 1024, 2048 and 4096
Default: 2048
selector Set a manual selector for the key.
Default: mail
domain Provide the domain(s) for which to generate keys for.
Default: The FQDN assigned to DMS, excluding any subdomain.
'ACCOUNT_PROVISIONER=FILE' also sources domains from mail accounts.
${ORANGE}EXAMPLES${RESET}
${LWHITE}./setup.sh config dkim keysize 2048${RESET}
Creates keys of length 2048 bit in a default setup where domains are obtained from
your accounts.
${LWHITE}setup config dkim keysize 4096${RESET}
Creates keys with their length increased to a size of 4096-bit.
${LWHITE}./setup.sh config dkim keysize 2048 selector 2021-dkim${RESET}
Creates keys of length 2048 bit in a default setup where domains are obtained from
your accounts. The DKIM selector used is '2021-dkim'.
${LWHITE}setup config dkim keysize 1024 selector 2023-dkim${RESET}
Creates 1024-bit sized keys, and changes the DKIM selector to '2023-dkim'.
${LWHITE}./setup.sh config dkim keysize 2048 selector 2021-dkim domain 'whoami.com,whoareyou.org'${RESET}
Appropriate for an LDAP setup. Creates keys of length 2048 bit in a default setup
where domains are obtained from your accounts. The DKIM selector used is '2021-dkim'.
The domains for which DKIM keys are generated are 'whoami.com' and 'whoareyou.org'.
${LWHITE}setup config dkim domain 'example.com,another-example.com'${RESET}
Only generates DKIM keys for the specified domains: 'example.com' and 'another-example.com'.
${ORANGE}EXIT STATUS${RESET}
Exit status is 0 if command was successful. If wrong arguments are provided or arguments contain
@ -137,6 +144,9 @@ while read -r DKIM_DOMAIN; do
--directory="/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}"
fi
# fix permissions to use the same user:group as /tmp/docker-mailserver/opendkim/keys
chown -R "$(stat -c '%U:%G' /tmp/docker-mailserver/opendkim/keys)" "/tmp/docker-mailserver/opendkim/keys/${DKIM_DOMAIN}"
# write to KeyTable if necessary
KEYTABLEENTRY="${SELECTOR}._domainkey.${DKIM_DOMAIN} ${DKIM_DOMAIN}:${SELECTOR}:/etc/opendkim/keys/${DKIM_DOMAIN}/${SELECTOR}.private"
if [[ ! -f "/tmp/docker-mailserver/opendkim/KeyTable" ]]; then

View File

@ -16,46 +16,44 @@ function __usage() {
echo -e "${PURPLE}RSPAMD-DKIM${RED}(${YELLOW}8${RED})
${ORANGE}NAME${RESET}
rspamd-dkim - Configure DomainKeys Identified Mail (DKIM) via Rspamd
rspamd-dkim - Configure DKIM (DomainKeys Identified Mail)
${ORANGE}SYNOPSIS${RESET}
setup config dkim [ OPTIONS${RED}...${RESET} ]
${ORANGE}DESCRIPTION${RESET}
This script aids in creating DKIM signing keys. The keys are created and managed by Rspamd.
OPTIONS can be used to configure a more complex setup.
Creates DKIM keys and configures them within DMS for Rspamd.
OPTIONS can be used when your requirements are not met by the defaults.
${ORANGE}OPTIONS${RESET}
${BLUE}Generic Program Information${RESET}
-v Enable verbose logging (setting the log level to 'debug').
-vv Enable very verbose logging (setting the log level to 'trace').
help Print the usage information.
-f | --force Overwrite existing files if there are any
-v Enable verbose logging (setting the log level to 'debug').
-vv Enable very verbose logging (setting the log level to 'trace').
help Print the usage information.
${BLUE}Configuration adjustments${RESET}
keytype Set the type of key you want to use
keytype Set the type of key you want to use.
Possible values: rsa, ed25519
Default: rsa
keysize Set the size of the keys to be generated
keysize Set the size of the keys to be generated.
Possible values: 1024, 2048 and 4096
Default: 2048
Only applies when using keytype=rsa
selector Set a manual selector for the key
selector Set a manual selector for the key.
Default: mail
domain Provide the domain for which keys are to be generated
Default: primary domain name of DMS
domain Provide the domain for which to generate keys for.
Default: The FQDN assigned to DMS, excluding any subdomain.
${ORANGE}EXAMPLES${RESET}
${LWHITE}setup config dkim keysize 2048${RESET}
Creates keys of length 2048 bit in a default setup where domains are obtained from
your accounts.
${LWHITE}setup config dkim keysize 4096${RESET}
Creates keys with their length increased to a size of 4096-bit.
${LWHITE}setup config dkim keysize 512 selector 2023-dkim${RESET}
Creates keys of length 512 bit in a default setup where domains are obtained from
your accounts. The DKIM selector used is '2023-dkim'.
${LWHITE}setup config dkim keysize 1024 selector 2023-dkim${RESET}
Creates 1024-bit sized keys, and changes the DKIM selector to '2023-dkim'.
${LWHITE}setup config dkim keysize 1024 selector 2023-dkim domain whoami.com${RESET}
Creates keys of length 1024 bit in a default setup where domains are obtained from your accounts.
The DKIM selector used is '2023-dkim'. The domain for which DKIM keys are generated is whoami.com.
${LWHITE}setup config dkim domain example.com${RESET}
Generate the DKIM key for a different domain (example.com).
${ORANGE}EXIT STATUS${RESET}
Exit status is 0 if command was successful. If wrong arguments are provided or arguments contain
@ -64,14 +62,8 @@ ${ORANGE}EXIT STATUS${RESET}
"
}
function __do_as_rspamd_user() {
local COMMAND=${1:?Command required when using __do_as_rspamd_user}
_log 'trace' "Running '${*}' as user '_rspamd' now"
shift 1
su -l '_rspamd' -s "$(command -v "${COMMAND}")" -- "${@}"
}
function _parse_arguments() {
FORCE=0
KEYTYPE='rsa'
KEYSIZE='2048'
SELECTOR='mail'
@ -115,6 +107,12 @@ function _parse_arguments() {
exit 0
;;
( '-f' | '--force' )
FORCE=1
shift 1
continue
;;
( '-vv' )
# shellcheck disable=SC2034
LOG_LEVEL='trace'
@ -135,30 +133,36 @@ function _parse_arguments() {
__usage
_exit_with_error "Unknown option(s) '${1}' ${2:+"and '${2}'"}"
;;
esac
shift 2
done
return 0
}
function _preflight_checks() {
if [[ ${KEYTYPE} == 'ed25519' ]] && [[ ${KEYSIZE} -ne 2048 ]]; then
_exit_with_error "Chosen keytype does not accept the 'keysize' argument"
fi
return 0
if [[ ! -d /tmp/docker-mailserver ]]; then
_log 'warn' "The directory '/tmp/docker-mailserver' does not seem to be mounted by a volume - the Rspamd (DKIM) configuration will not be persisted"
fi
_rspamd_get_envs
mkdir -p "${RSPAMD_DMS_DKIM_D}" "${RSPAMD_DMS_OVERRIDE_D}"
chown _rspamd:_rspamd "${RSPAMD_DMS_DKIM_D}"
}
function _create_keys() {
# Note: Variables not marked with `local` are used
# in other functions (after this function was called).
BASE_DIR='/tmp/docker-mailserver/rspamd/dkim'
if [[ ${KEYTYPE} == 'rsa' ]]; then
local BASE_FILE_NAME="${BASE_DIR}/${KEYTYPE}-${KEYSIZE}-${SELECTOR}-${DOMAIN}"
local BASE_FILE_NAME="${RSPAMD_DMS_DKIM_D}/${KEYTYPE}-${KEYSIZE}-${SELECTOR}-${DOMAIN}"
KEYTYPE_OPTIONS=('-b' "${KEYSIZE}")
_log 'info' "Creating DKIM keys of type '${KEYTYPE}' and length '${KEYSIZE}' with selector '${SELECTOR}' for domain '${DOMAIN}'"
else
local BASE_FILE_NAME="${BASE_DIR}/${KEYTYPE}-${SELECTOR}-${DOMAIN}"
local BASE_FILE_NAME="${RSPAMD_DMS_DKIM_D}/${KEYTYPE}-${SELECTOR}-${DOMAIN}"
KEYTYPE_OPTIONS=('-t' "${KEYTYPE}")
_log 'info' "Creating DKIM keys of type '${KEYTYPE}' with selector '${SELECTOR}' for domain '${DOMAIN}'"
fi
@ -167,8 +171,15 @@ function _create_keys() {
PUBLIC_KEY_DNS_FILE="${BASE_FILE_NAME}.public.dns.txt"
PRIVATE_KEY_FILE="${BASE_FILE_NAME}.private.txt"
mkdir -p "${BASE_DIR}"
chown _rspamd:_rspamd "${BASE_DIR}"
if [[ -f ${PUBLIC_KEY_FILE} ]] || [[ -f ${PUBLIC_KEY_DNS_FILE} ]] || [[ -f ${PRIVATE_KEY_FILE} ]]; then
if [[ ${FORCE} -eq 0 ]]; then
_log 'error' "Not overwriting existing files (use '--force' to overwrite existing files)"
exit 1
else
_log 'info' "Overwriting existing files as the '--force' option was supplied"
rm "${PUBLIC_KEY_FILE}" "${PUBLIC_KEY_DNS_FILE}" "${PRIVATE_KEY_FILE}"
fi
fi
# shellcheck disable=SC2310
if __do_as_rspamd_user rspamadm \
@ -189,8 +200,8 @@ function _create_keys() {
function _check_permissions() {
# shellcheck disable=SC2310
if ! __do_as_rspamd_user ls "${BASE_DIR}" >/dev/null; then
_log 'warn' "The Rspamd user ('_rspamd') seems to be unable to list files in the keys directory ('${BASE_DIR}') - Rspamd may experience permission errors later"
if ! __do_as_rspamd_user ls "${RSPAMD_DMS_DKIM_D}" >/dev/null; then
_log 'warn' "The Rspamd user ('_rspamd') seems to be unable to list files in the keys directory ('${RSPAMD_DMS_DKIM_D}') - Rspamd may experience permission errors later"
elif ! __do_as_rspamd_user cat "${PRIVATE_KEY_FILE}" >/dev/null; then
_log 'warn' "The Rspamd user ('_rspamd') seems to be unable to read the private key file - Rspamd may experience permission errors later"
else
@ -199,11 +210,11 @@ function _check_permissions() {
}
function _setup_default_signing_conf() {
local DEFAULT_CONFIG_FILE='/etc/rspamd/override.d/dkim_signing.conf'
local DEFAULT_CONFIG_FILE="${RSPAMD_DMS_OVERRIDE_D}/dkim_signing.conf"
if [[ -f ${DEFAULT_CONFIG_FILE} ]]; then
_log 'debug' "'${DEFAULT_CONFIG_FILE}' exists, not supplying a default"
_log 'info' "'${DEFAULT_CONFIG_FILE}' exists, not supplying a default ('--force' does not overwrite this file, manual adjustment required)"
else
_log 'info' "Supplying a default configuration ('${DEFAULT_CONFIG_FILE}')"
_log 'info' "Supplying a default configuration (to '${DEFAULT_CONFIG_FILE}')"
cat >"${DEFAULT_CONFIG_FILE}" << EOF
# documentation: https://rspamd.com/doc/modules/dkim_signing.html
@ -228,7 +239,15 @@ domain {
}
EOF
chown _rspamd:_rspamd "${DEFAULT_CONFIG_FILE}"
# We copy here immediately in order to not rely on the changedetector - this way, users
# can immediately use the new keys. The file should not already exist in ${RSPAMD_OVERRIDE_D}
# since it would have been copied already.
cp "${DEFAULT_CONFIG_FILE}" "${RSPAMD_OVERRIDE_D}/dkim_signing.conf"
chown _rspamd:_rspamd "${DEFAULT_CONFIG_FILE}" "${RSPAMD_OVERRIDE_D}/dkim_signing.conf"
_log 'debug' 'Restarting Rspamd as initial DKIM configuration was suppplied'
supervisorctl restart rspamd
fi
}
@ -257,6 +276,7 @@ function _final_steps() {
_obtain_hostname_and_domainname
_require_n_parameters_or_print_usage 0 "${@}"
_parse_arguments "${@}"
_preflight_checks
_create_keys
_check_permissions
_setup_default_signing_conf

View File

@ -59,10 +59,14 @@ function _quota_request_if_missing() {
fi
}
# Dovecot docs incorrectly refer to these units with names for SI types (base 10),
# But then mentions they're actually treated as IEC type (base 2):
# https://doc.dovecot.org/settings/types/#size
function _quota_unit_is_valid() {
if ! grep -qE "^([0-9]+(B|k|M|G|T)|0)\$" <<< "${QUOTA}"; then
__usage
_exit_with_error 'Invalid quota format. e.g. 302M (B (byte), k (kilobyte), M (megabyte), G (gigabyte) or T (terabyte))'
_exit_with_error 'Invalid quota format. e.g. 302M (B (byte), k (kibibyte), M (mebibyte), G (gibibyte) or T (tebibyte))'
fi
}

View File

@ -123,6 +123,7 @@ auth_mechanisms = plain login
#!include auth-sql.conf.ext
#!include auth-ldap.conf.ext
!include auth-passwdfile.inc
#!include auth-oauth2.conf.ext
#!include auth-checkpassword.conf.ext
#!include auth-vpopmail.conf.ext
#!include auth-static.conf.ext

View File

@ -0,0 +1,7 @@
auth_mechanisms = $auth_mechanisms oauthbearer xoauth2
passdb {
driver = oauth2
mechanisms = xoauth2 oauthbearer
args = /etc/dovecot/dovecot-oauth2.conf.ext
}

View File

@ -1,8 +1,8 @@
base = ou=people,dc=domain,dc=com
base = ou=people,dc=example,dc=com
default_pass_scheme = SSHA
dn = cn=admin,dc=domain,dc=com
dn = cn=admin,dc=example,dc=com
dnpass = admin
uris = ldap://mail.domain.com
uris = ldap://mail.example.com
tls = no
ldap_version = 3
pass_attrs = uniqueIdentifier=user,userPassword=password

View File

@ -0,0 +1,4 @@
introspection_url =
# Dovecot defaults:
introspection_mode = auth
username_attribute = email

View File

@ -0,0 +1,7 @@
# Docs: https://github.com/Snawoot/postfix-mta-sts-resolver/blob/master/man/mta-sts-daemon.yml.5.adoc
path: /var/run/mta-sts/daemon.sock
mode: 0666
cache:
type: sqlite
options:
filename: "/var/lib/mta-sts/cache.db"

View File

@ -1,9 +1,9 @@
bind = yes
bind_dn = cn=admin,dc=domain,dc=com
bind_dn = cn=admin,dc=example,dc=com
bind_pw = admin
query_filter = (&(mailAlias=%s)(mailEnabled=TRUE))
result_attribute = mail
search_base = ou=people,dc=domain,dc=com
server_host = mail.domain.com
search_base = ou=people,dc=example,dc=com
server_host = mail.example.com
start_tls = no
version = 3

View File

@ -1,9 +1,9 @@
bind = yes
bind_dn = cn=admin,dc=domain,dc=com
bind_dn = cn=admin,dc=example,dc=com
bind_pw = admin
query_filter = (&(|(mail=*@%s)(mailalias=*@%s))(mailEnabled=TRUE))
result_attribute = mail
search_base = ou=people,dc=domain,dc=com
server_host = mail.domain.com
search_base = ou=people,dc=example,dc=com
server_host = mail.example.com
start_tls = no
version = 3

View File

@ -1,9 +1,9 @@
bind = yes
bind_dn = cn=admin,dc=domain,dc=com
bind_dn = cn=admin,dc=example,dc=com
bind_pw = admin
query_filter = (&(mailGroupMember=%s)(mailEnabled=TRUE))
result_attribute = mail
search_base = ou=people,dc=domain,dc=com
server_host = mail.domain.com
search_base = ou=people,dc=example,dc=com
server_host = mail.example.com
start_tls = no
version = 3

View File

@ -1,9 +1,9 @@
bind = yes
bind_dn = cn=admin,dc=domain,dc=com
bind_dn = cn=admin,dc=example,dc=com
bind_pw = admin
query_filter = (mail=%s)
result_attribute = mail, uid
search_base = ou=people,dc=domain,dc=com
server_host = mail.domain.com
search_base = ou=people,dc=example,dc=com
server_host = mail.example.com
start_tls = no
version = 3

View File

@ -1,9 +1,9 @@
bind = yes
bind_dn = cn=admin,dc=domain,dc=com
bind_dn = cn=admin,dc=example,dc=com
bind_pw = admin
query_filter = (&(mail=%s)(mailEnabled=TRUE))
result_attribute = mail
search_base = ou=people,dc=domain,dc=com
server_host = mail.domain.com
search_base = ou=people,dc=example,dc=com
server_host = mail.example.com
start_tls = no
version = 3

View File

@ -5,6 +5,9 @@ biff = no
append_dot_mydomain = no
readme_directory = no
# Disabled as not compatible with Dovecot
smtputf8_enable = no
# Basic configuration
# myhostname =
alias_maps = hash:/etc/aliases
@ -51,11 +54,19 @@ smtpd_helo_required = yes
smtpd_delay_reject = yes
smtpd_helo_restrictions = permit_mynetworks, reject_invalid_helo_hostname, permit
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, reject_unauth_pipelining, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, reject_unknown_recipient_domain
smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, reject_unauth_pipelining
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, reject_unknown_recipient_domain
smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_sender_restrictions = $dms_smtpd_sender_restrictions
smtpd_discard_ehlo_keywords = silent-discard, dsn
smtpd_data_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_pipelining
disable_vrfy_command = yes
# Security - Prevent SMTP Smuggling attack
# https://www.postfix.org/smtp-smuggling.html#long
smtpd_forbid_bare_newline = yes
# It is possible to exclude clients on trusted networks from this restriction (the upstream default is `$mynetwork`):
# smtpd_forbid_bare_newline_exclusions = $mynetworks
# Custom defined parameters for DMS:
dms_smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unknown_sender_domain
# Submission ports 587 and 465 support for SPOOF_PROTECTION=1
@ -87,10 +98,10 @@ smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $mydomain
broken_sasl_auth_clients = yes
# Mail directory
virtual_transport = lmtp:unix:/var/run/dovecot/lmtp
# Postfix lookup tables for verifying valid users and managed mail domains:
# Populated during startup in: scripts/helpers/postfix.sh
virtual_mailbox_domains = /etc/postfix/vhost
virtual_mailbox_maps = texthash:/etc/postfix/vmailbox
# Populated during startup in: scripts/helpers/aliases.sh
virtual_alias_maps = texthash:/etc/postfix/virtual
# Milters used by DKIM

View File

@ -24,6 +24,7 @@ submission inet n - n - - smtpd
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o smtpd_sender_restrictions=$mua_sender_restrictions
-o smtpd_discard_ehlo_keywords=
-o milter_macro_daemon_name=ORIGINATING
-o cleanup_service_name=sender-cleanup
@ -37,6 +38,7 @@ submissions inet n - n - - smtpd
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o smtpd_sender_restrictions=$mua_sender_restrictions
-o smtpd_discard_ehlo_keywords=
-o milter_macro_daemon_name=ORIGINATING
-o cleanup_service_name=sender-cleanup

View File

@ -1,154 +0,0 @@
#! /bin/sh
# postgrey start/stop the postgrey greylisting deamon for postfix
# (priority should be smaller than that of postfix)
#
# Author: (c)2004-2006 Adrian von Bidder <avbidder@fortytwo.ch>
# Based on Debian sarge's 'skeleton' example
# Distribute and/or modify at will.
#
# Version: $Id: postgrey.init 1436 2006-12-07 07:15:03Z avbidder $
# altered by Georg Lauterbach as aendeavor 2020-11.05 14:02:00Z
### BEGIN INIT INFO
# Provides: postgrey
# Required-Start: $syslog $local_fs $remote_fs
# Required-Stop: $syslog $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start/stop the postgrey daemon
### END INIT INFO
set -e
PATH='/sbin:/bin:/usr/sbin:/usr/bin'
DAEMON='/usr/sbin/postgrey'
DAEMON_NAME='postgrey'
DESC='postfix greylisting daemon'
DAEMON_USER='postgrey'
PIDFILE="/var/run/${DAEMON_NAME}/${DAEMON_NAME}.pid"
SCRIPTNAME="/etc/init.d/${DAEMON_NAME}"
# gracefully exit if the package has been removed.
[ -x "${DAEMON}" ] || exit 0
# shellcheck source=/dev/null
. /lib/lsb/init-functions
# Read config file if it is present.
# shellcheck source=/dev/null
[ -r "/etc/default/${DAEMON_NAME}" ] && . "/etc/default/${DAEMON_NAME}"
POSTGREY_OPTS="--pidfile=${PIDFILE} --daemonize ${POSTGREY_OPTS}"
if [ -z "${POSTGREY_TEXT}" ]; then
POSTGREY_TEXT_OPT=""
else
POSTGREY_TEXT_OPT="--greylist-text=${POSTGREY_TEXT}"
fi
ret=0
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile \
"${PIDFILE}" --exec "${DAEMON}" --test >/dev/null || return 1
start-stop-daemon --start --quiet --pidfile \
"${PIDFILE}" --exec "${DAEMON}" -- "${POSTGREY_OPTS}" \
"${POSTGREY_TEXT_OPT}" || return 2
}
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --user "${DAEMON_USER}" --stop --quiet \
--retry=TERM/30/KILL/5 --pidfile "${PIDFILE}"
RETVAL="$?"
[ "${RETVAL}" -eq 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --user "${DAEMON_USER}" --stop --quiet \
--oknodo --retry=0/30/KILL/5 --exec "${DAEMON}"
[ "$?" -eq 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f "${PIDFILE}"
return "${RETVAL}"
}
do_reload()
{
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile "${PIDFILE}"
return 0
}
case "${1}" in
start )
[ "${VERBOSE}" != no ] && log_daemon_msg "Starting ${DESC}" "${DAEMON_NAME}"
do_start
case "${?}" in
0|1) [ "${VERBOSE}" != no ] && log_end_msg 0 ;;
2) [ "${VERBOSE}" != no ] && log_end_msg 1 ;;
esac
;;
stop )
[ "${VERBOSE}" != no ] && log_daemon_msg "Stopping ${DESC}" "${DAEMON_NAME}"
do_stop
case "${?}" in
0|1) [ "${VERBOSE}" != no ] && log_end_msg 0 ;;
2) [ "${VERBOSE}" != no ] && log_end_msg 1 ;;
esac
;;
reload|force-reload)
[ "${VERBOSE}" != no ] && log_daemon_msg "Reloading ${DESC}" "${DAEMON_NAME}"
do_reload
case "${?}" in
0|1) [ "${VERBOSE}" != no ] && log_end_msg 0 ;;
2) [ "${VERBOSE}" != no ] && log_end_msg 1 ;;
esac
;;
restart )
do_stop
do_start
;;
status )
status_of_proc -p "${PIDFILE}" "${DAEMON}" "${DAEMON_NAME}" 2>/dev/null
ret=${?}
;;
* )
echo "Usage: ${SCRIPTNAME} {start|stop|restart|reload|force-reload|status}" >&2
exit 1
;;
esac
exit ${ret}

View File

@ -1,9 +1,12 @@
# documentation: https://rspamd.com/doc/configuration/metrics.html#actions
# and https://rspamd.com/doc/configuration/metrics.html
#greylist = 4;
#add_header = 6;
#rewrite_subject = 7;
#reject = 15;
# These values work in conjunction with the symbol scores in
# `scores.d/*.conf`. When adjusting them, make sure to understand
# and to be able to explain the impact on the whole system.
greylist = 4;
add_header = 6;
rewrite_subject = 7;
reject = 11;
subject = "***SPAM*** %s"

View File

@ -0,0 +1,12 @@
# documentation: https://rspamd.com/doc/configuration/settings.html
# DMS::SED_TAG::1::START
# Disable all checks for authenticated users
authenticated {
priority = high;
authenticated = yes;
apply {
groups_enabled = [dkim];
}
}
# DMS::SED_TAG::1::END

View File

@ -0,0 +1,108 @@
# Please refer to
# https://github.com/docker-mailserver/docker-mailserver/issues/3690
# for understanding this file and its scores' values.
symbols = {
# SPF
"R_SPF_ALLOW" {
weight = -1;
description = "SPF verification allows sending";
groups = ["spf"];
}
"R_SPF_NA" {
weight = 1.5;
description = "Missing SPF record";
one_shot = true;
groups = ["spf"];
}
"R_SPF_SOFTFAIL" {
weight = 2.5;
description = "SPF verification soft-failed";
groups = ["spf"];
}
"R_SPF_FAIL" {
weight = 4.5;
description = "SPF verification failed";
groups = ["spf"];
}
"R_SPF_NEUTRAL" { # == R_SPF_NA
weight = 1.5;
description = "SPF policy is neutral";
groups = ["spf"];
}
"R_SPF_DNSFAIL" { # == R_SPF_SOFTFAIL
weight = 2.5;
description = "SPF DNS failure";
groups = ["spf"];
}
"R_SPF_PERMFAIL" { # == R_SPF_FAIL
weight = 4.5;
description = "SPF record is malformed or persistent DNS error";
groups = ["spf"];
}
# DKIM
"R_DKIM_ALLOW" {
weight = -1;
description = "DKIM verification succeed";
one_shot = true;
groups = ["dkim"];
}
"R_DKIM_NA" {
weight = 0;
description = "Missing DKIM signature";
one_shot = true;
groups = ["dkim"];
}
"R_DKIM_TEMPFAIL" {
weight = 1.5;
description = "DKIM verification soft-failed";
groups = ["dkim"];
}
"R_DKIM_PERMFAIL" {
weight = 4.5;
description = "DKIM verification hard-failed (invalid)";
groups = ["dkim"];
}
"R_DKIM_REJECT" { # == R_DKIM_PERMFAIL
weight = 4.5;
description = "DKIM verification failed";
one_shot = true;
groups = ["dkim"];
}
# DMARC
"DMARC_NA" {
weight = 1;
description = "No DMARC record";
groups = ["dmarc"];
}
"DMARC_POLICY_QUARANTINE" {
weight = 1.5;
description = "DMARC quarantine policy";
groups = ["dmarc"];
}
"DMARC_POLICY_REJECT" {
weight = 2;
description = "DMARC reject policy";
groups = ["dmarc"];
}
"DMARC_POLICY_ALLOW" { # no equivalent
weight = -1;
description = "DMARC permit policy";
groups = ["dmarc"];
}
"DMARC_POLICY_ALLOW_WITH_FAILURES" { # no equivalent
weight = -0.5;
description = "DMARC permit policy with DKIM/SPF failure";
groups = ["dmarc"];
}
"DMARC_POLICY_SOFTFAIL" { # == DMARC_POLICY_QUARANTINE
weight = 1.5;
description = "DMARC soft-failed";
groups = ["dmarc"];
}
}

View File

@ -43,10 +43,6 @@ function _install_postfix() {
function _install_packages() {
_log 'debug' 'Installing all packages now'
declare -a ANTI_VIRUS_SPAM_PACKAGES
declare -a CODECS_PACKAGES MISCELLANEOUS_PACKAGES
declare -a POSTFIX_PACKAGES MAIL_PROGRAMS_PACKAGES
ANTI_VIRUS_SPAM_PACKAGES=(
amavisd-new clamav clamav-daemon
pyzor razor spamassassin
@ -62,18 +58,17 @@ function _install_packages() {
)
MISCELLANEOUS_PACKAGES=(
apt-transport-https bind9-dnsutils binutils bsd-mailx
apt-transport-https binutils bsd-mailx
ca-certificates curl dbconfig-no-thanks
dumb-init ed gnupg iproute2 iputils-ping
libdate-manip-perl libldap-common
libmail-spf-perl libnet-dns-perl
locales logwatch netcat-openbsd
nftables rsyslog supervisor
uuid whois
dumb-init gnupg iproute2 libdate-manip-perl
libldap-common libmail-spf-perl
libnet-dns-perl locales logwatch
netcat-openbsd nftables rsyslog
supervisor uuid whois
)
POSTFIX_PACKAGES=(
pflogsumm postgrey postfix-ldap
pflogsumm postgrey postfix-ldap postfix-mta-sts-resolver
postfix-pcre postfix-policyd-spf-python postsrsd
)
@ -82,24 +77,37 @@ function _install_packages() {
opendmarc libsasl2-modules sasl2-bin
)
# `bind9-dnsutils` provides the `dig` command
# `iputils-ping` provides the `ping` command
DEBUG_PACKAGES=(
bind9-dnsutils iputils-ping less nano
)
apt-get "${QUIET}" --no-install-recommends install \
"${ANTI_VIRUS_SPAM_PACKAGES[@]}" \
"${CODECS_PACKAGES[@]}" \
"${MISCELLANEOUS_PACKAGES[@]}" \
"${POSTFIX_PACKAGES[@]}" \
"${MAIL_PROGRAMS_PACKAGES[@]}"
"${MAIL_PROGRAMS_PACKAGES[@]}" \
"${DEBUG_PACKAGES[@]}"
}
function _install_dovecot() {
declare -a DOVECOT_PACKAGES
# Dovecot packages for officially supported features.
DOVECOT_PACKAGES=(
dovecot-core dovecot-imapd
dovecot-ldap dovecot-lmtpd dovecot-managesieved
dovecot-pop3d dovecot-sieve dovecot-solr
)
if [[ ${DOVECOT_COMMUNITY_REPO} -eq 1 ]]; then
# Dovecot packages for community supported features.
DOVECOT_PACKAGES+=(dovecot-auth-lua)
# Dovecot's deb community repository only provides x86_64 packages, so do not include it
# when building for another architecture.
if [[ ${DOVECOT_COMMUNITY_REPO} -eq 1 ]] && [[ "$(uname --machine)" == "x86_64" ]]; then
_log 'trace' 'Using Dovecot community repository'
curl https://repo.dovecot.org/DOVECOT-REPO-GPG | gpg --import
gpg --export ED409DA1 > /etc/apt/trusted.gpg.d/dovecot.gpg
@ -107,6 +115,9 @@ function _install_dovecot() {
_log 'trace' 'Updating Dovecot package signatures'
apt-get "${QUIET}" update
# Additional community package needed for Lua support if the Dovecot community repository is used.
DOVECOT_PACKAGES+=(dovecot-lua)
fi
_log 'debug' 'Installing Dovecot'
@ -119,29 +130,14 @@ function _install_dovecot() {
function _install_rspamd() {
_log 'trace' 'Adding Rspamd package signatures'
local DEB_FILE='/etc/apt/sources.list.d/rspamd.list'
local RSPAMD_PACKAGE_NAME
# We try getting the most recent version of Rspamd for aarch64 (from an official source, which
# is the backports repository). The version for aarch64 is 3.2; the most recent version for amd64
# that we get with the official PPA is 3.4.
#
# Not removing it later is fine as you have to explicitly opt into installing a backports package
# which is not something you could be doing by accident.
if [[ $(uname --machine) == 'aarch64' ]]; then
echo '# Official Rspamd PPA does not support aarch64, so we use the Bullseye backports' >"${DEB_FILE}"
echo 'deb [arch=arm64] http://deb.debian.org/debian bullseye-backports main' >>"${DEB_FILE}"
RSPAMD_PACKAGE_NAME='rspamd/bullseye-backports'
else
curl -sSfL https://rspamd.com/apt-stable/gpg.key | gpg --dearmor >/etc/apt/trusted.gpg.d/rspamd.gpg
local URL='[arch=amd64 signed-by=/etc/apt/trusted.gpg.d/rspamd.gpg] http://rspamd.com/apt-stable/ bullseye main'
echo "deb ${URL}" >"${DEB_FILE}"
echo "deb-src ${URL}" >>"${DEB_FILE}"
RSPAMD_PACKAGE_NAME='rspamd'
fi
curl -sSfL https://rspamd.com/apt-stable/gpg.key | gpg --dearmor >/etc/apt/trusted.gpg.d/rspamd.gpg
local URL='[signed-by=/etc/apt/trusted.gpg.d/rspamd.gpg] http://rspamd.com/apt-stable/ bullseye main'
echo "deb ${URL}" >"${DEB_FILE}"
_log 'debug' 'Installing Rspamd'
apt-get "${QUIET}" update
apt-get "${QUIET}" --no-install-recommends install "${RSPAMD_PACKAGE_NAME}" 'redis-server'
apt-get "${QUIET}" --no-install-recommends install 'rspamd' 'redis-server'
}
function _install_fail2ban() {
@ -194,6 +190,19 @@ function _install_getmail() {
apt-get "${QUIET}" autoremove
}
function _install_utils() {
_log 'debug' 'Installing utils sourced from Github'
_log 'trace' 'Installing jaq'
curl -sL "https://github.com/01mf02/jaq/releases/latest/download/jaq-v1.2.0-$(uname -m)-unknown-linux-gnu" -o /usr/bin/jaq && chmod +x /usr/bin/jaq
_log 'trace' 'Installing swaks'
local SWAKS_VERSION='20240103.0'
local SWAKS_RELEASE="swaks-${SWAKS_VERSION}"
curl -sSfL "https://github.com/jetmore/swaks/releases/download/v${SWAKS_VERSION}/${SWAKS_RELEASE}.tar.gz" | tar -xz
mv "${SWAKS_RELEASE}/swaks" /usr/local/bin
rm -r "${SWAKS_RELEASE}"
}
function _remove_data_after_package_installations() {
_log 'debug' 'Deleting sensitive files (secrets)'
rm /etc/postsrsd.secret
@ -217,5 +226,6 @@ _install_dovecot
_install_rspamd
_install_fail2ban
_install_getmail
_install_utils
_remove_data_after_package_installations
_post_installation_steps

View File

@ -21,6 +21,10 @@ source /etc/dms-settings
# usage with DMS_HOSTNAME, which should remove the need to call this:
_obtain_hostname_and_domainname
# This is a helper to properly set all Rspamd-related environment variables
# correctly and in one place.
_rspamd_get_envs
# verify checksum file exists; must be prepared by start-mailserver.sh
if [[ ! -f ${CHKSUM_FILE} ]]; then
_exit_with_error "'${CHKSUM_FILE}' is missing" 0
@ -49,6 +53,7 @@ function _check_for_changes() {
# Handle any changes
_ssl_changes
_postfix_dovecot_changes
_rspamd_changes
_log_with_date 'debug' 'Reloading services due to detected changes'
@ -174,6 +179,33 @@ function _ssl_changes() {
# They presently have no special handling other than to trigger a change that will restart Postfix/Dovecot.
}
function _rspamd_changes() {
# RSPAMD_DMS_D='/tmp/docker-mailserver/rspamd'
if [[ ${CHANGED} =~ ${RSPAMD_DMS_D}/.* ]]; then
# "${RSPAMD_DMS_D}/override.d"
if [[ ${CHANGED} =~ ${RSPAMD_DMS_OVERRIDE_D}/.* ]]; then
_log_with_date 'trace' 'Rspamd - Copying configuration overrides'
rm "${RSPAMD_OVERRIDE_D}"/*
cp "${RSPAMD_DMS_OVERRIDE_D}"/* "${RSPAMD_OVERRIDE_D}"
fi
# "${RSPAMD_DMS_D}/custom-commands.conf"
if [[ ${CHANGED} =~ ${RSPAMD_DMS_CUSTOM_COMMANDS_F} ]]; then
_log_with_date 'trace' 'Rspamd - Generating new configuration from custom commands'
_rspamd_handle_user_modules_adjustments
fi
# "${RSPAMD_DMS_D}/dkim"
if [[ ${CHANGED} =~ ${RSPAMD_DMS_DKIM_D} ]]; then
_log_with_date 'trace' 'Rspamd - DKIM files updated'
fi
_log_with_date 'debug' 'Rspamd configuration has changed - restarting service'
supervisorctl restart rspamd
fi
}
while true; do
_check_for_changes
sleep 2

View File

@ -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
@ -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

View File

@ -23,6 +23,7 @@ function _handle_postfix_virtual_config() {
fi
}
# TODO: Investigate why this file is always created, nothing seems to append only the cp below?
function _handle_postfix_regexp_config() {
: >/etc/postfix/regexp
@ -30,12 +31,7 @@ function _handle_postfix_regexp_config() {
_log 'trace' "Adding regexp alias file postfix-regexp.cf"
cp -f /tmp/docker-mailserver/postfix-regexp.cf /etc/postfix/regexp
if ! grep 'virtual_alias_maps.*pcre:/etc/postfix/regexp' /etc/postfix/main.cf; then
sed -i -E \
's|virtual_alias_maps(.*)|virtual_alias_maps\1 pcre:/etc/postfix/regexp|g' \
/etc/postfix/main.cf
fi
_add_to_or_update_postfix_main 'virtual_alias_maps' 'pcre:/etc/postfix/regexp'
fi
}

View File

@ -40,6 +40,12 @@ function _monitored_files_checksums() {
"${DMS_DIR}/dovecot-quotas.cf"
"${DMS_DIR}/dovecot-masters.cf"
)
# Check whether Rspamd is used and if so, monitor it's changes as well
if [[ ${ENABLE_RSPAMD} -eq 1 ]] && [[ -d ${RSPAMD_DMS_D} ]]; then
readarray -d '' STAGING_FILES_RSPAMD < <(find "${RSPAMD_DMS_D}" -type f -name "*.sh" -print0)
STAGING_FILES+=("${STAGING_FILES_RSPAMD[@]}")
fi
fi
# SSL certs:

View File

@ -16,6 +16,7 @@ function _import_scripts() {
source "${PATH_TO_SCRIPTS}/network.sh"
source "${PATH_TO_SCRIPTS}/postfix.sh"
source "${PATH_TO_SCRIPTS}/relay.sh"
source "${PATH_TO_SCRIPTS}/rspamd.sh"
source "${PATH_TO_SCRIPTS}/ssl.sh"
source "${PATH_TO_SCRIPTS}/utils.sh"

View File

@ -91,3 +91,44 @@ function _vhost_ldap_support() {
#
# /etc/aliases is handled by `alias.sh` and uses `postalias` to update the Postfix alias database. No need for `postmap`.
# http://www.postfix.org/postalias.1.html
# Add a key with a value to Postfix's main configuration file
# or update an existing key. An already existing key can be updated
# by either appending to the existing value (default) or by prepending.
#
# @param ${1} = key name in Postfix's main configuration file
# @param ${2} = new value (appended or prepended)
# @param ${3} = action "append" (default) or "prepend" [OPTIONAL]
function _add_to_or_update_postfix_main() {
local KEY=${1:?Key name is required}
local NEW_VALUE=${2:?New value is required}
local ACTION=${3:-append}
local CURRENT_VALUE
# Get current value from /etc/postfix/main.cf
_adjust_mtime_for_postfix_maincf
CURRENT_VALUE=$(postconf -h "${KEY}" 2>/dev/null)
# If key does not exist or value is empty, add it - otherwise update with ACTION:
if [[ -z ${CURRENT_VALUE} ]]; then
postconf "${KEY} = ${NEW_VALUE}"
else
# If $NEW_VALUE is already present --> nothing to do, skip.
if [[ " ${CURRENT_VALUE} " == *" ${NEW_VALUE} "* ]]; then
return 0
fi
case "${ACTION}" in
('append')
postconf "${KEY} = ${CURRENT_VALUE} ${NEW_VALUE}"
;;
('prepend')
postconf "${KEY} = ${NEW_VALUE} ${CURRENT_VALUE}"
;;
(*)
_log 'error' "Action '${3}' in _add_to_or_update_postfix_main is unknown"
return 1
;;
esac
fi
}

View File

@ -173,7 +173,7 @@ function _setup_relayhost() {
_log 'debug' 'Setting up Postfix Relay Hosts'
if [[ -n ${DEFAULT_RELAY_HOST} ]]; then
_log 'trace' "Setting default relay host ${DEFAULT_RELAY_HOST} to /etc/postfix/main.cf"
_log 'trace' "Setting default relay host ${DEFAULT_RELAY_HOST}"
postconf "relayhost = ${DEFAULT_RELAY_HOST}"
fi

View File

@ -0,0 +1,117 @@
#! /bin/bash
# shellcheck disable=SC2034 # VAR appears unused.
# Perform a specific command as the Rspamd user (`_rspamd`). This is useful
# in case you want to have correct permissions on newly created files or if
# you want to check whether Rspamd can perform a specific action.
function __do_as_rspamd_user() {
_log 'trace' "Running '${*}' as user '_rspamd'"
su _rspamd -s /bin/bash -c "${*}"
}
# Calling this function brings common Rspamd-related environment variables
# into the current context. The environment variables are `readonly`, i.e.
# they cannot be modified. Use this function when you require common directory
# names, file names, etc.
function _rspamd_get_envs() {
readonly RSPAMD_LOCAL_D='/etc/rspamd/local.d'
readonly RSPAMD_OVERRIDE_D='/etc/rspamd/override.d'
readonly RSPAMD_DMS_D='/tmp/docker-mailserver/rspamd'
readonly RSPAMD_DMS_DKIM_D="${RSPAMD_DMS_D}/dkim"
readonly RSPAMD_DMS_OVERRIDE_D="${RSPAMD_DMS_D}/override.d"
readonly RSPAMD_DMS_CUSTOM_COMMANDS_F="${RSPAMD_DMS_D}/custom-commands.conf"
}
# Parses `RSPAMD_DMS_CUSTOM_COMMANDS_F` and executed the directives given by the file.
# To get a detailed explanation of the commands and how the file works, visit
# https://docker-mailserver.github.io/docker-mailserver/latest/config/security/rspamd/#with-the-help-of-a-custom-file
function _rspamd_handle_user_modules_adjustments() {
# Adds an option with a corresponding value to a module, or, in case the option
# is already present, overwrites it.
#
# @param ${1} = file name in ${RSPAMD_OVERRIDE_D}/
# @param ${2} = module name as it should appear in the log
# @param ${3} = option name in the module
# @param ${4} = value of the option
#
# ## Note
#
# While this function is currently bound to the scope of `_rspamd_handle_user_modules_adjustments`,
# it is written in a versatile way (taking 4 arguments instead of assuming `ARGUMENT2` / `ARGUMENT3`
# are set) so that it may be used elsewhere if needed.
function __add_or_replace() {
local MODULE_FILE=${1:?Module file name must be provided}
local MODULE_LOG_NAME=${2:?Module log name must be provided}
local OPTION=${3:?Option name must be provided}
local VALUE=${4:?Value belonging to an option must be provided}
# remove possible whitespace at the end (e.g., in case ${ARGUMENT3} is empty)
VALUE=${VALUE% }
local FILE="${RSPAMD_OVERRIDE_D}/${MODULE_FILE}"
readonly MODULE_FILE MODULE_LOG_NAME OPTION VALUE FILE
[[ -f ${FILE} ]] || touch "${FILE}"
if grep -q -E "${OPTION}.*=.*" "${FILE}"; then
__rspamd__log 'trace' "Overwriting option '${OPTION}' with value '${VALUE}' for ${MODULE_LOG_NAME}"
sed -i -E "s|([[:space:]]*${OPTION}).*|\1 = ${VALUE};|g" "${FILE}"
else
__rspamd__log 'trace' "Setting option '${OPTION}' for ${MODULE_LOG_NAME} to '${VALUE}'"
echo "${OPTION} = ${VALUE};" >>"${FILE}"
fi
}
# We check for usage of the previous location of the commands file.
# TODO This can be removed after the release of v14.0.0.
local RSPAMD_DMS_CUSTOM_COMMANDS_F_OLD="${RSPAMD_DMS_D}-modules.conf"
readonly RSPAMD_DMS_CUSTOM_COMMANDS_F_OLD
if [[ -f ${RSPAMD_DMS_CUSTOM_COMMANDS_F_OLD} ]]; then
_dms_panic__general "Old custom command file location '${RSPAMD_DMS_CUSTOM_COMMANDS_F_OLD}' is deprecated (use '${RSPAMD_DMS_CUSTOM_COMMANDS_F}' now)" 'Rspamd setup'
fi
if [[ -f "${RSPAMD_DMS_CUSTOM_COMMANDS_F}" ]]; then
__rspamd__log 'debug' "Found file '${RSPAMD_DMS_CUSTOM_COMMANDS_F}' - parsing and applying it"
local COMMAND ARGUMENT1 ARGUMENT2 ARGUMENT3
while read -r COMMAND ARGUMENT1 ARGUMENT2 ARGUMENT3; do
case "${COMMAND}" in
('disable-module')
__rspamd__helper__enable_disable_module "${ARGUMENT1}" 'false' 'override'
;;
('enable-module')
__rspamd__helper__enable_disable_module "${ARGUMENT1}" 'true' 'override'
;;
('set-option-for-module')
__add_or_replace "${ARGUMENT1}.conf" "module '${ARGUMENT1}'" "${ARGUMENT2}" "${ARGUMENT3}"
;;
('set-option-for-controller')
__add_or_replace 'worker-controller.inc' 'controller worker' "${ARGUMENT1}" "${ARGUMENT2} ${ARGUMENT3}"
;;
('set-option-for-proxy')
__add_or_replace 'worker-proxy.inc' 'proxy worker' "${ARGUMENT1}" "${ARGUMENT2} ${ARGUMENT3}"
;;
('set-common-option')
__add_or_replace 'options.inc' 'common options' "${ARGUMENT1}" "${ARGUMENT2} ${ARGUMENT3}"
;;
('add-line')
__rspamd__log 'trace' "Adding complete line to '${ARGUMENT1}'"
echo "${ARGUMENT2}${ARGUMENT3+ ${ARGUMENT3}}" >>"${RSPAMD_OVERRIDE_D}/${ARGUMENT1}"
;;
(*)
__rspamd__log 'warn' "Command '${COMMAND}' is invalid"
continue
;;
esac
done < <(_get_valid_lines_from_file "${RSPAMD_DMS_CUSTOM_COMMANDS_F}")
fi
}

View File

@ -4,6 +4,16 @@ function _escape() {
echo "${1//./\\.}"
}
# TODO: Not in use currently. Maybe in the future: https://github.com/docker-mailserver/docker-mailserver/pull/3484/files#r1299410851
# Replaces a string so that it can be used inside
# `sed` safely.
#
# @param ${1} = string to escape
# @output = prints the escaped string
function _escape_for_sed() {
sed -E 's/[]\/$*.^[]/\\&/g' <<< "${1:?String to escape for sed is required}"
}
# Returns input after filtering out lines that are:
# empty, white-space, comments (`#` as the first non-whitespace character)
function _get_valid_lines_from_file() {
@ -29,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
}
@ -117,9 +127,17 @@ function _replace_by_env_in_file() {
function _env_var_expect_zero_or_one() {
local ENV_VAR_NAME=${1:?ENV var name must be provided to _env_var_expect_zero_or_one}
[[ ${!ENV_VAR_NAME} =~ ^(0|1)$ ]] && return 0
_log 'warn' "The value of '${ENV_VAR_NAME}' is not zero or one ('${!ENV_VAR_NAME}'), but was expected to be"
return 1
if [[ ! -v ${ENV_VAR_NAME} ]]; then
_log 'warn' "'${ENV_VAR_NAME}' is not set, but was expected to be"
return 1
fi
if [[ ! ${!ENV_VAR_NAME} =~ ^(0|1)$ ]]; then
_log 'warn' "The value of '${ENV_VAR_NAME}' (= '${!ENV_VAR_NAME}') is not 0 or 1, but was expected to be"
return 1
fi
return 0
}
# Check if an environment variable's value is an integer.

View File

@ -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'
@ -48,6 +49,7 @@ function _register_functions() {
_register_setup_function '_setup_dovecot_dhparam'
_register_setup_function '_setup_dovecot_quota'
_register_setup_function '_setup_spam_to_junk'
_register_setup_function '_setup_spam_mark_as_read'
fi
case "${ACCOUNT_PROVISIONER}" in
@ -69,6 +71,11 @@ function _register_functions() {
;;
esac
if [[ ${ENABLE_OAUTH2} -eq 1 ]]; then
_environment_variables_oauth2
_register_setup_function '_setup_oauth2'
fi
if [[ ${ENABLE_SASLAUTHD} -eq 1 ]]; then
_environment_variables_saslauthd
_register_setup_function '_setup_saslauthd'
@ -89,20 +96,22 @@ function _register_functions() {
_register_setup_function '_setup_dovecot_hostname'
_register_setup_function '_setup_postfix_early'
_register_setup_function '_setup_fetchmail'
_register_setup_function '_setup_fetchmail_parallel'
# needs to come after _setup_postfix_early
# Dependent upon _setup_postfix_early first calling _create_aliases
# Due to conditional check for /etc/postfix/regexp
_register_setup_function '_setup_spoof_protection'
_register_setup_function '_setup_getmail'
_register_setup_function '_setup_postfix_late'
if [[ ${ENABLE_SRS} -eq 1 ]]; then
_register_setup_function '_setup_SRS'
_register_start_daemon '_start_daemon_postsrsd'
fi
_register_setup_function '_setup_postfix_late'
_register_setup_function '_setup_fetchmail'
_register_setup_function '_setup_fetchmail_parallel'
_register_setup_function '_setup_getmail'
_register_setup_function '_setup_logrotate'
_register_setup_function '_setup_mail_summary'
_register_setup_function '_setup_logwatch'
@ -111,6 +120,11 @@ function _register_functions() {
_register_setup_function '_setup_apply_fixes_after_configuration'
_register_setup_function '_environment_variables_export'
if [[ ${ENABLE_MTA_STS} -eq 1 ]]; then
_register_setup_function '_setup_mta_sts'
_register_start_daemon '_start_daemon_mta_sts_daemon'
fi
# ? >> Daemons
_register_start_daemon '_start_daemon_cron'
@ -118,7 +132,13 @@ function _register_functions() {
[[ ${SMTP_ONLY} -ne 1 ]] && _register_start_daemon '_start_daemon_dovecot'
[[ ${ENABLE_UPDATE_CHECK} -eq 1 ]] && _register_start_daemon '_start_daemon_update_check'
if [[ ${ENABLE_UPDATE_CHECK} -eq 1 ]]; then
if [[ ${DMS_RELEASE} != 'edge' ]]; then
_register_start_daemon '_start_daemon_update_check'
else
_log 'warn' "ENABLE_UPDATE_CHECK=1 is configured, but image is not a stable release. Update-Check is disabled."
fi
fi
# The order here matters: Since Rspamd is using Redis, Redis should be started before Rspamd.
[[ ${ENABLE_RSPAMD_REDIS} -eq 1 ]] && _register_start_daemon '_start_daemon_rspamd_redis'
@ -151,7 +171,7 @@ function _register_functions() {
_early_supervisor_setup
_early_variables_setup
_log 'info' "Welcome to docker-mailserver $(</VERSION)"
_log 'info' "Welcome to docker-mailserver ${DMS_RELEASE}"
_register_functions
_check

View File

@ -38,6 +38,7 @@ function _start_daemon_opendkim { _default_start_daemon 'opendkim' ;
function _start_daemon_opendmarc { _default_start_daemon 'opendmarc' ; }
function _start_daemon_postgrey { _default_start_daemon 'postgrey' ; }
function _start_daemon_postsrsd { _default_start_daemon 'postsrsd' ; }
function _start_daemon_mta_sts_daemon { _default_start_daemon 'mta-sts-daemon' ; }
function _start_daemon_rspamd { _default_start_daemon 'rspamd' ; }
function _start_daemon_rspamd_redis { _default_start_daemon 'rspamd-redis' ; }
function _start_daemon_rsyslog { _default_start_daemon 'rsyslog' ; }

View File

@ -20,6 +20,16 @@ function _setup() {
${FUNC}
done
_setup_post
}
function _setup_post() {
# Dovecot `.svbin` files must have a newer mtime than their `.sieve` source files,
# Modifications during setup to these files sometimes results in a common mtime value.
# Handled during post-setup as setup of Dovecot Sieve scripts is not centralized.
find /usr/lib/dovecot/ -iname '*.sieve' -exec touch -d '2 seconds ago' {} +
find /usr/lib/dovecot/ -iname '*.svbin' -exec touch -d '1 seconds ago' {} +
# All startup modifications to configs should have taken place before calling this:
_prepare_for_change_detection
}

View File

@ -16,10 +16,9 @@ function _setup_opendkim() {
_log 'trace' "Adding OpenDKIM to Postfix's milters"
postconf 'dkim_milter = inet:localhost:8891'
# shellcheck disable=SC2016
sed -i -E \
-e '/\$dkim_milter/! s|^(smtpd_milters =.*)|\1 \$dkim_milter|g' \
-e '/\$dkim_milter/! s|^(non_smtpd_milters =.*)|\1 \$dkim_milter|g' \
/etc/postfix/main.cf
_add_to_or_update_postfix_main 'smtpd_milters' '$dkim_milter'
# shellcheck disable=SC2016
_add_to_or_update_postfix_main 'non_smtpd_milters' '$dkim_milter'
# check if any keys are available
if [[ -e /tmp/docker-mailserver/opendkim/KeyTable ]]; then
@ -64,7 +63,7 @@ function _setup_opendmarc() {
postconf 'dmarc_milter = inet:localhost:8893'
# Make sure to append the OpenDMARC milter _after_ the OpenDKIM milter!
# shellcheck disable=SC2016
sed -i -E '/\$dmarc_milter/! s|^(smtpd_milters =.*)|\1 \$dmarc_milter|g' /etc/postfix/main.cf
_add_to_or_update_postfix_main 'smtpd_milters' '$dmarc_milter'
sed -i \
-e "s|^AuthservID.*$|AuthservID ${HOSTNAME}|g" \

View File

@ -6,12 +6,10 @@ function _setup_dovecot() {
cp -a /usr/share/dovecot/protocols.d /etc/dovecot/
# disable pop3 (it will be eventually enabled later in the script, if requested)
mv /etc/dovecot/protocols.d/pop3d.protocol /etc/dovecot/protocols.d/pop3d.protocol.disab
# disable imap (it will be eventually enabled later in the script, if requested)
mv /etc/dovecot/protocols.d/imapd.protocol /etc/dovecot/protocols.d/imapd.protocol.disab
mv /etc/dovecot/protocols.d/managesieved.protocol /etc/dovecot/protocols.d/managesieved.protocol.disab
sed -i -e 's|#ssl = yes|ssl = yes|g' /etc/dovecot/conf.d/10-master.conf
sed -i -e 's|#port = 993|port = 993|g' /etc/dovecot/conf.d/10-master.conf
sed -i -e 's|#port = 995|port = 995|g' /etc/dovecot/conf.d/10-master.conf
sed -i -e 's|#ssl = yes|ssl = required|g' /etc/dovecot/conf.d/10-ssl.conf
sed -i 's|^postmaster_address = .*$|postmaster_address = '"${POSTMASTER_ADDRESS}"'|g' /etc/dovecot/conf.d/15-lda.conf
sedfile -i 's|^postmaster_address = .*$|postmaster_address = '"${POSTMASTER_ADDRESS}"'|g' /etc/dovecot/conf.d/15-lda.conf
if ! grep -q -E '^stats_writer_socket_path=' /etc/dovecot/dovecot.conf; then
printf '\n%s\n' 'stats_writer_socket_path=' >>/etc/dovecot/dovecot.conf
@ -37,9 +35,21 @@ function _setup_dovecot() {
esac
if [[ ${ENABLE_POP3} -eq 1 || ${ENABLE_IMAP} -eq 1 ]]; then
sedfile -i -e 's|#ssl = yes|ssl = yes|g' /etc/dovecot/conf.d/10-master.conf
sedfile -i -e 's|#ssl = yes|ssl = required|g' /etc/dovecot/conf.d/10-ssl.conf
fi
if [[ ${ENABLE_POP3} -eq 1 ]]; then
_log 'debug' 'Enabling POP3 services'
mv /etc/dovecot/protocols.d/pop3d.protocol.disab /etc/dovecot/protocols.d/pop3d.protocol
sedfile -i -e 's|#port = 995|port = 995|g' /etc/dovecot/conf.d/10-master.conf
fi
if [[ ${ENABLE_IMAP} -eq 1 ]]; then
_log 'debug' 'Enabling IMAP services'
mv /etc/dovecot/protocols.d/imapd.protocol.disab /etc/dovecot/protocols.d/imapd.protocol
sedfile -i -e 's|#port = 993|port = 993|g' /etc/dovecot/conf.d/10-master.conf
fi
[[ -f /tmp/docker-mailserver/dovecot.cf ]] && cp /tmp/docker-mailserver/dovecot.cf /etc/dovecot/local.conf
@ -89,23 +99,20 @@ function _setup_dovecot_quota() {
# disable dovecot quota in docevot confs
if [[ -f /etc/dovecot/conf.d/90-quota.conf ]]; then
mv /etc/dovecot/conf.d/90-quota.conf /etc/dovecot/conf.d/90-quota.conf.disab
sed -i \
sedfile -i \
"s|mail_plugins = \$mail_plugins quota|mail_plugins = \$mail_plugins|g" \
/etc/dovecot/conf.d/10-mail.conf
sed -i \
sedfile -i \
"s|mail_plugins = \$mail_plugins imap_quota|mail_plugins = \$mail_plugins|g" \
/etc/dovecot/conf.d/20-imap.conf
fi
# disable quota policy check in postfix
sed -i "s|check_policy_service inet:localhost:65265||g" /etc/postfix/main.cf
else
if [[ -f /etc/dovecot/conf.d/90-quota.conf.disab ]]; then
mv /etc/dovecot/conf.d/90-quota.conf.disab /etc/dovecot/conf.d/90-quota.conf
sed -i \
sedfile -i \
"s|mail_plugins = \$mail_plugins|mail_plugins = \$mail_plugins quota|g" \
/etc/dovecot/conf.d/10-mail.conf
sed -i \
sedfile -i \
"s|mail_plugins = \$mail_plugins|mail_plugins = \$mail_plugins imap_quota|g" \
/etc/dovecot/conf.d/20-imap.conf
fi
@ -113,11 +120,11 @@ function _setup_dovecot_quota() {
local MESSAGE_SIZE_LIMIT_MB=$((POSTFIX_MESSAGE_SIZE_LIMIT / 1000000))
local MAILBOX_LIMIT_MB=$((POSTFIX_MAILBOX_SIZE_LIMIT / 1000000))
sed -i \
sedfile -i \
"s|quota_max_mail_size =.*|quota_max_mail_size = ${MESSAGE_SIZE_LIMIT_MB}$([[ ${MESSAGE_SIZE_LIMIT_MB} -eq 0 ]] && echo "" || echo "M")|g" \
/etc/dovecot/conf.d/90-quota.conf
sed -i \
sedfile -i \
"s|quota_rule = \*:storage=.*|quota_rule = *:storage=${MAILBOX_LIMIT_MB}$([[ ${MAILBOX_LIMIT_MB} -eq 0 ]] && echo "" || echo "M")|g" \
/etc/dovecot/conf.d/90-quota.conf
@ -127,7 +134,7 @@ function _setup_dovecot_quota() {
fi
# enable quota policy check in postfix
sed -i -E \
sedfile -i -E \
"s|(reject_unknown_recipient_domain)|\1, check_policy_service inet:localhost:65265|g" \
/etc/postfix/main.cf
fi
@ -188,5 +195,5 @@ function _setup_dovecot_dhparam() {
function _setup_dovecot_hostname() {
_log 'debug' 'Applying hostname to Dovecot'
sed -i "s|^#hostname =.*$|hostname = '${HOSTNAME}'|g" /etc/dovecot/conf.d/15-lda.conf
sedfile -i "s|^#hostname =.*$|hostname = '${HOSTNAME}'|g" /etc/dovecot/conf.d/15-lda.conf
}

View File

@ -38,13 +38,7 @@ function _setup_ldap() {
DOVECOT_LDAP_MAPPING['DOVECOT_BASE']="${DOVECOT_BASE:="${LDAP_SEARCH_BASE}"}"
DOVECOT_LDAP_MAPPING['DOVECOT_DN']="${DOVECOT_DN:="${LDAP_BIND_DN}"}"
DOVECOT_LDAP_MAPPING['DOVECOT_DNPASS']="${DOVECOT_DNPASS:="${LDAP_BIND_PW}"}"
DOVECOT_LDAP_MAPPING['DOVECOT_URIS']="${DOVECOT_URIS:="${DOVECOT_HOSTS:="${LDAP_SERVER_HOST}"}"}"
# Add protocol to DOVECOT_URIS so that we can use dovecot's "uris" option:
# https://doc.dovecot.org/configuration_manual/authentication/ldap/
if [[ ${DOVECOT_LDAP_MAPPING["DOVECOT_URIS"]} != *'://'* ]]; then
DOVECOT_LDAP_MAPPING['DOVECOT_URIS']="ldap://${DOVECOT_LDAP_MAPPING["DOVECOT_URIS"]}"
fi
DOVECOT_LDAP_MAPPING['DOVECOT_URIS']="${DOVECOT_URIS:="${LDAP_SERVER_HOST}"}"
# Default DOVECOT_PASS_FILTER to the same value as DOVECOT_USER_FILTER
DOVECOT_LDAP_MAPPING['DOVECOT_PASS_FILTER']="${DOVECOT_PASS_FILTER:="${DOVECOT_USER_FILTER}"}"

View File

@ -13,31 +13,22 @@ function _setup_logs_general() {
function _setup_logrotate() {
_log 'debug' 'Setting up logrotate'
LOGROTATE='/var/log/mail/mail.log\n{\n compress\n copytruncate\n delaycompress\n'
if [[ ${LOGROTATE_INTERVAL} =~ ^(daily|weekly|monthly)$ ]]; then
_log 'trace' "Logrotate interval set to ${LOGROTATE_INTERVAL}"
else
_dms_panic__invalid_value 'LOGROTATE_INTERVAL' 'Setup -> Logrotate'
fi
case "${LOGROTATE_INTERVAL}" in
( 'daily' )
_log 'trace' 'Setting postfix logrotate interval to daily'
LOGROTATE="${LOGROTATE} rotate 4\n daily\n"
;;
( 'weekly' )
_log 'trace' 'Setting postfix logrotate interval to weekly'
LOGROTATE="${LOGROTATE} rotate 4\n weekly\n"
;;
( 'monthly' )
_log 'trace' 'Setting postfix logrotate interval to monthly'
LOGROTATE="${LOGROTATE} rotate 4\n monthly\n"
;;
( * )
_log 'warn' 'LOGROTATE_INTERVAL not found in _setup_logrotate'
;;
esac
echo -e "${LOGROTATE}}" >/etc/logrotate.d/maillog
cat >/etc/logrotate.d/maillog << EOF
/var/log/mail/mail.log
{
compress
copytruncate
delaycompress
rotate 4
${LOGROTATE_INTERVAL}
}
EOF
}
function _setup_mail_summary() {

View File

@ -24,6 +24,7 @@ function _setup_save_states() {
[[ ${ENABLE_FAIL2BAN} -eq 1 ]] && SERVICEDIRS+=('lib/fail2ban')
[[ ${ENABLE_FETCHMAIL} -eq 1 ]] && SERVICEDIRS+=('lib/fetchmail')
[[ ${ENABLE_GETMAIL} -eq 1 ]] && SERVICEDIRS+=('lib/getmail')
[[ ${ENABLE_MTA_STS} -eq 1 ]] && SERVICEDIRS+=('lib/mta-sts')
[[ ${ENABLE_POSTGREY} -eq 1 ]] && SERVICEDIRS+=('lib/postgrey')
[[ ${ENABLE_RSPAMD} -eq 1 ]] && SERVICEDIRS+=('lib/rspamd')
[[ ${ENABLE_RSPAMD_REDIS} -eq 1 ]] && SERVICEDIRS+=('lib/redis')
@ -84,6 +85,7 @@ function _setup_save_states() {
[[ ${ENABLE_AMAVIS} -eq 1 ]] && chown -R amavis:amavis "${STATEDIR}/lib-amavis"
[[ ${ENABLE_CLAMAV} -eq 1 ]] && chown -R clamav:clamav "${STATEDIR}/lib-clamav"
[[ ${ENABLE_FETCHMAIL} -eq 1 ]] && chown -R fetchmail:nogroup "${STATEDIR}/lib-fetchmail"
[[ ${ENABLE_MTA_STS} -eq 1 ]] && chown -R _mta-sts:_mta-sts "${STATEDIR}/lib-mta-sts"
[[ ${ENABLE_POSTGREY} -eq 1 ]] && chown -R postgrey:postgrey "${STATEDIR}/lib-postgrey"
[[ ${ENABLE_RSPAMD} -eq 1 ]] && chown -R _rspamd:_rspamd "${STATEDIR}/lib-rspamd"
[[ ${ENABLE_RSPAMD_REDIS} -eq 1 ]] && chown -R redis:redis "${STATEDIR}/lib-redis"
@ -105,10 +107,10 @@ function _setup_save_states() {
# These two require the postdrop(103) group:
chgrp -R postdrop "${STATEDIR}"/spool-postfix/{maildrop,public}
# After changing the group, special bits (set-gid, sticky) may be stripped, restore them:
# Ref: https://github.com/docker-mailserver/docker-mailserver/pull/3149#issuecomment-1454981309
chmod 1730 "${STATEDIR}/spool-postfix/maildrop"
chmod 2710 "${STATEDIR}/spool-postfix/public"
# These permissions rely on the `postdrop` binary having the SGID bit set.
# Ref: https://github.com/docker-mailserver/docker-mailserver/pull/3625
chmod 730 "${STATEDIR}/spool-postfix/maildrop"
chmod 710 "${STATEDIR}/spool-postfix/public"
elif [[ ${ONE_DIR} -eq 1 ]]; then
_log 'warn' "'ONE_DIR=1' but no volume was mounted to '${STATEDIR}'"
else

View File

@ -0,0 +1,7 @@
#!/bin/bash
function _setup_mta_sts() {
_log 'trace' 'Adding MTA-STS lookup to the Postfix TLS policy map'
_add_to_or_update_postfix_main smtp_tls_policy_maps 'socketmap:unix:/var/run/mta-sts/daemon.sock:postfix'
}

View File

@ -0,0 +1,11 @@
#!/bin/bash
function _setup_oauth2() {
_log 'debug' 'Setting up OAUTH2'
# Enable OAuth2 PassDB (Authentication):
sedfile -i -e '/\!include auth-oauth2\.conf\.ext/s/^#//' /etc/dovecot/conf.d/10-auth.conf
_replace_by_env_in_file 'OAUTH2_' '/etc/dovecot/dovecot-oauth2.conf.ext'
return 0
}

View File

@ -19,9 +19,6 @@ function _setup_postfix_early() {
postconf "inet_protocols = ${POSTFIX_INET_PROTOCOLS}"
fi
__postfix__log 'trace' "Disabling SMTPUTF8 support"
postconf 'smtputf8_enable = no'
__postfix__log 'trace' "Configuring SASLauthd"
if [[ ${ENABLE_SASLAUTHD} -eq 1 ]] && [[ ! -f /etc/postfix/sasl/smtpd.conf ]]; then
cat >/etc/postfix/sasl/smtpd.conf << EOF
@ -30,18 +27,25 @@ mech_list: plain login
EOF
fi
# User has explicitly requested to disable SASL auth:
# TODO: Additive config by feature would be better. Should only enable SASL auth
# on submission(s) services in master.cf when SASLAuthd or Dovecot is enabled.
if [[ ${ENABLE_SASLAUTHD} -eq 0 ]] && [[ ${SMTP_ONLY} -eq 1 ]]; then
# Default for services (eg: Port 25); NOTE: This has since become the default:
sed -i -E \
's|^smtpd_sasl_auth_enable =.*|smtpd_sasl_auth_enable = no|g' \
/etc/postfix/main.cf
# Submission services that are explicitly enabled by default:
sed -i -E \
's|^ -o smtpd_sasl_auth_enable=.*| -o smtpd_sasl_auth_enable=no|g' \
/etc/postfix/master.cf
fi
# scripts/helpers/aliases.sh:_create_aliases()
__postfix__log 'trace' 'Setting up aliases'
_create_aliases
# scripts/helpers/postfix.sh:_create_postfix_vhost()
__postfix__log 'trace' 'Setting up Postfix vhost'
_create_postfix_vhost
@ -63,6 +67,25 @@ EOF
's|^(dms_smtpd_sender_restrictions = .*)|\1, reject_unknown_client_hostname|' \
/etc/postfix/main.cf
fi
# Dovecot feature integration
# TODO: Alias SMTP_ONLY=0 to DOVECOT_ENABLED=1?
if [[ ${SMTP_ONLY} -ne 1 ]]; then
__postfix__log 'trace' 'Configuring Postfix with Dovecot integration'
# /etc/postfix/vmailbox is created by: scripts/helpers/accounts.sh:_create_accounts()
# This file config is for Postfix to verify a mail account exists before accepting
# mail arriving and delivering it to Dovecot over LMTP.
if [[ ${ACCOUNT_PROVISIONER} == 'FILE' ]]; then
postconf 'virtual_mailbox_maps = texthash:/etc/postfix/vmailbox'
fi
postconf 'virtual_transport = lmtp:unix:/var/run/dovecot/lmtp'
fi
if [[ -n ${POSTFIX_DAGENT} ]]; then
__postfix__log 'trace' "Changing virtual transport to '${POSTFIX_DAGENT}'"
postconf "virtual_transport = ${POSTFIX_DAGENT}"
fi
}
function _setup_postfix_late() {
@ -80,12 +103,6 @@ function _setup_postfix_late() {
__postfix__log 'trace' 'Configuring relay host'
_setup_relayhost
if [[ -n ${POSTFIX_DAGENT} ]]; then
__postfix__log 'trace' "Changing virtual transport to '${POSTFIX_DAGENT}'"
# Default value in main.cf should be 'lmtp:unix:/var/run/dovecot/lmtp'
postconf "virtual_transport = ${POSTFIX_DAGENT}"
fi
__postfix__setup_override_configuration
}

View File

@ -1,29 +1,29 @@
#!/bin/bash
function _setup_saslauthd() {
_log 'debug' 'Setting up SASLAUTHD'
if [[ ! -f /etc/saslauthd.conf ]]; then
# NOTE: It's unlikely this file would already exist,
# Unlike Dovecot/Postfix LDAP support, this file has no ENV replacement
# nor does it copy from the DMS config volume to this internal location.
if [[ ${ACCOUNT_PROVISIONER} == 'LDAP' ]] \
&& [[ ! -f /etc/saslauthd.conf ]]; then
_log 'trace' 'Creating /etc/saslauthd.conf'
cat > /etc/saslauthd.conf << EOF
ldap_servers: ${SASLAUTHD_LDAP_SERVER}
ldap_auth_method: ${SASLAUTHD_LDAP_AUTH_METHOD}
ldap_bind_dn: ${SASLAUTHD_LDAP_BIND_DN}
ldap_bind_pw: ${SASLAUTHD_LDAP_PASSWORD}
ldap_search_base: ${SASLAUTHD_LDAP_SEARCH_BASE}
ldap_filter: ${SASLAUTHD_LDAP_FILTER}
ldap_start_tls: ${SASLAUTHD_LDAP_START_TLS}
ldap_tls_check_peer: ${SASLAUTHD_LDAP_TLS_CHECK_PEER}
${SASLAUTHD_LDAP_TLS_CACERT_FILE}
${SASLAUTHD_LDAP_TLS_CACERT_DIR}
${SASLAUTHD_LDAP_PASSWORD_ATTR}
${SASLAUTHD_LDAP_MECH}
# Create a config based on ENV
sed '/^.*: $/d'> /etc/saslauthd.conf << EOF
ldap_servers: ${SASLAUTHD_LDAP_SERVER:=${LDAP_SERVER_HOST}}
ldap_auth_method: ${SASLAUTHD_LDAP_AUTH_METHOD:=bind}
ldap_bind_dn: ${SASLAUTHD_LDAP_BIND_DN:=${LDAP_BIND_DN}}
ldap_bind_pw: ${SASLAUTHD_LDAP_PASSWORD:=${LDAP_BIND_PW}}
ldap_search_base: ${SASLAUTHD_LDAP_SEARCH_BASE:=${LDAP_SEARCH_BASE}}
ldap_filter: ${SASLAUTHD_LDAP_FILTER:=(&(uniqueIdentifier=%u)(mailEnabled=TRUE))}
ldap_start_tls: ${SASLAUTHD_LDAP_START_TLS:=no}
ldap_tls_check_peer: ${SASLAUTHD_LDAP_TLS_CHECK_PEER:=no}
ldap_tls_cacert_file: ${SASLAUTHD_LDAP_TLS_CACERT_FILE}
ldap_tls_cacert_dir: ${SASLAUTHD_LDAP_TLS_CACERT_DIR}
ldap_password_attr: ${SASLAUTHD_LDAP_PASSWORD_ATTR}
ldap_mech: ${SASLAUTHD_LDAP_MECH}
ldap_referrals: yes
log_level: 10
EOF
@ -42,4 +42,3 @@ EOF
gpasswd -a postfix sasl >/dev/null
}

View File

@ -70,6 +70,8 @@ function __setup__security__spamassassin() {
if [[ ${ENABLE_SPAMASSASSIN} -eq 1 ]]; then
_log 'debug' 'Enabling and configuring SpamAssassin'
# Maintainers should take care in attempting to change these sed commands. Alternatives were already explored:
# https://github.com/docker-mailserver/docker-mailserver/pull/3767#issuecomment-1885989591
# shellcheck disable=SC2016
sed -i -r 's|^\$sa_tag_level_deflt (.*);|\$sa_tag_level_deflt = '"${SA_TAG}"';|g' /etc/amavis/conf.d/20-debian_defaults
@ -111,7 +113,7 @@ function __setup__security__spamassassin() {
if [[ ${SPAMASSASSIN_SPAM_TO_INBOX} -eq 1 ]]; then
_log 'trace' 'Configuring Spamassassin/Amavis to send SPAM to inbox'
_log 'debug' 'SPAM_TO_INBOX=1 is set. SA_KILL will be ignored.'
_log 'debug' "'SPAMASSASSIN_SPAM_TO_INBOX=1' is set. The 'SA_KILL' ENV will be ignored."
sed -i "s|\$final_spam_destiny.*=.*$|\$final_spam_destiny = D_PASS;|g" /etc/amavis/conf.d/49-docker-mailserver
sed -i "s|\$final_bad_header_destiny.*=.*$|\$final_bad_header_destiny = D_PASS;|g" /etc/amavis/conf.d/49-docker-mailserver
@ -265,9 +267,34 @@ EOF
chown dovecot:root /usr/lib/dovecot/sieve-global/after/spam_to_junk.{sieve,svbin}
if [[ ${ENABLE_SPAMASSASSIN} -eq 1 ]] && [[ ${SPAMASSASSIN_SPAM_TO_INBOX} -eq 0 ]]; then
_log 'warning' "'SPAMASSASSIN_SPAM_TO_INBOX=0' but it is required to be 1 for 'MOVE_SPAM_TO_JUNK=1' to work"
_log 'warn' "'SPAMASSASSIN_SPAM_TO_INBOX=0' but it is required to be 1 for 'MOVE_SPAM_TO_JUNK=1' to work"
fi
else
_log 'debug' 'Spam emails will not be moved to the Junk folder'
fi
}
function _setup_spam_mark_as_read() {
if [[ ${MARK_SPAM_AS_READ} -eq 1 ]]; then
_log 'debug' 'Spam emails will be marked as read'
mkdir -p /usr/lib/dovecot/sieve-global/after/
# Header support: `X-Spam-Flag` (SpamAssassin), `X-Spam` (Rspamd)
cat >/usr/lib/dovecot/sieve-global/after/spam_mark_as_read.sieve << EOF
require ["mailbox","imap4flags"];
if anyof (header :contains "X-Spam-Flag" "YES",
header :contains "X-Spam" "Yes") {
setflag "\\\\Seen";
}
EOF
sievec /usr/lib/dovecot/sieve-global/after/spam_mark_as_read.sieve
chown dovecot:root /usr/lib/dovecot/sieve-global/after/spam_mark_as_read.{sieve,svbin}
if [[ ${ENABLE_SPAMASSASSIN} -eq 1 ]] && [[ ${SPAMASSASSIN_SPAM_TO_INBOX} -eq 0 ]]; then
_log 'warn' "'SPAMASSASSIN_SPAM_TO_INBOX=0' but it is required to be 1 for 'MARK_SPAM_AS_READ=1' to work"
fi
else
_log 'debug' 'Spam emails will not be marked as read'
fi
}

View File

@ -1,12 +1,18 @@
#!/bin/bash
# Function called during global setup to handle the complete setup of Rspamd.
# This file is executed during startup of DMS. Hence, the `index.sh` helper has already
# been sourced, and thus, all helper functions from `rspamd.sh` are available.
# Function called during global setup to handle the complete setup of Rspamd. Functions
# with a single `_` prefix are sourced from the `rspamd.sh` helper.
function _setup_rspamd() {
if _env_var_expect_zero_or_one 'ENABLE_RSPAMD' && [[ ${ENABLE_RSPAMD} -eq 1 ]]; then
_log 'debug' 'Enabling and configuring Rspamd'
__rspamd__log 'trace' '---------- Setup started ----------'
__rspamd__run_early_setup_and_checks # must run first
_rspamd_get_envs # must run first
__rspamd__run_early_setup_and_checks # must run second
__rspamd__setup_logfile
__rspamd__setup_redis
__rspamd__setup_postfix
__rspamd__setup_clamav
@ -14,7 +20,11 @@ function _setup_rspamd() {
__rspamd__setup_learning
__rspamd__setup_greylisting
__rspamd__setup_hfilter_group
__rspamd__handle_user_modules_adjustments # must run last
__rspamd__setup_check_authenticated
_rspamd_handle_user_modules_adjustments # must run last
# only performing checks, no further setup handled from here onwards
__rspamd__check_dkim_permissions
__rspamd__log 'trace' '---------- Setup finished ----------'
else
@ -41,6 +51,8 @@ function __rspamd__helper__enable_disable_module() {
local LOCAL_OR_OVERRIDE=${3:-local}
local MESSAGE='Enabling'
readonly MODULE ENABLE_MODULE LOCAL_OR_OVERRIDE
if [[ ! ${ENABLE_MODULE} =~ ^(true|false)$ ]]; then
__rspamd__log 'warn' "__rspamd__helper__enable_disable_module got non-boolean argument for deciding whether module should be enabled or not"
return 1
@ -60,23 +72,11 @@ EOF
# Run miscellaneous early setup tasks and checks, such as creating files needed at runtime
# or checking for other anti-spam/anti-virus software.
function __rspamd__run_early_setup_and_checks() {
# Note: Variables not marked with `local` are
# used in other functions as well.
RSPAMD_LOCAL_D='/etc/rspamd/local.d'
RSPAMD_OVERRIDE_D='/etc/rspamd/override.d'
RSPAMD_DMS_D='/tmp/docker-mailserver/rspamd'
local RSPAMD_DMS_OVERRIDE_D="${RSPAMD_DMS_D}/override.d/"
mkdir -p /var/lib/rspamd/
: >/var/lib/rspamd/stats.ucl
if [[ -d ${RSPAMD_DMS_OVERRIDE_D} ]]; then
__rspamd__log 'debug' "Found directory '${RSPAMD_DMS_OVERRIDE_D}' - linking it to '${RSPAMD_OVERRIDE_D}'"
if rmdir "${RSPAMD_OVERRIDE_D}" 2>/dev/null; then
ln -s "${RSPAMD_DMS_OVERRIDE_D}" "${RSPAMD_OVERRIDE_D}"
else
__rspamd__log 'warn' "Could not remove '${RSPAMD_OVERRIDE_D}' (not empty? not a directory?; did you restart properly?) - not linking '${RSPAMD_DMS_OVERRIDE_D}'"
fi
cp "${RSPAMD_DMS_OVERRIDE_D}"/* "${RSPAMD_OVERRIDE_D}"
fi
if [[ ${ENABLE_AMAVIS} -eq 1 ]] || [[ ${ENABLE_SPAMASSASSIN} -eq 1 ]]; then
@ -100,6 +100,20 @@ function __rspamd__run_early_setup_and_checks() {
fi
}
# Keep in sync with `target/scripts/startup/setup.d/log.sh:_setup_logrotate()`
function __rspamd__setup_logfile() {
cat >/etc/logrotate.d/rspamd << EOF
/var/log/mail/rspamd.log
{
compress
copytruncate
delaycompress
rotate 4
${LOGROTATE_INTERVAL}
}
EOF
}
# Sets up Redis. In case the user does not use a dedicated Redis instance, we
# supply a configuration for our local Redis instance which is started later.
function __rspamd__setup_redis() {
@ -137,7 +151,7 @@ function __rspamd__setup_postfix() {
postconf 'rspamd_milter = inet:localhost:11332'
# shellcheck disable=SC2016
sed -i -E 's|^(smtpd_milters =.*)|\1 \$rspamd_milter|g' /etc/postfix/main.cf
_add_to_or_update_postfix_main 'smtpd_milters' '$rspamd_milter'
}
# If ClamAV is enabled, we will integrate it into Rspamd.
@ -179,6 +193,8 @@ function __rspamd__setup_default_modules() {
metric_exporter
)
readonly -a DISABLE_MODULES
local MODULE
for MODULE in "${DISABLE_MODULES[@]}"; do
__rspamd__helper__enable_disable_module "${MODULE}" 'false'
done
@ -194,6 +210,7 @@ function __rspamd__setup_learning() {
__rspamd__log 'debug' 'Setting up intelligent learning of spam and ham'
local SIEVE_PIPE_BIN_DIR='/usr/lib/dovecot/sieve-pipe'
readonly SIEVE_PIPE_BIN_DIR
ln -s "$(type -f -P rspamc)" "${SIEVE_PIPE_BIN_DIR}/rspamc"
sedfile -i -E 's|(mail_plugins =.*)|\1 imap_sieve|' /etc/dovecot/conf.d/20-imap.conf
@ -247,10 +264,12 @@ function __rspamd__setup_greylisting() {
# succeeds.
function __rspamd__setup_hfilter_group() {
local MODULE_FILE="${RSPAMD_LOCAL_D}/hfilter_group.conf"
readonly MODULE_FILE
if _env_var_expect_zero_or_one 'RSPAMD_HFILTER' && [[ ${RSPAMD_HFILTER} -eq 1 ]]; then
__rspamd__log 'debug' 'Hfilter (group) module is enabled'
# Check if we received a number first
if _env_var_expect_integer 'RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE' && [[ ${RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE} -ne 6 ]]; then
if _env_var_expect_integer 'RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE' \
&& [[ ${RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE} -ne 6 ]]; then
__rspamd__log 'trace' "Adjusting score for 'HFILTER_HOSTNAME_UNKNOWN' in Hfilter group module to ${RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE}"
sed -i -E \
"s|(.*score =).*(# __TAG__HFILTER_HOSTNAME_UNKNOWN)|\1 ${RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE}; \2|g" \
@ -264,95 +283,55 @@ function __rspamd__setup_hfilter_group() {
fi
}
# Parses `RSPAMD_CUSTOM_COMMANDS_FILE` and executed the directives given by the file.
# To get a detailed explanation of the commands and how the file works, visit
# https://docker-mailserver.github.io/docker-mailserver/edge/config/security/rspamd/#with-the-help-of-a-custom-file
function __rspamd__handle_user_modules_adjustments() {
# Adds an option with a corresponding value to a module, or, in case the option
# is already present, overwrites it.
#
# @param ${1} = file name in ${RSPAMD_OVERRIDE_D}/
# @param ${2} = module name as it should appear in the log
# @patam ${3} = option name in the module
# @param ${4} = value of the option
#
# ## Note
#
# While this function is currently bound to the scope of `__rspamd__handle_user_modules_adjustments`,
# it is written in a versatile way (taking 4 arguments instead of assuming `ARGUMENT2` / `ARGUMENT3`
# are set) so that it may be used elsewhere if needed.
function __add_or_replace() {
local MODULE_FILE=${1:?Module file name must be provided}
local MODULE_LOG_NAME=${2:?Module log name must be provided}
local OPTION=${3:?Option name must be provided}
local VALUE=${4:?Value belonging to an option must be provided}
# remove possible whitespace at the end (e.g., in case ${ARGUMENT3} is empty)
VALUE=${VALUE% }
local FILE="${RSPAMD_OVERRIDE_D}/${MODULE_FILE}"
[[ -f ${FILE} ]] || touch "${FILE}"
if grep -q -E "${OPTION}.*=.*" "${FILE}"; then
__rspamd__log 'trace' "Overwriting option '${OPTION}' with value '${VALUE}' for ${MODULE_LOG_NAME}"
sed -i -E "s|([[:space:]]*${OPTION}).*|\1 = ${VALUE};|g" "${FILE}"
else
__rspamd__log 'trace' "Setting option '${OPTION}' for ${MODULE_LOG_NAME} to '${VALUE}'"
echo "${OPTION} = ${VALUE};" >>"${FILE}"
fi
}
local RSPAMD_CUSTOM_COMMANDS_FILE="${RSPAMD_DMS_D}/custom-commands.conf"
local RSPAMD_CUSTOM_COMMANDS_FILE_OLD="${RSPAMD_DMS_D}-modules.conf"
# We check for usage of the previous location of the commands file.
# This can be removed after the release of v14.0.0.
if [[ -f ${RSPAMD_CUSTOM_COMMANDS_FILE_OLD} ]]; then
__rspamd__log 'warn' "Detected usage of old file location for modules adjustment ('${RSPAMD_CUSTOM_COMMANDS_FILE_OLD}') - please use the new location ('${RSPAMD_CUSTOM_COMMANDS_FILE}')"
__rspamd__log 'warn' "Using old file location now (deprecated) - this will prevent startup in v13.0.0"
RSPAMD_CUSTOM_COMMANDS_FILE=${RSPAMD_CUSTOM_COMMANDS_FILE_OLD}
fi
if [[ -f "${RSPAMD_CUSTOM_COMMANDS_FILE}" ]]; then
__rspamd__log 'debug' "Found file '${RSPAMD_CUSTOM_COMMANDS_FILE}' - parsing and applying it"
while read -r COMMAND ARGUMENT1 ARGUMENT2 ARGUMENT3; do
case "${COMMAND}" in
('disable-module')
__rspamd__helper__enable_disable_module "${ARGUMENT1}" 'false' 'override'
;;
('enable-module')
__rspamd__helper__enable_disable_module "${ARGUMENT1}" 'true' 'override'
;;
('set-option-for-module')
__add_or_replace "${ARGUMENT1}.conf" "module '${ARGUMENT1}'" "${ARGUMENT2}" "${ARGUMENT3}"
;;
('set-option-for-controller')
__add_or_replace 'worker-controller.inc' 'controller worker' "${ARGUMENT1}" "${ARGUMENT2} ${ARGUMENT3}"
;;
('set-option-for-proxy')
__add_or_replace 'worker-proxy.inc' 'proxy worker' "${ARGUMENT1}" "${ARGUMENT2} ${ARGUMENT3}"
;;
('set-common-option')
__add_or_replace 'options.inc' 'common options' "${ARGUMENT1}" "${ARGUMENT2} ${ARGUMENT3}"
;;
('add-line')
__rspamd__log 'trace' "Adding complete line to '${ARGUMENT1}'"
echo "${ARGUMENT2}${ARGUMENT3+ ${ARGUMENT3}}" >>"${RSPAMD_OVERRIDE_D}/${ARGUMENT1}"
;;
(*)
__rspamd__log 'warn' "Command '${COMMAND}' is invalid"
continue
;;
esac
done < <(_get_valid_lines_from_file "${RSPAMD_CUSTOM_COMMANDS_FILE}")
# If 'RSPAMD_CHECK_AUTHENTICATED' is enabled, then content checks for all users, i.e.
# also for authenticated users, are performed.
#
# The default that DMS ships does not check authenticated users. In case the checks are
# enabled, this function will remove the part of the Rspamd configuration that disables
# checks for authenticated users.
function __rspamd__setup_check_authenticated() {
local MODULE_FILE="${RSPAMD_LOCAL_D}/settings.conf"
readonly MODULE_FILE
if _env_var_expect_zero_or_one 'RSPAMD_CHECK_AUTHENTICATED' \
&& [[ ${RSPAMD_CHECK_AUTHENTICATED} -eq 0 ]]
then
__rspamd__log 'debug' 'Content checks for authenticated users are disabled'
else
__rspamd__log 'debug' 'Enabling content checks for authenticated users'
sed -i -E \
'/DMS::SED_TAG::1::START/{:a;N;/DMS::SED_TAG::1::END/!ba};/authenticated/d' \
"${MODULE_FILE}"
fi
}
# This function performs a simple check: go through DKIM configuration files, acquire
# all private key file locations and check whether they exist and whether they can be
# accessed by Rspamd.
function __rspamd__check_dkim_permissions() {
local DKIM_CONF_FILES DKIM_KEY_FILES
[[ -f ${RSPAMD_LOCAL_D}/dkim_signing.conf ]] && DKIM_CONF_FILES+=("${RSPAMD_LOCAL_D}/dkim_signing.conf")
[[ -f ${RSPAMD_OVERRIDE_D}/dkim_signing.conf ]] && DKIM_CONF_FILES+=("${RSPAMD_OVERRIDE_D}/dkim_signing.conf")
# Here, we populate DKIM_KEY_FILES which we later iterate over. DKIM_KEY_FILES
# contains all keys files configured by the user.
local FILE
for FILE in "${DKIM_CONF_FILES[@]}"; do
readarray -t DKIM_KEY_FILES_TMP < <(grep -o -E 'path = .*' "${FILE}" | cut -d '=' -f 2 | tr -d ' ";')
DKIM_KEY_FILES+=("${DKIM_KEY_FILES_TMP[@]}")
done
for FILE in "${DKIM_KEY_FILES[@]}"; do
if [[ -f ${FILE} ]]; then
__rspamd__log 'trace' "Checking DKIM file '${FILE}'"
# See https://serverfault.com/a/829314 for an explanation on `-exec false {} +`
# We additionally resolve symbolic links to check the permissions of the actual files
if find "$(realpath -eL "${FILE}")" \( -user _rspamd -or -group _rspamd -or -perm -o=r \) -exec false {} +; then
__rspamd__log 'warn' "Rspamd DKIM private key file '${FILE}' does not appear to have correct permissions/ownership for Rspamd to use it"
else
__rspamd__log 'trace' "DKIM file '${FILE}' permissions and ownership appear correct"
fi
else
__rspamd__log 'warn' "Rspamd DKIM private key file '${FILE}' is configured for usage, but does not appear to exist"
fi
done
}

View File

@ -11,6 +11,9 @@ function _setup_spoof_protection() {
postconf 'smtpd_sender_login_maps = ldap:/etc/postfix/ldap-senders.cf'
fi
else
# NOTE: This file is always created at startup, it potentially has content added.
# TODO: From section: "SPOOF_PROTECTION=1 handling for smtpd_sender_login_maps"
# https://github.com/docker-mailserver/docker-mailserver/issues/2819#issue-1402114383
if [[ -f /etc/postfix/regexp ]]; then
postconf 'smtpd_sender_login_maps = unionmap:{ texthash:/etc/postfix/virtual, hash:/etc/aliases, pcre:/etc/postfix/maps/sender_login_maps.pcre, pcre:/etc/postfix/regexp }'
else

View File

@ -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
}

View File

@ -14,8 +14,15 @@ function _early_variables_setup() {
# completely with a single version.
function __environment_variables_backwards_compatibility() {
if [[ ${ENABLE_LDAP:-0} -eq 1 ]]; then
_log 'warn' "'ENABLE_LDAP=1' is deprecated (and will be removed in v13.0.0) => use 'ACCOUNT_PROVISIONER=LDAP' instead"
ACCOUNT_PROVISIONER='LDAP'
_log 'error' "'ENABLE_LDAP=1' has been changed to 'ACCOUNT_PROVISIONER=LDAP' since DMS v13"
fi
# Dovecot and SASLAuthd have applied an 'ldap://' fallback for compatibility since v10 (June 2021)
# This was silently applied, but users should be explicit:
if [[ ${LDAP_SERVER_HOST:-'://'} != *'://'* ]] \
|| [[ ${DOVECOT_URIS:-'://'} != *'://'* ]] \
|| [[ ${SASLAUTHD_LDAP_SERVER:-'://'} != *'://'* ]]; then
_log 'error' "The ENV for which LDAP host to connect to must include the URI scheme ('ldap://', 'ldaps://', 'ldapi://')"
fi
# TODO this can be uncommented in a PR handling the HOSTNAME/DOMAINNAME issue
@ -39,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'
@ -46,11 +55,13 @@ function __environment_variables_general_setup() {
VARS[CLAMAV_MESSAGE_SIZE_LIMIT]="${CLAMAV_MESSAGE_SIZE_LIMIT:=25M}"
VARS[FAIL2BAN_BLOCKTYPE]="${FAIL2BAN_BLOCKTYPE:=drop}"
VARS[MOVE_SPAM_TO_JUNK]="${MOVE_SPAM_TO_JUNK:=1}"
VARS[MARK_SPAM_AS_READ]="${MARK_SPAM_AS_READ:=0}"
VARS[POSTGREY_AUTO_WHITELIST_CLIENTS]="${POSTGREY_AUTO_WHITELIST_CLIENTS:=5}"
VARS[POSTGREY_DELAY]="${POSTGREY_DELAY:=300}"
VARS[POSTGREY_MAX_AGE]="${POSTGREY_MAX_AGE:=35}"
VARS[POSTGREY_TEXT]="${POSTGREY_TEXT:=Delayed by Postgrey}"
VARS[POSTSCREEN_ACTION]="${POSTSCREEN_ACTION:=enforce}"
VARS[RSPAMD_CHECK_AUTHENTICATED]="${RSPAMD_CHECK_AUTHENTICATED:=0}"
VARS[RSPAMD_GREYLISTING]="${RSPAMD_GREYLISTING:=0}"
VARS[RSPAMD_HFILTER]="${RSPAMD_HFILTER:=1}"
VARS[RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE]="${RSPAMD_HFILTER_HOSTNAME_UNKNOWN_SCORE:=6}"
@ -72,10 +83,12 @@ function __environment_variables_general_setup() {
VARS[ENABLE_FETCHMAIL]="${ENABLE_FETCHMAIL:=0}"
VARS[ENABLE_GETMAIL]="${ENABLE_GETMAIL:=0}"
VARS[ENABLE_MANAGESIEVE]="${ENABLE_MANAGESIEVE:=0}"
VARS[ENABLE_OAUTH2]="${ENABLE_OAUTH2:=0}"
VARS[ENABLE_OPENDKIM]="${ENABLE_OPENDKIM:=1}"
VARS[ENABLE_OPENDMARC]="${ENABLE_OPENDMARC:=1}"
VARS[ENABLE_POLICYD_SPF]="${ENABLE_POLICYD_SPF:=1}"
VARS[ENABLE_POP3]="${ENABLE_POP3:=0}"
VARS[ENABLE_IMAP]="${ENABLE_IMAP:=1}"
VARS[ENABLE_POSTGREY]="${ENABLE_POSTGREY:=0}"
VARS[ENABLE_QUOTAS]="${ENABLE_QUOTAS:=1}"
VARS[ENABLE_RSPAMD]="${ENABLE_RSPAMD:=0}"
@ -139,7 +152,14 @@ function __environment_variables_general_setup() {
VARS[UPDATE_CHECK_INTERVAL]="${UPDATE_CHECK_INTERVAL:=1d}"
}
function _environment_variables_oauth2() {
_log 'debug' 'Setting OAUTH2-related environment variables now'
VARS[OAUTH2_INTROSPECTION_URL]="${OAUTH2_INTROSPECTION_URL:=}"
}
# This function handles environment variables related to LDAP.
# NOTE: SASLAuthd and Dovecot LDAP support inherit these common ENV.
function _environment_variables_ldap() {
_log 'debug' 'Setting LDAP-related environment variables now'
@ -151,55 +171,12 @@ function _environment_variables_ldap() {
}
# This function handles environment variables related to SASLAUTHD
# and, if activated, variables related to SASLAUTHD and LDAP.
# LDAP specific ENV handled in: `startup/setup.d/saslauthd.sh:_setup_saslauthd()`
function _environment_variables_saslauthd() {
_log 'debug' 'Setting SASLAUTHD-related environment variables now'
# Only used by the supervisor service command (upstream default: `/etc/default/saslauthd`)
VARS[SASLAUTHD_MECHANISMS]="${SASLAUTHD_MECHANISMS:=pam}"
# SASL ENV for configuring an LDAP specific
# `saslauthd.conf` via `setup-stack.sh:_setup_sasulauthd()`
if [[ ${ACCOUNT_PROVISIONER} == 'LDAP' ]]; then
_log 'trace' 'Setting SASLSAUTH-LDAP variables nnow'
VARS[SASLAUTHD_LDAP_AUTH_METHOD]="${SASLAUTHD_LDAP_AUTH_METHOD:=bind}"
VARS[SASLAUTHD_LDAP_BIND_DN]="${SASLAUTHD_LDAP_BIND_DN:=${LDAP_BIND_DN}}"
VARS[SASLAUTHD_LDAP_FILTER]="${SASLAUTHD_LDAP_FILTER:=(&(uniqueIdentifier=%u)(mailEnabled=TRUE))}"
VARS[SASLAUTHD_LDAP_PASSWORD]="${SASLAUTHD_LDAP_PASSWORD:=${LDAP_BIND_PW}}"
VARS[SASLAUTHD_LDAP_SEARCH_BASE]="${SASLAUTHD_LDAP_SEARCH_BASE:=${LDAP_SEARCH_BASE}}"
VARS[SASLAUTHD_LDAP_SERVER]="${SASLAUTHD_LDAP_SERVER:=${LDAP_SERVER_HOST}}"
[[ ${SASLAUTHD_LDAP_SERVER} != *'://'* ]] && SASLAUTHD_LDAP_SERVER="ldap://${SASLAUTHD_LDAP_SERVER}"
VARS[SASLAUTHD_LDAP_START_TLS]="${SASLAUTHD_LDAP_START_TLS:=no}"
VARS[SASLAUTHD_LDAP_TLS_CHECK_PEER]="${SASLAUTHD_LDAP_TLS_CHECK_PEER:=no}"
if [[ -z ${SASLAUTHD_LDAP_TLS_CACERT_FILE} ]]; then
SASLAUTHD_LDAP_TLS_CACERT_FILE=''
else
SASLAUTHD_LDAP_TLS_CACERT_FILE="ldap_tls_cacert_file: ${SASLAUTHD_LDAP_TLS_CACERT_FILE}"
fi
VARS[SASLAUTHD_LDAP_TLS_CACERT_FILE]="${SASLAUTHD_LDAP_TLS_CACERT_FILE}"
if [[ -z ${SASLAUTHD_LDAP_TLS_CACERT_DIR} ]]; then
SASLAUTHD_LDAP_TLS_CACERT_DIR=''
else
SASLAUTHD_LDAP_TLS_CACERT_DIR="ldap_tls_cacert_dir: ${SASLAUTHD_LDAP_TLS_CACERT_DIR}"
fi
VARS[SASLAUTHD_LDAP_TLS_CACERT_DIR]="${SASLAUTHD_LDAP_TLS_CACERT_DIR}"
if [[ -z ${SASLAUTHD_LDAP_PASSWORD_ATTR} ]]; then
SASLAUTHD_LDAP_PASSWORD_ATTR=''
else
SASLAUTHD_LDAP_PASSWORD_ATTR="ldap_password_attr: ${SASLAUTHD_LDAP_PASSWORD_ATTR}"
fi
VARS[SASLAUTHD_LDAP_PASSWORD_ATTR]="${SASLAUTHD_LDAP_PASSWORD_ATTR}"
if [[ -z ${SASLAUTHD_LDAP_MECH} ]]; then
SASLAUTHD_LDAP_MECH=''
else
SASLAUTHD_LDAP_MECH="ldap_mech: ${SASLAUTHD_LDAP_MECH}"
fi
VARS[SASLAUTHD_LDAP_MECH]="${SASLAUTHD_LDAP_MECH}"
fi
}
# This function Writes the contents of the `VARS` map (associative array)

View File

@ -3,8 +3,8 @@
# shellcheck source=./helpers/log.sh
source /usr/local/bin/helpers/log.sh
VERSION=$(</VERSION)
VERSION_URL='https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/VERSION'
VERSION="${DMS_RELEASE#v}"
VERSION_URL='https://github.com/docker-mailserver/docker-mailserver/releases/latest'
CHANGELOG_URL='https://github.com/docker-mailserver/docker-mailserver/blob/master/CHANGELOG.md'
# check for correct syntax
@ -17,7 +17,8 @@ fi
while true; do
# get remote version information
LATEST=$(curl -Lsf "${VERSION_URL}")
# JSON response provides a field for the release tag, the `v` prefix is removed with `[1:]`
LATEST=$(curl -sfL -H 'accept: application/json' "${VERSION_URL}" | jaq -r '.tag_name[1:]')
# did we get a valid response?
if [[ ${LATEST} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
@ -26,7 +27,7 @@ while true; do
# compare versions
if dpkg --compare-versions "${VERSION}" lt "${LATEST}"; then
# send mail notification to postmaster
read -r -d '' MAIL << EOF
read -r -d '#' MAIL << EOF
Hello ${POSTMASTER_ADDRESS}!
There is a docker-mailserver update available on your host: $(hostname -f)
@ -34,7 +35,7 @@ There is a docker-mailserver update available on your host: $(hostname -f)
Current version: ${VERSION}
Latest version: ${LATEST}
Changelog: ${CHANGELOG_URL}
Changelog: ${CHANGELOG_URL}#END
EOF
_log_with_date 'info' "Update available [ ${VERSION} --> ${LATEST} ]"

Some files were not shown because too many files have changed in this diff Show More