Huge role refactoring/cleanup. Other commits will propably follow. Because some bugs will exist. Still important for longrun and also for auto docs/help/slideshow generation

This commit is contained in:
2025-07-08 23:43:13 +02:00
parent 6b87a049d4
commit 563d5fd528
1242 changed files with 2301 additions and 1355 deletions

View File

@@ -0,0 +1,53 @@
# Administration 🕵️‍♂️
## Database Access 📂
To access the database, use the following command:
```bash
docker-compose exec -it database mysql -u root -D mailu -p
```
## Container Access 🖥️
To access the front container, use this command:
```bash
docker-compose exec -it front /bin/bash
```
## Restarting Services 🔄
To restart all services, use the following command:
```bash
docker-compose restart
```
## Resending Queued Mails ✉️
To resend queued mails, use this command:
```bash
docker-compose exec -it smtp postqueue -f
```
# Updates 🔄
For instructions on updating your Mailu setup, follow the official [Mailu maintenance guide](https://mailu.io/master/maintain.html).
# Queue Management 📬
To manage the Postfix email queue in Mailu, you can use the following commands:
- **Display the email queue**:
```bash
docker compose exec -it smtp postqueue -p
```
- **Delete all emails in the queue**:
```bash
docker compose exec -it smtp postsuper -d ALL
```

View File

@@ -0,0 +1,62 @@
# Installation ⚙️
## Fetchmail Issues 📨
Fetchmail might not work properly with large amounts of data. For more information, refer to this [issue](https://github.com/Mailu/Mailu/issues/1719).
## Deactivating Fetchmail ❌
Before uninstalling Fetchmail, ensure you remove all fetched accounts from the administration panel.
## Fetchmail Security Concerns 🔐
There are known security concerns with Fetchmail as stated in the [German Wikipedia](https://de.wikipedia.org/wiki/Fetchmail). If you require Fetchmail functions in the future, consider creating a Docker container for [Getmail](https://en.wikipedia.org/wiki/Getmail) as it is considered more secure.
## Fetchmail Workaround 🔄
If you need to receive emails from another account, follow these steps:
1. Redirect your emails to your new email account.
2. Export all data from your original account.
3. Import all data to your new account.
## Port Management 🌐
Check for any port conflicts and manually change the conflicting ports if necessary. Use the following command to verify:
```bash
netstat -tulpn
```
## Admin Account Creation 👤
To use Mailu, create the primary administrator user account, `admin@{{hostname}}`, using the command below. Replace `PASSWORD` with your preferred password:
```bash
docker-compose -p mailu exec admin flask mailu admin {{admin}} {{hostname}} PASSWORD
```
## CLI User Management 🛠️
For managing users, follow the instructions in the official [Mailu CLI documentation](https://mailu.io/master/cli.html).
## Starting the Server ▶️
To start the server, use the following command:
```bash
docker-compose -p mailu up -d
```
## OIDC Support 🔐
This role now supports OpenID Connect (OIDC) authentication with [Mailu-OIDC](https://github.com/heviat/Mailu-OIDC)! 🎉
To enable OIDC authentication, simply set the following variable:
```yaml
oidc:
enabled: true
```
For more details, check out the [Mailu-OIDC repository](https://github.com/heviat/Mailu-OIDC/tree/2024.06).

View File

@@ -0,0 +1,41 @@
# Mailu
## Description
Revolutionize your email communications with Mailu, a secure and flexible mail server solution that integrates comprehensive features like robust SMTP/IMAP support, advanced spam filtering, DKIM signing, and seamless webmail access. With its modern design and performance-oriented architecture, Mailu empowers you to manage digital correspondence with efficiency and reliability.
## Overview
Mailu is a complete mail server suite delivered as a Docker-based solution. It supports all essential email protocols, offers intuitive administration through a web interface, and integrates advanced security measures such as TLS encryption and virus scanning. Its modular architecture allows for scalable deployments and easy customization to suit diverse operational requirements.
For further details on installation, configuration, and upgrades, please refer to the following documentation files in this directory:
- [Installation.md](./Installation.md)
- [Upgrade.md](./Upgrade.md)
- [Spam_Issues.md](./Spam_Issues.md)
- [User_Administration.md](./User_Administration.md)
For more information about this role, visit the GitHub repositories:
- [Mailu](https://github.com/kevinveenbirkenbach/cymais/tree/master/roles/web-app-mailu)
- [Mailu-OIDC](https://github.com/heviat/Mailu-OIDC)
## Features
- **Comprehensive Email Protocols:** Supports SMTP, IMAP, and POP3 for reliable email delivery and retrieval.
- **Advanced Security:** Incorporates TLS encryption, DKIM, and SPF to secure your communications and prevent spoofing.
- **Integrated Spam Filtering and Antivirus:** Offers robust tools for spam detection and virus scanning, ensuring your inboxes remain clean and secure.
- **Customizable Webmail and Administration:** Provides a modern web interface for managing emails and administrative tasks with ease.
- **Flexible Deployment:** Easily scale and customize using Docker Compose, with configurable settings for networking, storage, and external services.
- **OIDC Support:** Optionally integrate with OpenID Connect for centralized authentication across your services.
## Further Resources
- [Mailu Official Website](https://mailu.io/)
- [Mailu compose setup guide](https://mailu.io/1.7/compose/setup.html)
- [SysPass issue #1299](https://github.com/nuxsmin/sysPass/issues/1299)
- [Mailu issue #1719](https://github.com/Mailu/Mailu/issues/1719)
- [Mailu issue #1171](https://github.com/Mailu/Mailu/issues/1171)
- [Mailu issue #2135](https://github.com/Mailu/Mailu/issues/2135)
- [Mailu issue #2827](https://github.com/Mailu/Mailu/issues/2827)
- [Mailu GitHub repository](https://github.com/Mailu/Mailu)
- [Plesk support article on RoundCube connection issue](https://support.plesk.com/hc/en-us/articles/115001264814-Unable-to-log-into-RoundCube-Connection-to-storage-server-failed)
- [Gist by marienfressinaud](https://gist.github.com/marienfressinaud/f284a59b18aad395eb0de2d22836ae6b)

View File

@@ -0,0 +1,22 @@
# Spam Issues 🚨
## Inspect 🔎
Use the following tools to monitor your domain and email deliverability:
- [Google Postmaster](https://postmaster.google.com/) - Analyzes deliverability and spam issues for Gmail.
- [Yahoo Postmaster](https://postmaster.yahooinc.com) - Provides insights and delivery reports for Yahoo.
- [MXToolbox](https://mxtoolbox.com)
## Blacklist Check 🚫
If your domain is blacklisted, you can check the status with these services and take steps to remove your domain if necessary:
- [Spamhaus](https://check.spamhaus.org/)
- [Barracuda](https://www.barracudacentral.org/lookups)
## Cloudmark Reset Request 🔄
If your IP or domain is flagged by Cloudmark, you can submit a **reset request**:
- [Cloudmark Reset](https://csi.cloudmark.com/en/reset/)

View File

@@ -0,0 +1,6 @@
# Test Server Instance
Use the following tools to test your server instance:
- [SSL-Tools Mailserver Test](https://de.ssl-tools.net/mailservers/)
- [TestEmail.de](http://testemail.de/)

View File

@@ -0,0 +1,108 @@
# User Administration
## Promoting an OIDC User to Admin 🧑‍💼
If your administrator logs in via OpenID Connect (OIDC) and you don't want to create a separate local user, you can promote the existing OIDC-authenticated user to a global admin directly in the Mailu database using the CLI.
Follow these steps:
1. Enter the Mailu `admin` container shell:
```bash
docker exec -it mailu-admin-1 flask shell
```
2. Inside the interactive shell, run the following commands:
```python
from mailu import models, db
user = models.User.query.filter_by(email='admin@example.com').first()
user.global_admin = True
db.session.commit()
```
Replace `admin@example.com` with the OIDC email address used to log in.
3. Exit the shell:
```python
exit()
```
Your OIDC-authenticated user is now a full **global admin** and has access to all administrative functions in the Mailu interface.
> 💡 Tip: This method is useful when you're using federated login and want to avoid managing separate local admin credentials.
Klar! Hier ist die Anleitung zur Änderung der primären Domain eines Mailu-Benutzers, speziell für **MariaDB** als Datenbank-Backend, auf **Englisch** und im gleichen Stil wie deine Doku:
---
## Changing the Primary Domain of a Mailu Account (MariaDB) 🌐
Mailu links user accounts to specific domains, so changing a user's primary domain cannot be done via the admin interface. You need to update it manually via the database.
> ⚠️ **Warning:** Always back up your database before performing manual operations.
### Steps for MariaDB:
1. Connect to the Mailu MariaDB container:
```bash
docker compose exec -it database mariadb -u mailu -p
```
Enter the password when prompted (you can find it in your `docker-compose.yml` or `.env` file).
2. Select the Mailu database (usually named `mailu`):
```sql
USE mailu;
```
3. Update the user's domain and email:
```sql
UPDATE user SET email='newname@newdomain.com', domain_name='newdomain.com' WHERE email='oldname@olddomain.com';
```
If needed, also update the local part (username):
```sql
UPDATE user SET localpart='newname' WHERE email='newname@newdomain.com';
```
4. If the new domain does not exist yet, insert it into the `domain` table:
```sql
INSERT INTO domain (name, max_users, max_aliases, max_quota_bytes, comment, enabled)
VALUES ('newdomain.com', 100, 100, 10737418240, 'New domain', true);
```
5. If the user had aliases, update the `alias` table accordingly.
---
### Alternative: Recreate the User
If you prefer not to modify the database manually:
- Delete the old user via the admin UI
- Create a new user under the desired domain
- Migrate emails using IMAP tools (e.g. `imapsync`)
---
### Update DNS and Mailu Configuration
Ensure that the new domain is correctly set up:
- Add it to `HOSTNAMES` in your `docker-compose.yml`
- Set up proper DNS records (MX, SPF, DKIM, DMARC)
- If using Let's Encrypt (`TLS_FLAVOR=cert`), make sure the domain is included in `LETSENCRYPT_HOSTS`
> 💡 **Tip:** Mailu must be aware of the domain both in its configuration and the database for mail routing and certificate issuance to work correctly.
---
Wenn du willst, kann ich dir das gleich in eine fertige Markdown-Datei oder ein Doku-Format einfügen.

View File

@@ -0,0 +1,23 @@
---
galaxy_info:
author: "Kevin Veen-Birkenbach"
description: "Revolutionize your email communications with Mailu, a secure and flexible mail server solution that integrates comprehensive features for managing digital correspondence reliably."
license: "CyMaIS NonCommercial License (CNCL)"
license_url: "https://s.veen.world/cncl"
company: |
Kevin Veen-Birkenbach
Consulting & Coaching Solutions
https://www.veen.world
galaxy_tags:
- mailu
- docker
- email
- mail server
- self-hosted
repository: "https://s.veen.world/cymais"
issue_tracker_url: "https://s.veen.world/cymaisissues"
documentation: "https://s.veen.world/cymais"
logo:
class: "fa-solid fa-envelope"
run_after:
- web-app-keycloak

View File

@@ -0,0 +1,25 @@
credentials:
secret_key:
description: "Secret key for cryptographic operations in Mailu (must be a 16-byte random string, hex-encoded)"
algorithm: "sha256"
validation: "^[a-f0-9]{32}$"
database_password:
description: "Password for the Mailu PostgreSQL or MariaDB database user"
algorithm: "bcrypt"
validation: "^\\$2[aby]\\$.{56}$"
api_token:
description: "Authentication token for accessing the Mailu RESTful API (minimum 3 characters)"
algorithm: "plain"
validation: "^.{3,}$"
initial_administrator_password:
description: "Initial password for the Mailu administrator account (used during setup)"
algorithm: "sha256"
validation: "^[a-f0-9]{64}$"
dkim_public_key:
description: "Public DKIM key for DNS configuration (TXT record)"
algorithm: "plain"
validation: "^.{64,}$"

View File

@@ -0,0 +1,3 @@
users:
administrator:
email: "administrator@{{ primary_domain }}" # Administrator Email for DNS Records

View File

@@ -0,0 +1,2 @@
# Todos
- Check if DKIM generation works on new setups

View File

@@ -0,0 +1,67 @@
- name: "Fetch existing API tokens via curl inside admin container"
command: >-
docker compose exec -T admin \
curl -s -X GET {{ mailu_api_base_url }}/token \
-H "Authorization: Bearer {{ mailu_global_api_token }}"
args:
chdir: "{{ mailu_compose_dir }}"
register: mailu_tokens_cli
changed_when: false
- name: "Extract existing token info for '{{ mailu_user_key }};{{ mailu_user_name }}'"
set_fact:
mailu_user_existing_token: >-
{{ (
mailu_tokens_cli.stdout
| default('[]')
| from_json
| selectattr('comment','equalto', mailu_user_key ~ " - ansible.cymais")
| list
).0 | default(None) }}
- name: "Delete existing API token for '{{ mailu_user_key }};{{ mailu_user_name }}' if local token missing but remote exists"
command: >-
docker compose exec -T admin \
curl -s -X DELETE {{ mailu_api_base_url }}/token/{{ mailu_user_existing_token.id }} \
-H "Authorization: Bearer {{ mailu_global_api_token }}"
args:
chdir: "{{ mailu_compose_dir }}"
when:
- users[mailu_user_key].mailu_token is not defined
- mailu_user_existing_token is not none
- mailu_user_existing_token.id is defined
register: mailu_token_delete
changed_when: mailu_token_delete.rc == 0
- name: "Create API token for '{{ mailu_user_key }};{{ mailu_user_name }}' if no local token defined"
command: >-
docker compose exec -T admin \
curl -s -X POST {{ mailu_api_base_url }}/token \
-H "Authorization: Bearer {{ mailu_global_api_token }}" \
-H "Content-Type: application/json" \
-d '{{ {
"comment": mailu_user_key ~ " - ansible.cymais",
"email": users[mailu_user_key].email,
"ip": mailu_token_ip
} | to_json }}'
args:
chdir: "{{ mailu_compose_dir }}"
when: users[mailu_user_key].mailu_token is not defined
register: mailu_token_creation
changed_when: mailu_token_creation.rc == 0
- name: "Set mailu_token for '{{ mailu_user_key }};{{ mailu_user_name }}' in users dict if newly created"
set_fact:
users: >-
{{ users
| combine({
mailu_user_key: (
users[mailu_user_key]
| combine({
'mailu_token': (mailu_token_creation.stdout | from_json).token
})
)
}, recursive=True)
}}
when: users[mailu_user_key].mailu_token is not defined

View File

@@ -0,0 +1,27 @@
- name: "Ensure Mailu user '{{ mailu_user_key }};{{ mailu_user_name }}@{{ mailu_domain }}'' exists"
command: >
docker compose exec admin flask mailu {{ mailu_action }}
{{ mailu_user_name }} {{ mailu_domain }} '{{ mailu_password }}'
args:
chdir: "{{ mailu_compose_dir }}"
register: mailu_user_result
failed_when: >
mailu_user_result.rc != 0 and
(
"exists, not created" not in mailu_user_result.stderr and
"Duplicate entry" not in mailu_user_result.stderr
)
changed_when: mailu_user_result.rc == 0
when: "'mail-bot' in item.value.roles or 'administrator' in item.value.roles"
- name: "Change password for user '{{ mailu_user_key }};{{ mailu_user_name }}@{{ mailu_domain }}'"
command: >
docker compose exec admin flask mailu password
{{ mailu_user_name }} {{ mailu_domain }} '{{ mailu_password }}'
args:
chdir: "{{ mailu_compose_dir }}"
when: "'mail-bot' in item.value.roles or 'administrator' in item.value.roles"
- name: "Create Mailu API Token for {{ mailu_user_name }}"
include_tasks: create-mailu-token.yml
when: "{{ 'mail-bot' in item.value.roles }}"

View File

@@ -0,0 +1,49 @@
- name: Check if DKIM private key file exists in the antispam container
command: >
docker compose exec -T antispam
test -f {{mailu_dkim_key_path}}
register: dkim_key_file_stat
failed_when: false
changed_when: false
args:
chdir: "{{ docker_compose.directories.instance }}"
- name: Generate DKIM key
command: >
docker compose exec -T antispam
rspamadm dkim_keygen -s dkim -d {{ applications[application_id].domain }} -k {{ mailu_dkim_key_path }}
register: dkim_keygen_output
when: dkim_key_file_stat.rc != 0
args:
chdir: "{{ docker_compose.directories.instance }}"
- name: Fetch DKIM private key from antispam container
shell: >
docker compose exec -T antispam
cat {{ mailu_dkim_key_path }}
args:
chdir: "{{ docker_compose.directories.instance }}"
register: dkim_priv_content
failed_when: dkim_priv_content.rc != 0
changed_when: false
- name: Generate DKIM public key on the host
command: openssl rsa -pubout
args:
stdin: "{{ dkim_priv_content.stdout }}"
register: dkim_pub_raw
changed_when: false
- name: Normalize and build Mailu DKIM TXT record
set_fact:
mailu_dkim_public_key: >-
v=DKIM1; k=rsa; p={{
dkim_pub_raw.stdout
| regex_replace('-----BEGIN PUBLIC KEY-----', '')
| regex_replace('-----END PUBLIC KEY-----', '')
| regex_replace('\s+', '')
}}
- name: Debug Mailu DKIM public key
debug:
msg: "Mailu DKIM public key: {{ mailu_dkim_public_key }}"

View File

@@ -0,0 +1,55 @@
---
- name: "Include service-rdbms-central"
include_role:
name: service-rdbms-central
when: run_once_docker_mailu is not defined
- name: "Include role webserver-proxy-domain for {{ application_id }}"
include_role:
name: webserver-proxy-domain
vars:
domain: "{{ domains | get_domain(application_id) }}"
http_port: "{{ ports.localhost.http[application_id] }}"
nginx_docker_reverse_proxy_extra_configuration: "client_max_body_size 31M;"
when: run_once_docker_mailu is not defined
- name: "Include the webserver-proxy-tls-deploy role"
include_role:
name: webserver-proxy-tls-deploy
when: run_once_docker_mailu is not defined
- name: Flush docker service handlers
meta: flush_handlers
when: run_once_docker_mailu is not defined
- name: "Create Mailu accounts"
include_tasks: create-mailu-user.yml
vars:
mailu_compose_dir: "{{ docker_compose.directories.instance }}"
mailu_domain: "{{ primary_domain }}"
mailu_api_base_url: "http://127.0.0.1:8080/api/v1"
mailu_global_api_token: "{{ applications.mailu.credentials.api_token }}"
mailu_action: >-
{{
(
'administrator' in (item.value.get('roles', []))
)
| ternary('admin','user')
}}
mailu_user_key: "{{ item.key }}"
mailu_user_name: "{{ item.value.username }}"
mailu_password: "{{ item.value.password }}"
mailu_token_ip: "{{ item.value.ip | default('') }}"
loop: "{{ users | dict2items }}"
loop_control:
loop_var: item
when: run_once_docker_mailu is not defined
- name: Set Mailu DNS records
include_tasks: set-mailu-dns-records.yml
when: dns_provider == 'cloudflare'
- name: Run the docker_mailu roles once
set_fact:
run_once_docker_mailu: true
when: run_once_docker_mailu is not defined

View File

@@ -0,0 +1,87 @@
- name: "Load Mailu DNS variables"
include_vars: vars/mailu-dns.yml
- name: Generate DKIM public key
include_tasks: generate-and-read-dkim.yml
- name: "Set A record for mail server"
community.general.cloudflare_dns:
api_token: "{{ cloudflare_record_api_token }}"
zone: "{{ mailu_dns_zone }}"
type: A
name: "{{ domain }}"
content: "{{ mailu_dns_ip }}"
proxied: false
ttl: 1
state: present
- name: "Set CNAME record for autoconfig"
community.general.cloudflare_dns:
api_token: "{{ cloudflare_record_api_token }}"
zone: "{{ mailu_dns_zone }}"
type: CNAME
name: "autoconfig.{{ mailu_dns_zone }}"
value: "{{ domain }}"
proxied: false
ttl: 1
state: present
- name: "Set MX record"
community.general.cloudflare_dns:
api_token: "{{ cloudflare_record_api_token }}"
zone: "{{ mailu_dns_zone }}"
type: MX
name: "{{ mailu_dns_zone }}"
value: "{{ domain }}"
priority: 10
ttl: 1
state: present
- name: "Set SRV records"
community.general.cloudflare_dns:
api_token: "{{ cloudflare_record_api_token }}"
zone: "{{ mailu_dns_zone }}"
type: SRV
service: "_{{ item.key }}"
proto: "_tcp"
priority: "{{ item.value.priority }}"
weight: "{{ item.value.weight }}"
port: "{{ item.value.port }}"
value: "{{ domain }}"
ttl: 1
state: present
loop: "{{ mailu_dns_srv_records | dict2items }}"
ignore_errors: true
#register: srv_result
#failed_when: srv_result.rc != 0 and ("An identical record already exists" not in srv_result.stdout)
#changed_when: srv_result.rc == 0 and ("An identical record already exists" not in srv_result.stdout)
- name: "Set SPF TXT record"
community.general.cloudflare_dns:
api_token: "{{ cloudflare_record_api_token }}"
zone: "{{ mailu_dns_zone }}"
type: TXT
name: "{{ mailu_dns_zone }}"
value: "v=spf1 mx a:{{ domain }} ~all"
ttl: 1
state: present
- name: "Set DMARC TXT record"
community.general.cloudflare_dns:
api_token: "{{ cloudflare_record_api_token }}"
zone: "{{ mailu_dns_zone }}"
type: TXT
name: "_dmarc.{{ mailu_dns_zone }}"
value: "v=DMARC1; p=reject; ruf=mailto:{{ mailu_dmarc_ruf }}; adkim=s; aspf=s"
ttl: 1
state: present
- name: "Set DKIM TXT record"
community.general.cloudflare_dns:
api_token: "{{ cloudflare_record_api_token }}"
zone: "{{ mailu_dns_zone }}"
type: TXT
name: "dkim._domainkey.{{ mailu_dns_zone }}"
value: "{{ mailu_dkim_public_key }}"
ttl: 1
state: present

View File

@@ -0,0 +1,175 @@
{% include 'roles/docker-compose/templates/base.yml.j2' %}
# Core services
resolver:
image: {{docker_source}}/unbound:{{applications.mailu.version}}
{% include 'roles/docker-container/templates/base.yml.j2' %}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
ipv4_address: {{networks.local.mailu.dns}}
front:
image: {{docker_source}}/nginx:{{applications.mailu.version}}
{% include 'roles/docker-container/templates/base.yml.j2' %}
ports:
- "127.0.0.1:{{ports.localhost.http[application_id]}}:80"
- "{{networks.internet.ip4}}:25:25"
- "{{networks.internet.ip4}}:465:465"
- "{{networks.internet.ip4}}:587:587"
- "{{networks.internet.ip4}}:110:110"
- "{{networks.internet.ip4}}:995:995"
- "{{networks.internet.ip4}}:143:143"
- "{{networks.internet.ip4}}:993:993"
- "{{networks.internet.ip4}}:4190:4190"
volumes:
- "{{docker_compose.directories.volumes}}overrides/nginx:/overrides:ro"
- "{{cert_mount_directory}}:/certs:ro"
{% include 'roles/docker-container/templates/depends_on/dmbs_incl.yml.j2' %}
resolver:
condition: service_started
{% include 'roles/docker-container/templates/networks.yml.j2' %}
webmail:
radicale:
dns:
- {{networks.local.mailu.dns}}
admin:
image: {{docker_source}}/admin:{{applications.mailu.version}}
{% include 'roles/docker-container/templates/base.yml.j2' %}
volumes:
- "admin_data:/data"
- "dkim:/dkim"
{% include 'roles/docker-container/templates/depends_on/dmbs_incl.yml.j2' %}
resolver:
condition: service_started
front:
condition: service_started
dns:
- {{networks.local.mailu.dns}}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
imap:
image: {{docker_source}}/dovecot:{{applications.mailu.version}}
{% include 'roles/docker-container/templates/base.yml.j2' %}
volumes:
- "dovecot_mail:/mail"
- "{{docker_compose.directories.volumes}}overrides:/overrides:ro"
depends_on:
- front
- resolver
dns:
- {{networks.local.mailu.dns}}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
smtp:
image: {{docker_source}}/postfix:{{applications.mailu.version}}
{% include 'roles/docker-container/templates/base.yml.j2' %}
volumes:
- "{{docker_compose.directories.volumes}}overrides:/overrides:ro"
- "smtp_queue:/queue"
depends_on:
- front
- resolver
dns:
- {{networks.local.mailu.dns}}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
oletools:
image: {{docker_source}}/oletools:{{applications.mailu.version}}
hostname: oletools
restart: {{docker_restart_policy}}
depends_on:
- resolver
dns:
- {{networks.local.mailu.dns}}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
noinet:
antispam:
image: {{docker_source}}/rspamd:{{applications.mailu.version}}
{% include 'roles/docker-container/templates/base.yml.j2' %}
volumes:
- "filter:/var/lib/rspamd"
- "dkim:/dkim"
- "{{docker_compose.directories.volumes}}overrides/rspamd:/overrides:ro"
depends_on:
- front
- redis
- antivirus
- resolver
dns:
- {{networks.local.mailu.dns}}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
noinet:
# Optional services
antivirus:
image: clamav/clamav-debian:latest
{% include 'roles/docker-container/templates/base.yml.j2' %}
volumes:
- "filter:/data"
depends_on:
- resolver
dns:
- {{networks.local.mailu.dns}}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
webdav:
image: {{docker_source}}/radicale:{{applications.mailu.version}}
{% include 'roles/docker-container/templates/base.yml.j2' %}
volumes:
- "webdav_data:/data"
depends_on:
- resolver
dns:
- {{networks.local.mailu.dns}}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
radicale:
fetchmail:
image: {{docker_source}}/fetchmail:{{applications.mailu.version}}
volumes:
- "admin_data:/data"
{% include 'roles/docker-container/templates/base.yml.j2' %}
depends_on:
- admin
- smtp
- imap
- resolver
dns:
- {{networks.local.mailu.dns}}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
webmail:
image: {{docker_source}}/webmail:{{applications.mailu.version}}
{% include 'roles/docker-container/templates/base.yml.j2' %}
volumes:
- "webmail_data:/data"
- "{{docker_compose.directories.volumes}}overrides:/overrides:ro"
depends_on:
- imap
- front
- resolver
dns:
- {{networks.local.mailu.dns}}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
webmail:
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}
smtp_queue:
admin_data:
webdav_data:
webmail_data:
filter:
dkim:
dovecot_mail:
redis:
{% include 'roles/docker-compose/templates/networks.yml.j2' %}
radicale:
driver: bridge
webmail:
driver: bridge
noinet:
driver: bridge
internal: true

View File

@@ -0,0 +1,203 @@
# Mailu main configuration file
#
# For a detailed list of configuration variables, see the documentation at
# https://mailu.io
###################################
# Common configuration variables
###################################
# https://chat.openai.com/share/1497464d-dfb5-46eb-9d26-04be99991ace
LD_PRELOAD=/usr/lib/libhardened_malloc.so
# Set to a randomly generated 16 bytes string
SECRET_KEY={{applications.mailu.credentials.secret_key}}
# Subnet of the docker network. This should not conflict with any networks to which your system is connected. (Internal and external!)
SUBNET={{networks.local.mailu.subnet}}
# Main mail domain
DOMAIN={{applications.mailu.domain}}
# Hostnames for this server, separated with comas
HOSTNAMES={{domains | get_domain(application_id)}}
# Postmaster local part (will append the main mail domain)
POSTMASTER=admin
# Choose how secure connections will behave (value: letsencrypt, cert, notls, mail, mail-letsencrypt)
TLS_FLAVOR=mail
# Authentication rate limit (per source IP address)
AUTH_RATELIMIT=10/minute;1000/hour
# Opt-out of statistics, replace with "True" to opt out
DISABLE_STATISTICS=True
###################################
# Optional features
###################################
# Expose the admin interface (value: true, false)
ADMIN=true
# Choose which webmail to run if any (values: roundcube, rainloop, none)
WEBMAIL=roundcube
# Dav server implementation (value: radicale, none)
WEBDAV=radicale
# Antivirus solution (value: clamav, none)
ANTIVIRUS=clamav
###################################
# Mail settings
###################################
# Message size limit in bytes
# Default: accept messages up to 50MB
# Max attachment size will be 33% smaller
MESSAGE_SIZE_LIMIT=50000000
# Networks granted relay permissions
# Use this with care, all hosts in this networks will be able to send mail without authentication!
RELAYNETS=
# Will relay all outgoing mails if configured
RELAYHOST=
# Fetchmail delay
FETCHMAIL_DELAY=600
# Recipient delimiter, character used to delimiter localpart from custom address part
RECIPIENT_DELIMITER=+
# DMARC rua and ruf email
DMARC_RUA=admin
DMARC_RUF=admin
# Welcome email, enable and set a topic and body if you wish to send welcome
# emails to all users.
WELCOME=false
WELCOME_SUBJECT=Welcome to your new email account
WELCOME_BODY=Welcome to your new email account, if you can read this, then it is configured properly!
# Maildir Compression
# choose compression-method, default: none (value: bz2, gz)
COMPRESSION=
# change compression-level, default: 6 (value: 1-9)
COMPRESSION_LEVEL=
###################################
# Web settings
###################################
# Path to redirect / to
WEBROOT_REDIRECT=/webmail
# Path to the admin interface if enabled
WEB_ADMIN=/admin
# Path to the webmail if enabled
WEB_WEBMAIL=/webmail
# Website name
SITENAME=Mailservices
# Linked Website URL
WEBSITE=https://{{domains | get_domain(application_id)}}
###################################
# Advanced settings
###################################
# Log driver for front service. Possible values:
# json-file (default)
# journald (On systemd platforms, useful for Fail2Ban integration)
# syslog (Non systemd platforms, Fail2Ban integration. Disables `docker-compose log` for front!)
LOG_DRIVER=syslog
# docker-compose project name, this will prepended to containers names.
COMPOSE_PROJECT_NAME=mailu
# Default password scheme used for newly created accounts and changed passwords
# (value: BLF-CRYPT, SHA512-CRYPT, SHA256-CRYPT, MD5-CRYPT, CRYPT)
PASSWORD_SCHEME=BLF-CRYPT
# Header to take the real ip from
REAL_IP_HEADER=
# IPs for nginx set_real_ip_from (CIDR list separated by commas)
REAL_IP_FROM=
# choose wether mailu bounces (no) or rejects (yes) mail when recipient is unknown (value: yes, no)
REJECT_UNLISTED_RECIPIENT=
# Log level threshold in start.py (value: CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET)
LOG_LEVEL=WARNING
###################################
# Database settings
###################################
SQLALCHEMY_DATABASE_URI_ROUNDCUBE=mysql://{{database_username}}:{{database_password}}@{{database_host}}/{{database_name}}?collation=utf8mb4_unicode_ci
SQLALCHEMY_DATABASE_URI=mysql+mysqlconnector://{{database_username}}:{{database_password}}@{{database_host}}/{{database_name}}?collation=utf8mb4_unicode_ci
###################################
# API Settings
###################################
API=true
WEB_API=/api
# Configures the authentication token. The minimum length is 3 characters. This token must be passed as request header to the API as authentication token. This is a mandatory setting for using the RESTful API.
API_TOKEN={{applications.mailu.credentials.api_token}}
# Activated https://mailu.io/master/configuration.html#advanced-settings
AUTH_REQUIRE_TOKENS=True
{% if applications | is_feature_enabled('oidc',application_id) %}
###################################
# OpenID Connect settings
###################################
# @see https://github.com/heviat/Mailu-OIDC/tree/master
# Enable OpenID Connect. Possible values: True, False
OIDC_ENABLED={{ applications | is_feature_enabled('oidc',application_id) | string | capitalize }}
# OpenID Connect provider configuration URL
OIDC_PROVIDER_INFO_URL={{oidc.client.issuer_url}}
# OpenID Connect Client ID for Mailu
OIDC_CLIENT_ID={{oidc.client.id}}
# OpenID Connect Client secret for Mailu
OIDC_CLIENT_SECRET={{oidc.client.secret}}
# Label text for OpenID Connect login button. Default: OpenID Connect
OIDC_BUTTON_NAME={{oidc.button_text}}
# Disable TLS certificate verification for the OIDC client. Possible values: True, False
OIDC_VERIFY_SSL=True
# Enable redirect to OIDC provider for password change. Possible values: True, False
OIDC_CHANGE_PASSWORD_REDIRECT_ENABLED=True
# Redirect URL for password change. Defaults to provider issuer url appended by /.well-known/change-password
OIDC_CHANGE_PASSWORD_REDIRECT_URL={{oidc.client.change_credentials}}
{% if applications[application_id].oidc.email_by_username | bool %}
# The OIDC claim used as the username. If the selected claim contains an email address, it will be used as is. If it is not an email (e.g., sub), the email address will be constructed as <OIDC_USERNAME_CLAIM>@<OIDC_USER_DOMAIN>. Defaults to email.
OIDC_USERNAME_CLAIM={{oidc.attributes.username}}
# The domain used when constructing an email from a non-email username (e.g., when OIDC_USERNAME_CLAIM=sub). Ignored if OIDC_USERNAME_CLAIM is already an email. Defaults to the value of DOMAIN.
OIDC_USER_DOMAIN={{primary_domain}}
{% endif %}
# If enabled, users who authenticate successfully but do not yet have an account will have one created for them. If disabled, only existing users can log in, and authentication will fail for users without a pre-existing account. Defaults to True.
OIDC_ENABLE_USER_CREATION={{ applications[application_id].oidc.enable_user_creation | string | capitalize }}
{% endif %}

View File

@@ -0,0 +1,33 @@
version: "2024.06" # Docker Image Version
oidc:
email_by_username: true # If true, then the mail is set by the username. If wrong then the OIDC user email is used
enable_user_creation: true # Users will be created if not existing
domain: "{{primary_domain}}" # The main domain from which mails will be send \ email suffix behind @
features:
matomo: true
css: false
portfolio_iframe: true # Deactivated mailu iframe loading until keycloak supports it
oidc: true
central_database: false # Deactivate central database for mailu, I don't know why the database deactivation is necessary
domains:
canonical:
- "mail.{{ primary_domain }}"
csp:
flags:
style-src:
unsafe-inline: true
script-src-elem:
unsafe-inline: true
script-src:
unsafe-inline: true
unsafe-eval: true
rbac:
roles:
mail-bot:
description: "Has an token to send and recieve emails"
docker:
services:
redis:
enabled: true
database:
enabled: true

View File

@@ -0,0 +1,41 @@
# vars/mailu-dns.yml
mailu_dns_zone: "{{ applications[application_id].domain }}"
mailu_dns_ip: "{{ networks.internet.ip4 }}"
cloudflare_record_api_token: "{{ certbot_dns_api_token }}"
mailu_dmarc_ruf: "{{ applications[application_id].users.administrator.email }}"
mailu_dkim_key_file: "{{ applications[application_id].domain }}.dkim.key"
mailu_dkim_key_path: "/dkim/{{ mailu_dkim_key_file }}"
mailu_dns_srv_records:
submission:
port: 587
priority: 20
weight: 1
submissions:
port: 465
priority: 20
weight: 1
imaps:
port: 993
priority: 20
weight: 1
imap:
port: 143
priority: 20
weight: 1
pop3s:
port: 995
priority: 20
weight: 1
pop3:
port: 110
priority: 20
weight: 1
autodiscover:
port: 443
priority: 20
weight: 1

View File

@@ -0,0 +1,14 @@
application_id: "mailu"
# Database Configuration
database_password: "{{applications.mailu.credentials.database_password}}"
database_type: "mariadb"
cert_mount_directory: "{{docker_compose.directories.volumes}}certs/"
# Use dedicated source for oidc if activated
# @see https://github.com/heviat/Mailu-OIDC/tree/2024.06
docker_source: "{{ 'ghcr.io/heviat' if applications | is_feature_enabled('oidc',application_id) else 'ghcr.io/mailu' }}"
domain: "{{ domains | get_domain(application_id) }}"
http_port: "{{ ports.localhost.http[application_id] }}"