From 91dabffbd81e63abc0b391583e4abb75b0efbcae Mon Sep 17 00:00:00 2001 From: Markus Pesch Date: Mon, 7 Sep 2026 17:30:42 +0200 Subject: [PATCH] Initial Commit --- .ansible-lint | 4 + .editorconfig | 12 + .gitea/workflows/ansible-linters.yaml | 20 + .gitea/workflows/markdown-linters.yaml | 18 + .gitea/workflows/release.yaml | 22 + .gitignore | 2 + .markdownlint.yaml | 137 ++ .vscode/settings.json | 14 + .yamllint.yaml | 19 + LICENSE | 20 + README.md | 85 + defaults/main.yml | 982 ++++++++++++ handlers/main.yml | 22 + meta/argument_specs.yaml | 797 ++++++++++ meta/main.yaml | 17 + package-lock.json | 1389 +++++++++++++++++ package.json | 19 + renovate.json | 9 + tasks/main.yml | 303 ++++ .../renewal-hooks/post/postfix.sh.j2 | 50 + templates/etc/postfix/aliases.j2 | 7 + templates/etc/postfix/canonical_maps.j2 | 9 + .../etc/postfix/check_client_access_maps.j2 | 11 + .../etc/postfix/check_helo_access_maps.j2 | 11 + .../postfix/check_recipient_access_maps.j2 | 11 + .../etc/postfix/check_sender_access_maps.j2 | 11 + templates/etc/postfix/main.cf.j2 | 1135 ++++++++++++++ templates/etc/postfix/master.cf.j2 | 25 + .../etc/postfix/pgsql_relay_domain_maps.cf.j2 | 9 + .../postfix/pgsql_relay_recipient_maps.cf.j2 | 9 + .../etc/postfix/pgsql_sender_login_maps.cf.j2 | 9 + ...l_virtual_alias_domain_catchall_maps.cf.j2 | 9 + ...ql_virtual_alias_domain_mailbox_maps.cf.j2 | 9 + .../pgsql_virtual_alias_domain_maps.cf.j2 | 9 + .../postfix/pgsql_virtual_alias_maps.cf.j2 | 9 + .../pgsql_virtual_mailbox_domains.cf.j2 | 9 + .../pgsql_virtual_mailbox_limit_maps.cf.j2 | 9 + .../postfix/pgsql_virtual_mailbox_maps.cf.j2 | 9 + .../etc/postfix/recipient_canonical_maps.j2 | 9 + templates/etc/postfix/relay_domain_maps.j2 | 11 + templates/etc/postfix/relay_recipient_maps.j2 | 15 + templates/etc/postfix/relocated_maps.j2 | 10 + templates/etc/postfix/sasl_password_maps.j2 | 7 + .../etc/postfix/sender_canonical_maps.j2 | 9 + .../etc/postfix/smtpd_sender_login_maps.j2 | 17 + .../etc/postfix/submission_header_cleanup.j2 | 10 + templates/etc/postfix/tls_policy_maps.j2 | 10 + templates/etc/postfix/transport_maps.j2 | 10 + templates/etc/postfix/virtual_alias_maps.j2 | 11 + .../etc/postfix/virtual_mailbox_domains.j2 | 14 + templates/etc/postfix/virtual_mailbox_maps.j2 | 14 + .../systemd/system/status-email@.service.j2 | 12 + templates/usr/local/sbin/systemd-email.sh.j2 | 9 + 53 files changed, 5419 insertions(+) create mode 100644 .ansible-lint create mode 100644 .editorconfig create mode 100644 .gitea/workflows/ansible-linters.yaml create mode 100644 .gitea/workflows/markdown-linters.yaml create mode 100644 .gitea/workflows/release.yaml create mode 100644 .gitignore create mode 100644 .markdownlint.yaml create mode 100644 .vscode/settings.json create mode 100644 .yamllint.yaml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 defaults/main.yml create mode 100644 handlers/main.yml create mode 100644 meta/argument_specs.yaml create mode 100644 meta/main.yaml create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 renovate.json create mode 100644 tasks/main.yml create mode 100644 templates/etc/letsencrypt/renewal-hooks/post/postfix.sh.j2 create mode 100644 templates/etc/postfix/aliases.j2 create mode 100644 templates/etc/postfix/canonical_maps.j2 create mode 100644 templates/etc/postfix/check_client_access_maps.j2 create mode 100644 templates/etc/postfix/check_helo_access_maps.j2 create mode 100644 templates/etc/postfix/check_recipient_access_maps.j2 create mode 100644 templates/etc/postfix/check_sender_access_maps.j2 create mode 100644 templates/etc/postfix/main.cf.j2 create mode 100644 templates/etc/postfix/master.cf.j2 create mode 100644 templates/etc/postfix/pgsql_relay_domain_maps.cf.j2 create mode 100644 templates/etc/postfix/pgsql_relay_recipient_maps.cf.j2 create mode 100644 templates/etc/postfix/pgsql_sender_login_maps.cf.j2 create mode 100644 templates/etc/postfix/pgsql_virtual_alias_domain_catchall_maps.cf.j2 create mode 100644 templates/etc/postfix/pgsql_virtual_alias_domain_mailbox_maps.cf.j2 create mode 100644 templates/etc/postfix/pgsql_virtual_alias_domain_maps.cf.j2 create mode 100644 templates/etc/postfix/pgsql_virtual_alias_maps.cf.j2 create mode 100644 templates/etc/postfix/pgsql_virtual_mailbox_domains.cf.j2 create mode 100644 templates/etc/postfix/pgsql_virtual_mailbox_limit_maps.cf.j2 create mode 100644 templates/etc/postfix/pgsql_virtual_mailbox_maps.cf.j2 create mode 100644 templates/etc/postfix/recipient_canonical_maps.j2 create mode 100644 templates/etc/postfix/relay_domain_maps.j2 create mode 100644 templates/etc/postfix/relay_recipient_maps.j2 create mode 100644 templates/etc/postfix/relocated_maps.j2 create mode 100644 templates/etc/postfix/sasl_password_maps.j2 create mode 100644 templates/etc/postfix/sender_canonical_maps.j2 create mode 100644 templates/etc/postfix/smtpd_sender_login_maps.j2 create mode 100644 templates/etc/postfix/submission_header_cleanup.j2 create mode 100644 templates/etc/postfix/tls_policy_maps.j2 create mode 100644 templates/etc/postfix/transport_maps.j2 create mode 100644 templates/etc/postfix/virtual_alias_maps.j2 create mode 100644 templates/etc/postfix/virtual_mailbox_domains.j2 create mode 100644 templates/etc/postfix/virtual_mailbox_maps.j2 create mode 100644 templates/etc/systemd/system/status-email@.service.j2 create mode 100644 templates/usr/local/sbin/systemd-email.sh.j2 diff --git a/.ansible-lint b/.ansible-lint new file mode 100644 index 0000000..23a163f --- /dev/null +++ b/.ansible-lint @@ -0,0 +1,4 @@ +--- + +exclude_paths: +- .gitea/ diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ad4c311 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = false diff --git a/.gitea/workflows/ansible-linters.yaml b/.gitea/workflows/ansible-linters.yaml new file mode 100644 index 0000000..4e38255 --- /dev/null +++ b/.gitea/workflows/ansible-linters.yaml @@ -0,0 +1,20 @@ +name: Ansible Linter + +on: + pull_request: + types: [ "opened", "reopened", "synchronize" ] + push: + branches: [ '**' ] + tags-ignore: [ '**' ] + +jobs: + ansible-lint: + runs-on: + - ubuntu-latest + steps: + - uses: actions/checkout@v6.0.1 + - name: Run ansible-lint + uses: ansible/ansible-lint@v26.1.0 + with: + args: "--config-file .ansible-lint" + setup_python: "true" diff --git a/.gitea/workflows/markdown-linters.yaml b/.gitea/workflows/markdown-linters.yaml new file mode 100644 index 0000000..bac3496 --- /dev/null +++ b/.gitea/workflows/markdown-linters.yaml @@ -0,0 +1,18 @@ +name: Lint Markdown files + +on: + pull_request: + types: [ "opened", "reopened", "synchronize" ] + push: + branches: [ '**' ] + tags-ignore: [ '**' ] + +jobs: + markdown-lint: + runs-on: + - ubuntu-latest + steps: + - uses: actions/checkout@v6.0.1 + - uses: DavidAnson/markdownlint-cli2-action@v21.0.0 + with: + globs: '**/*.md' diff --git a/.gitea/workflows/release.yaml b/.gitea/workflows/release.yaml new file mode 100644 index 0000000..f4dc263 --- /dev/null +++ b/.gitea/workflows/release.yaml @@ -0,0 +1,22 @@ +name: Release Ansible Role + +on: + push: + tags: + - '**' + workflow_dispatch: {} + +jobs: + release: + name: Release Ansible Role + runs-on: ubuntu-latest + steps: + - name: Install Ansible Galaxy + run: | + apt update --yes + apt install --yes ansible + - env: + ANSIBLE_GALAXY_TOKEN: ${{ secrets.ANSIBLE_GALAXY_TOKEN }} + name: Update Ansible Role in Ansible Galaxy + run: | + ansible-galaxy role import --token=${ANSIBLE_GALAXY_TOKEN} volker-raschek ${GITHUB_REPOSITORY#*/} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9c3c141 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.ansible +node_modules \ No newline at end of file diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 0000000..0cca4db --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,137 @@ +# markdownlint YAML configuration +# https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml + +# Default state for all rules +default: true + +# Path to configuration file to extend +extends: null + +# MD003/heading-style/header-style - Heading style +MD003: + # Heading style + style: "atx" + +# MD004/ul-style - Unordered list style +MD004: + style: "dash" + +# MD007/ul-indent - Unordered list indentation +MD007: + # Spaces for indent + indent: 2 + # Whether to indent the first level of the list + start_indented: false + +# MD009/no-trailing-spaces - Trailing spaces +MD009: + # Spaces for line break + br_spaces: 2 + # Allow spaces for empty lines in list items + list_item_empty_lines: false + # Include unnecessary breaks + strict: false + +# MD010/no-hard-tabs - Hard tabs +MD010: + # Include code blocks + code_blocks: true + +# MD012/no-multiple-blanks - Multiple consecutive blank lines +MD012: + # Consecutive blank lines + maximum: 1 + +# MD013/line-length - Line length +MD013: + # Number of characters + line_length: 120 + # Number of characters for headings + heading_line_length: 120 + # Number of characters for code blocks + code_block_line_length: 120 + # Include code blocks + code_blocks: false + # Include tables + tables: false + # Include headings + headings: true + # Strict length checking + strict: false + # Stern length checking + stern: false + +# MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines +MD022: + # Blank lines above heading + lines_above: 1 + # Blank lines below heading + lines_below: 1 + +# MD025/single-title/single-h1 - Multiple top-level headings in the same document +MD025: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD026/no-trailing-punctuation - Trailing punctuation in heading +MD026: + # Punctuation characters + punctuation: ".,;:!。,;:!" + +# MD029/ol-prefix - Ordered list item prefix +MD029: + # List style + style: "one_or_ordered" + +# MD030/list-marker-space - Spaces after list markers +MD030: + # Spaces for single-line unordered list items + ul_single: 1 + # Spaces for single-line ordered list items + ol_single: 1 + # Spaces for multi-line unordered list items + ul_multi: 1 + # Spaces for multi-line ordered list items + ol_multi: 1 + +# MD033/no-inline-html - Inline HTML +MD033: + # Allowed elements + allowed_elements: [] + +# MD035/hr-style - Horizontal rule style +MD035: + # Horizontal rule style + style: "---" + +# MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading +MD036: + # Punctuation characters + punctuation: ".,;:!?。,;:!?" + +# MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading +MD041: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD044/proper-names - Proper names should have the correct capitalization +MD044: + # List of proper names + names: + - gitea + # Include code blocks + code_blocks: false + +# MD046/code-block-style - Code block style +MD046: + # Block style + style: "fenced" + +# MD048/code-fence-style - Code fence style +MD048: + # Code fence syle + style: "backtick" diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e112343 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "ansible.python.interpreterPath": "/bin/python", + "files.associations": { + "**/.gitea/**/*.yml": "yaml", + "**/.gitea/**/*.yaml": "yaml", + "docker-compose*.yml": "dockercompose", + "*.yml": "ansible", + "*.yaml": "ansible", + ".yamllint": "yaml", + ".yamllint.yml": "yaml", + ".yamllint.yaml": "yaml" + }, + "rewrap.wrappingColumn": 120 +} \ No newline at end of file diff --git a/.yamllint.yaml b/.yamllint.yaml new file mode 100644 index 0000000..e0e4d53 --- /dev/null +++ b/.yamllint.yaml @@ -0,0 +1,19 @@ +--- + +# +# Documentation: +# https://yamllint.readthedocs.io/en/stable/ +# + +rules: + brackets: + forbid: false + min-spaces-inside: 0 + max-spaces-inside: 2 + min-spaces-inside-empty: 0 + max-spaces-inside-empty: 0 + indentation: + spaces: 2 + indent-sequences: false + line-length: + max: 360 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7450a8b --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2026 Markus Pesch + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d78c4f3 --- /dev/null +++ b/README.md @@ -0,0 +1,85 @@ +# certificate-authority + +This Ansible role can be used to create a root and intermediate certificate authority and issue client certificates from +them. Additionally offers the ansible role the feature to import the certificates of the authority into the systems +trust store. + +## Examples + +The following minimal example creates a root and intermediate certificate authority and issues a client certificate from +the intermediate certificate authority. + +```yaml +certificate_authority_client_skip: false +certificate_authority_client_common_name: "{{ inventory_hostname }}" +certificate_authority_client_subject_alternative_names: +- "DNS:{{ inventory_hostname }}" +- "DNS:san.example.local" +- "IP:10.11.12.13" +``` + +## Parameters + +### Root Certificate Authority (CA) + +| Name | Description | Value | +| --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | +| `certificate_authority_root_ca_skip` | Skip creation or import of a root certificate authority in general. | `false` | +| `certificate_authority_root_ca_create` | Create root certificate from scratch or import via `certificate_authority_root_ca_tls` prefixed variables. | `true` | +| `certificate_authority_root_ca_import` | Import the TLS certificate of the root certificate authority into the systems trust store. | `true` | +| `certificate_authority_root_ca_path` | Directory where the private and public TLS key of the root certificate authority should be stored. | `/etc/ansible-playbook/pki/ca` | +| `certificate_authority_root_ca_common_name` | Common Name (CN) of the root certificate authority. | `Ansible Root CA` | +| `certificate_authority_root_ca_country_name` | Country name of the root certificate authority. For example `US`, `FR` or `DE`. | `""` | +| `certificate_authority_root_ca_email_address` | E-Mail Address of the root certificate authority owner. | `""` | +| `certificate_authority_root_ca_organization_name` | Organization name of the root certificate authority owner. | `""` | +| `certificate_authority_root_ca_organizational_unit_name` | Organizational unit name of the root certificate authority. | `""` | +| `certificate_authority_root_ca_state_or_province_name` | State or province name where the owner of the root certificate authority is located. | `""` | +| `certificate_authority_root_ca_subject_alternative_names` | Subject Alternative Names (SAN) of the root certificate authority. Example: `DNS:example.local`, `IP:10.11.12.13`. | `[]` | +| `certificate_authority_root_ca_not_after` | Time in the future from now when the TLS certificate should expire | `+3650d` | +| `certificate_authority_root_ca_not_before` | Time in the past from now when the TLS certificate should be valid. | `+0s` | +| `certificate_authority_root_ca_tls_key_content` | Content of a custom used root certificate authority. Will only be imported, when `certificate_authority_root_ca_create: false`. | `""` | +| `certificate_authority_root_ca_tls_crt_content` | Content of a custom used certificate of the certificate authority. Will only be imported, when `certificate_authority_root_ca_create: false`. | `""` | +| `certificate_authority_root_ca_tls_key_passphrase` | Passphrase for the private key of the generated or imported root certificate authority. | `""` | +| `certificate_authority_root_ca_tls_key_type` | Algorithm of the private key of the root certificate authority. | `RSA` | + +### Intermediate Certificate Authority (CA) + +| Name | Description | Value | +| ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | +| `certificate_authority_intermediate_ca_skip` | Skip creation or import of a intermediate certificate authority in general. | `false` | +| `certificate_authority_intermediate_ca_create` | Create intermediate certificate from scratch or import via `certificate_authority_intermediate_ca_tls` prefixed variables. | `true` | +| `certificate_authority_intermediate_ca_path` | Directory where the private and public TLS key of the intermediate certificate authority should be stored. | `/etc/ansible-playbook/pki/intermediate` | +| `certificate_authority_intermediate_ca_common_name` | Common Name (CN) of the intermediate certificate authority. | `Ansible Intermediate CA` | +| `certificate_authority_intermediate_ca_country_name` | Country name of the intermediate certificate authority. For example `US`, `FR` or `DE`. | `""` | +| `certificate_authority_intermediate_ca_email_address` | E-Mail Address of the intermediate certificate authority owner. | `""` | +| `certificate_authority_intermediate_ca_organization_name` | Organization name of the intermediate certificate authority owner. | `""` | +| `certificate_authority_intermediate_ca_organizational_unit_name` | Organizational unit name of the intermediate certificate authority. | `""` | +| `certificate_authority_intermediate_ca_state_or_province_name` | State or province name where the owner of the intermediate certificate authority is located. | `""` | +| `certificate_authority_intermediate_ca_subject_alternative_names` | Subject Alternative Names (SAN) of the intermediate certificate authority. Example: `DNS:example.local`, `IP:10.11.12.13`. | `[]` | +| `certificate_authority_intermediate_ca_not_after` | Time in the future from now when the TLS certificate should expire | `+1825d` | +| `certificate_authority_intermediate_ca_not_before` | Time in the past from now when the TLS certificate should be valid. | `+0s` | +| `certificate_authority_intermediate_ca_tls_key_content` | Content of a custom used intermediate certificate authority. Will only be imported, when `certificate_authority_intermediate_ca_create: false`. | `""` | +| `certificate_authority_intermediate_ca_tls_crt_content` | Content of a custom used certificate of the certificate authority. Will only be imported, when `certificate_authority_intermediate_ca_create: false`. | `""` | +| `certificate_authority_intermediate_ca_tls_key_passphrase` | Passphrase for the private key of the generated or imported intermediate certificate authority. | `""` | +| `certificate_authority_intermediate_ca_tls_key_type` | Algorithm of the private key of the intermediate certificate authority. | `RSA` | + +### Client Certificate + +| Name | Description | Value | +| -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | +| `certificate_authority_client_skip` | Skip creation or import of a client certificate in general. | `true` | +| `certificate_authority_client_create` | Create client certificate from scratch or import via `certificate_authority_client_tls` prefixed variables. | `true` | +| `certificate_authority_client_path` | Directory where the private and public TLS key of the client certificate authority should be stored. | `/etc/ansible-playbook/pki/client` | +| `certificate_authority_client_common_name` | Common Name (CN) of the client certificate. | `Ansible Client Certificate` | +| `certificate_authority_client_country_name` | Country name of the client certificate. For example `US`, `FR` or `DE`. | `""` | +| `certificate_authority_client_email_address` | E-Mail Address of the client certificate owner. | `""` | +| `certificate_authority_client_organization_name` | Organization name of the client certificate owner. | `""` | +| `certificate_authority_client_organizational_unit_name` | Organizational unit name of the client certificate. | `""` | +| `certificate_authority_client_state_or_province_name` | State or province name where the owner of the client certificate is located. | `""` | +| `certificate_authority_client_subject_alternative_names` | Subject Alternative Names (SAN) of the client certificate. Example: `DNS:example.local`, `IP:10.11.12.13`. | `[]` | +| `certificate_authority_client_not_after` | Time in the future from now when the TLS certificate should expire | `+397d` | +| `certificate_authority_client_not_before` | Time in the past from now when the TLS certificate should be valid. | `+0s` | +| `certificate_authority_client_tls_key_passphrase` | Passphrase for the private key of the generated or imported client certificate. | `""` | +| `certificate_authority_client_tls_key_type` | Algorithm of the private key of the client certificate. | `RSA` | +| `certificate_authority_client_tls_crt_content` | Content of a custom used client certificate. Will only be imported, when `certificate_authority_client_create: false`. | `""` | +| `certificate_authority_client_tls_key_content` | Content of the private key of a custom used client certificate. Will only be imported, when `certificate_authority_client_create: false`. | `""` | diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..1b6bc67 --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,982 @@ +--- + +## @section Postfix configuration + +## @param postfix_address_verify_db Lookup table URI for address verification. Postfix uses this table to verify recipient addresses before accepting mail for delivery. +## @param postfix_address_verify_negative_expire_time Time after which a failed probe expires from the address verification cache. +## @param postfix_address_verify_negative_refresh_time Time after which a failed address verification probe needs to be refreshed. +## @param postfix_address_verify_positive_expire_time Time after which a successful probe expires from the address verification cache. +## @param postfix_address_verify_positive_refresh_time Time after which a successful address verification probe needs to be refreshed. +postfix_address_verify_db: "lmdb:/var/lib/postfix/verify_cache" +postfix_address_verify_negative_expire_time: "" +postfix_address_verify_negative_refresh_time: "" +postfix_address_verify_positive_expire_time: "" +postfix_address_verify_positive_refresh_time: "" + +## @param postfix_alias_database [string] Alias database for local(8) delivery. Postfix uses this database to map email addresses to local recipients. +## @param postfix_alias_maps [string] Alias maps for local(8) delivery. Postfix uses this database to map email addresses to local recipients. +postfix_alias_database_enabled: true +postfix_alias_database_table: "lmdb:/etc/postfix/aliases" +postfix_alias_database_entry_root: "root" +postfix_alias_database_entries: +- origin: "root" + user: "{{ postfix_alias_database_entry_root }}" + +# Basic system aliases -- these MUST be present +- origin: "MAILER-DAEMON" + user: "postmaster" +- origin: "postmaster" + user: "root" + +# General redirection for pseudo-users to a real user. This is useful for system accounts that should not receive mail directly. +- origin: "abuse" + user: "root" +- origin: "bin" + user: "root" +- origin: "clamav" + user: "root" +- origin: "daemon" + user: "root" +- origin: "ftp" + user: "root" +- origin: "hostmaster" + user: "root" +- origin: "named" + user: "root" +- origin: "news" + user: "root" +- origin: "nobody" + user: "root" +- origin: "postfix" + user: "root" +- origin: "security" + user: "root" +- origin: "usenet" + user: "root" +- origin: "uucp" + user: "root" +- origin: "virusalert" + user: "root" +- origin: "webmaster" + user: "root" +- origin: "www" + user: "root" + +# Instead of bouncing 'noreply', we send it to /dev/null +- origin: "noreply" + user: "devnull" +- origin: "devnull" + user: "/dev/null" + +postfix_alias_maps: "{{ postfix_alias_database_table }}" +postfix_alias_maps_table_entries: [] + +## @param postfix_append_at_myorigin Append the value of $myorigin to addresses that do not contain a domain part. +postfix_append_at_myorigin: true + +## @param postfix_append_dot_mydomain Append a dot and the value of $mydomain to addresses that do not contain a domain part. +postfix_append_dot_mydomain: false + +## @param postfix_biff Enable or disable the biff service, which notifies users of new mail. The default is false, which disables the service. +postfix_biff: false + +## @param postfix_canonical_maps [array] Address rewriting for both sender and recipient. Assembled from enabled LMDB sources. Empty items are filtered out by the template. +postfix_canonical_maps: +- "{{ postfix_lmdb_canonical_maps_table if postfix_lmdb_enabled and postfix_lmdb_canonical_maps_enabled else '' }}" + +## @param postfix_check_client_access_maps [array] Client access control tables. Assembled from enabled LMDB sources. Empty items are filtered out by the template. +postfix_check_client_access_maps: +- "{{ postfix_lmdb_check_client_access_maps_table if postfix_lmdb_enabled and postfix_lmdb_check_client_access_maps_enabled else '' }}" + +## @param postfix_check_helo_access_maps [array] HELO/EHLO access control tables. Assembled from enabled LMDB sources. Empty items are filtered out by the template. +postfix_check_helo_access_maps: +- "{{ postfix_lmdb_check_helo_access_maps_table if postfix_lmdb_enabled and postfix_lmdb_check_helo_access_maps_enabled else '' }}" + +## @param postfix_check_recipient_access_maps [array] Recipient access control tables. Assembled from enabled LMDB sources. Empty items are filtered out by the template. +postfix_check_recipient_access_maps: +- "{{ postfix_lmdb_check_recipient_access_maps_table if postfix_lmdb_enabled and postfix_lmdb_check_recipient_access_maps_enabled else '' }}" + +## @param postfix_check_sender_access_maps [array] Sender access control tables. Assembled from enabled LMDB sources. Empty items are filtered out by the template. +postfix_check_sender_access_maps: +- "{{ postfix_lmdb_check_sender_access_maps_table if postfix_lmdb_enabled and postfix_lmdb_check_sender_access_maps_enabled else '' }}" + +## @param postfix_compatibility_level The Postfix compatibility level. This parameter controls the behavior of certain Postfix features and settings to maintain compatibility with older versions of Postfix. +postfix_compatibility_level: "3.11" + +## @param postfix_delay_warning_time The time after which Postfix sends a warning message to the sender if a message is delayed in the queue. +postfix_delay_warning_time: "" + +## @param postfix_disable_vrfy_command Disable the VRFY command in the Postfix SMTP server. +postfix_disable_vrfy_command: false + +## @param postfix_home_mailbox The path to the mailbox for local users. +postfix_home_mailbox: "" + +## @param postfix_inet_interfaces The network interfaces that Postfix should listen on for incoming connections. +postfix_inet_interfaces: "" + +## @param postfix_inet_protocols The internet protocols that Postfix should use when making and accepting connections. Possible values: "all", "ipv4", "ipv6", "ipv4, ipv6", "ipv6, ipv4". The default is "all". +postfix_inet_protocols: "" + +## @param postfix_mailbox_size_limit The maximal size in bytes of an individual mailbox or maildir file, or zero (no limit). Use -1 to postfix build-in default. +postfix_mailbox_size_limit: -1 + +## @param postfix_mail_name The name of the mail system. Leave empty to use postfix build-in default value. +postfix_mail_name: "" + +## @param postfix_mail_owner The user account that owns the Postfix daemon processes. Leave empty to use postfix build-in default value. +postfix_mail_owner: "" + +## @param postfix_message_size_limit The maximum size in bytes of a message that the Postfix SMTP server will accept. Use -1 to postfix build-in default. +postfix_message_size_limit: -1 + +## @param postfix_milter_default_action The default action for the Postfix Milter (mail filter) library when a mail filter application does not respond. Possible values: "accept", "reject", "discard", "tempfail", "shutdown". +postfix_milter_default_action: "" + +## @param postfix_milter_mail_macros The macros that the Postfix Milter (mail filter) library should pass to the mail filter application. +postfix_milter_mail_macros: "" + +## @param postfix_milter_protocol The Milter protocol version to use. Leave empty to use postfix build-in default value. +postfix_milter_protocol: "" + +## @param postfix_mua_client_restrictions [array] Restrictions for the Postfix SMTP client when sending mail. The order is important, as the first match is used. +postfix_mua_client_restrictions: [] + +## @param postfix_mua_relay_restrictions [array] Restrictions for the Postfix SMTP client when relaying mail. The order is important, as the first match is used. +postfix_mua_relay_restrictions: [] + +## @param postfix_mua_sender_restrictions [array] Restrictions for the Postfix SMTP client when sending mail. The order is important, as the first match is used. +postfix_mua_sender_restrictions: [] + +## @param postfix_mydestination [array] Domains that are delivered via the $local_transport mail delivery. The order is important, as the first match is used. The default configuration includes the mail server's hostname and localhost. +postfix_mydestination: [] + +## @param postfix_mydomain [string] The internet domain name of this mail system. The default is to use the domain part of $myhostname. +postfix_mydomain: "{{ inventory_hostname.split('.')[1:] | join('.') }}" + +## @param postfix_myhostname [string] The internet hostname of this mail system. The default is to use the fully qualified domain name of the host. +postfix_myhostname: "{{ inventory_hostname }}" + +## @param postfix_mynetworks [array] Additional IP addresses or CIDR ranges to trust for relaying +postfix_mynetworks: [] + +## @param postfix_mynetworks_style The method to generate the default value for the $mynetworks parameter. Possible values: "subnet", "host", "class", "hash", "static". Leave empty to use postfix build-in default value. +postfix_mynetworks_style: "" + +## @param postfix_myorigin The domain name that locally-posted mail appears to come from, and that locally-posted mail is delivered to. Leave empty to use postfix build-in default value. +postfix_myorigin: "" + +## @param postfix_non_smtpd_milters [array] A list of Milter (mail filter) applications for new mail that does not arrive via the Postfix smtpd(8) server. This includes local submission via the sendmail(1) command line, new mail that arrives via the Postfix qmqpd(8) server, and old mail that is re-injected into the queue with "postsuper -r". +postfix_non_smtpd_milters: [] + +## @param postfix_proxy_interfaces Public IP address when Postfix runs behind a proxy or NAT +postfix_proxy_interfaces: "" + +## @param postfix_recipient_canonical_maps [array] Recipient address rewriting. Assembled from enabled LMDB sources. Empty items are filtered out by the template. +postfix_recipient_canonical_maps: +- "{{ postfix_lmdb_recipient_canonical_maps_table if postfix_lmdb_enabled and postfix_lmdb_recipient_canonical_maps_enabled else '' }}" + +## @param postfix_recipient_delimiter The character that separates the local part of an email address from the extension. +postfix_recipient_delimiter: "" + +## @param postfix_relay_domains [array] Domains for which this server acts as relay. The order is important, as the first match is used. The SMTP server validates recipient addresses with $relay_recipient_maps and rejects non-existent recipients. Empty items are filtered out by the template. +postfix_relay_domains: +- "{{ postfix_lmdb_relay_domains_table if postfix_lmdb_enabled and postfix_lmdb_relay_domains_enabled else '' }}" +- "{{ postfix_pgsql_relay_domains_table if postfix_pgsql_enabled and postfix_pgsql_relay_domains_enabled else '' }}" + +## @param postfix_relay_recipient_maps [array] Valid recipients in relay domains. The order is important, as the first match is used. Postfix needs to know only if a lookup string is found or not, but it does not use the result from table lookup. Empty items are filtered out by the template. +postfix_relay_recipient_maps: +- "{{ postfix_lmdb_relay_recipients_table if postfix_lmdb_enabled and postfix_lmdb_relay_recipients_enabled else '' }}" +- "{{ postfix_pgsql_relay_recipient_maps_table if postfix_pgsql_enabled and postfix_pgsql_relay_recipient_maps_enabled else '' }}" + +## @param postfix_relocated_maps [array] Contact information for relocated users. Assembled from enabled LMDB sources. Empty items are filtered out by the template. +postfix_relocated_maps: +- "{{ postfix_lmdb_relocated_maps_table if postfix_lmdb_enabled and postfix_lmdb_relocated_maps_enabled else '' }}" + +## @param postfix_sender_canonical_maps [array] Sender address rewriting. Assembled from enabled LMDB sources. Empty items are filtered out by the template. +postfix_sender_canonical_maps: +- "{{ postfix_lmdb_sender_canonical_maps_table if postfix_lmdb_enabled and postfix_lmdb_sender_canonical_maps_enabled else '' }}" + +## @param postfix_smtpd_forbid_bare_newline Forbid bare newline in SMTPD. Leave empty to use postfix build-in default value. +postfix_smtpd_forbid_bare_newline: "" + +## @param postfix_smtpd_forbid_bare_newline_exclusions [array] Exclude the specified clients from smtpd_forbid_bare_newline enforcement. Leave empty to use postfix build-in default value. +postfix_smtpd_forbid_bare_newline_exclusions: "" + +## @param postfix_smtp_sasl_password_maps [array] SMTP SASL password maps. Assembled from enabled LMDB sources. Empty items are filtered out by the template. +postfix_smtp_sasl_password_maps: +- "{{ postfix_lmdb_smtp_sasl_password_maps_table if postfix_lmdb_enabled and postfix_lmdb_smtp_sasl_password_maps_enabled else '' }}" + +## @param postfix_smtpd_sender_login_maps [array] SASL login names that own sender addresses. Assembled from enabled LMDB/PgSQL sources. Empty items are filtered out by the template. +postfix_smtpd_sender_login_maps: +- "{{ postfix_lmdb_smtpd_sender_login_maps_table if postfix_lmdb_enabled and postfix_lmdb_smtpd_sender_login_maps_enabled else '' }}" +- "{{ postfix_pgsql_smtpd_sender_login_maps_table if postfix_pgsql_enabled and postfix_pgsql_smtpd_sender_login_maps_enabled else '' }}" + +## @param postfix_relayhost Next-hop destination for non-local mail (e.g. "[smtp.example.com]:587") +# postfix_relayhost: "[smtp.example.com]:587" + +## @param postfix_smtp_sasl_auth_enable Enable SASL authentication for the Postfix SMTP client +postfix_smtp_sasl_auth_enable: false + +## @param postfix_smtp_tls_CAfile Path to the CA certificate file for the Postfix SMTP client. This file is used to verify the server's certificate when establishing a TLS connection. +postfix_smtp_tls_capath: "/etc/ssl/certs" + +## @param postfix_smtp_tls_cert_file Path to the TLS certificate file for the Postfix SMTP client. This file is used to authenticate the client when establishing a TLS connection. +## @param postfix_smtp_tls_key_file Path to the TLS private key file for the Postfix SMTP client. This file is used to authenticate the client when establishing a TLS connection. +postfix_smtp_tls_cert_file: "" +postfix_smtp_tls_key_file: "" + +## @param postfix_smtp_tls_loglevel Log level for the Postfix SMTP client TLS. Possible values: 0 (no logging), 1 (log TLS negotiation), 2 (log TLS negotiation and session parameters), 3 (log TLS negotiation, session parameters, and certificate details). Use -1 to postfix build-in default. +postfix_smtp_tls_loglevel: -1 + +## @param postfix_smtp_tls_mandatory_ciphers TLS ciphers for the Postfix SMTP client when mandatory TLS is required. Leave empty to use postfix build-in default value. +postfix_smtp_tls_mandatory_ciphers: "" + +## @param postfix_smtp_tls_mandatory_protocols TLS protocol versions for the Postfix SMTP client when mandatory TLS is required. Specify a space-separated list of protocols, e.g. "TLSv1.2 TLSv1.3". +postfix_smtp_tls_mandatory_protocols: ">=TLSv1.2" + +## @param postfix_smtp_tls_protocols TLS protocol versions for the Postfix SMTP client. Specify a space-separated list of protocols, e.g. "TLSv1.2 TLSv1.3". +postfix_smtp_tls_protocols: ">=TLSv1.2" + +## @param postfix_smtp_tls_security_level TLS security level for the Postfix SMTP client. Possible values: none, may, encrypt, dane, dane-only, fingerprint, verify, secure. Leave empty to use postfix build-in default value. +postfix_smtp_tls_security_level: "" + +## @param postfix_smtp_tls_session_cache_database Database for caching TLS sessions. Postfix uses this database to cache TLS session parameters for outgoing SMTP connections. +postfix_smtp_tls_session_cache_database: "lmdb:/var/lib/postfix/smtp_scache" + +## @section Postfix SMTP daemon configuration + +## @param postfix_smtpd_banner The text that the Postfix SMTP server sends in response to the EHLO command. Leave empty to use postfix build-in default value. +postfix_smtpd_banner: "" + +## @param postfix_smtpd_data_restrictions [array] Restrictions for the Postfix SMTP server when processing the DATA command. The order is important, as the first match is used. The default configuration does not impose any restrictions on the DATA command. +postfix_smtpd_data_restrictions: [] + +## @param postfix_smtpd_client_restrictions [array] Restrictions for the Postfix SMTP server when processing client connections. The order is important, as the first match is used. The default configuration allows relaying only from trusted networks and authenticated users, and rejects all other clients. +postfix_smtpd_client_restrictions: [] + +## @param postfix_smtpd_end_of_data_restrictions [array] Restrictions for the Postfix SMTP server when processing the END-OF-DATA command. The order is important, as the first match is used. The default configuration does not impose any restrictions on the END-OF-DATA command. +postfix_smtpd_end_of_data_restrictions: [] + +## @param postfix_smtpd_etrn_restrictions [array] Restrictions for the Postfix SMTP server when processing the ETRN command. The order is important, as the first match is used. The default configuration does not impose any restrictions on the ETRN command. +postfix_smtpd_etrn_restrictions: [] + +## @param postfix_smtpd_helo_required Require that a remote SMTP client introduces itself with the HELO or EHLO command. +postfix_smtpd_helo_required: false + +## @param postfix_smtpd_helo_restrictions [array] Restrictions for the Postfix SMTP server when processing HELO/EHLO commands. The order is important, as the first match is used. The default configuration does not impose any restrictions on HELO/EHLO commands. +postfix_smtpd_helo_restrictions: [] + +## @param postfix_smtpd_milters [array] A list of Milter (mail filter) applications for new mail that arrives via the Postfix smtpd(8) server. This includes mail that is submitted via the sendmail(1) command line, new mail that arrives via the Postfix qmqpd(8) server, and old mail that is re-injected into the queue with "postsuper -r". +postfix_smtpd_milters: [] + +## @param postfix_smtpd_recipient_restrictions [array] Restrictions for the Postfix SMTP server when processing recipient addresses +## (RCPT TO). The order is important, as the first match is used. The check_*_access maps are automatically prepended by the +## template based on the postfix_check_*_access_maps variables. +postfix_smtpd_recipient_restrictions: [] + +## @param postfix_smtpd_relay_restrictions [array] Restrictions for the Postfix SMTP server when relaying mail. The order is important, as the first match is used. Leave empty to use postfix build-in default value. +postfix_smtpd_relay_restrictions: [] + +## @param postfix_smtpd_sasl_authenticated_header Add a header to messages that are submitted by authenticated users. +postfix_smtpd_sasl_authenticated_header: false + +## @param postfix_smtpd_sasl_auth_enable Enable SASL authentication in the Postfix SMTP server. By default, the Postfix SMTP server does not offer authentication to clients. +postfix_smtpd_sasl_auth_enable: false + +## @param postfix_smtpd_sasl_path The path to the Postfix SMTP server's SASL authentication socket. Leave empty to use postfix build-in default value. +postfix_smtpd_sasl_path: "" + +## @param postfix_smtpd_sasl_security_options SASL security options for the Postfix SMTP server. Leave empty to use postfix build-in default value. +postfix_smtpd_sasl_security_options: [] + +## @param postfix_smtpd_sasl_tls_security_options SASL security options for the Postfix SMTP server when TLS is used. +postfix_smtpd_sasl_tls_security_options: [] + +## @param postfix_smtpd_sasl_type The SASL plug-in type that the Postfix SMTP server should use for authentication. Leave empty to use postfix build-in default value. +postfix_smtpd_sasl_type: "" + +## @param postfix_smtpd_sender_restrictions [array] Restrictions for the Postfix SMTP server when processing sender addresses. The order is important, as the first match is used. The default configuration allows relaying only from trusted networks and authenticated users, and rejects all other clients. +postfix_smtpd_sender_restrictions: [] + +## @param postfix_smtpd_tls_auth_only Require that clients use TLS when authenticating. +postfix_smtpd_tls_auth_only: false + +## @param postfix_smtpd_tls_CApath Path to the directory containing CA certificates for the Postfix SMTP server. This directory is used to verify client certificates when establishing a TLS connection. +postfix_smtpd_tls_capath: "/etc/ssl/certs" + +## @param postfix_smtpd_tls_loglevel Log level for the Postfix SMTP server TLS. Possible values: 0 (no logging), 1 (log TLS negotiation), 2 (log TLS negotiation and session parameters), 3 (log TLS negotiation, session parameters, and certificate details). Use -1 to postfix build-in default. +postfix_smtpd_tls_loglevel: -1 + +## @param postfix_smtpd_tls_mandatory_ciphers TLS ciphers for the Postfix SMTP server when mandatory TLS is required. Leave empty to use postfix build-in default value. +postfix_smtpd_tls_mandatory_ciphers: "" + +## @param postfix_smtpd_tls_cert_file Path to the TLS certificate file for the Postfix SMTP server. This file is used to authenticate the server when establishing a TLS connection. +## @param postfix_smtpd_tls_key_file Path to the TLS private key file for the Postfix SMTP server. This file is used to authenticate the server when establishing a TLS connection. +postfix_smtpd_tls_cert_file: "" +postfix_smtpd_tls_key_file: "" + +## @param postfix_smtpd_tls_mandatory_protocols TLS protocol versions for the Postfix SMTP server when mandatory TLS is required. +postfix_smtpd_tls_mandatory_protocols: ">=TLSv1.2" + +## @param postfix_smtpd_tls_protocols TLS protocol versions for the Postfix SMTP server. +postfix_smtpd_tls_protocols: ">=TLSv1.2" + +## @param postfix_smtpd_tls_security_level TLS security level for the Postfix SMTP server. Possible values: none, may, encrypt, dane, dane-only, fingerprint, verify, secure. +postfix_smtpd_tls_security_level: "may" + +## @param postfix_smtpd_tls_session_cache_database Database for caching TLS sessions. Postfix uses this database to cache TLS session parameters for incoming SMTP connections. +postfix_smtpd_tls_session_cache_database: "lmdb:/var/lib/postfix/smtpd_scache" + +## @param postfix_strict_rfc821_envelopes Require that addresses received in SMTP MAIL FROM and RCPT TO commands are valid according to RFC 821. +postfix_strict_rfc821_envelopes: false + +## @param postfix_tls_policy_maps [array] Per-destination TLS security policy. Assembled from enabled LMDB sources. Empty items are filtered out by the template. +postfix_tls_policy_maps: +- "{{ postfix_lmdb_tls_policy_maps_table if postfix_lmdb_enabled and postfix_lmdb_tls_policy_maps_enabled else '' }}" + +## @param postfix_tls_preempt_cipherlist Preempt the cipher list order with the server's preference. +postfix_tls_preempt_cipherlist: false + +## @param postfix_tls_ssl_options List or bit-mask of OpenSSL options to enable. +postfix_tls_ssl_options: "" + +## @param postfix_transport_maps [array] Custom transport routing rules. Assembled from enabled LMDB sources. Empty items are filtered out by the template. +postfix_transport_maps: +- "{{ postfix_lmdb_transport_maps_table if postfix_lmdb_enabled and postfix_lmdb_transport_maps_enabled else '' }}" + +## @param postfix_virtual_alias_domains [array] Virtual alias domains. Leave empty to use postfix build-in default value. +postfix_virtual_alias_domains: "" + +## @param postfix_virtual_alias_maps [array] Virtual alias address mappings. Assembled from enabled LMDB/PgSQL sources. Empty items are filtered out by the template. +postfix_virtual_alias_maps: +- "{{ postfix_lmdb_virtual_alias_maps_table if postfix_lmdb_enabled and postfix_lmdb_virtual_alias_maps_enabled else '' }}" +- "{{ postfix_pgsql_virtual_alias_maps_table if postfix_pgsql_enabled and postfix_pgsql_virtual_alias_maps_enabled else '' }}" +- "{{ postfix_pgsql_virtual_alias_domain_maps_table if postfix_pgsql_enabled and postfix_pgsql_virtual_alias_maps_enabled else '' }}" +- "{{ postfix_pgsql_virtual_alias_domain_catchall_maps_table if postfix_pgsql_enabled and postfix_pgsql_virtual_alias_maps_enabled else '' }}" + +## @param postfix_virtual_mailbox_domains [array] Virtual mailbox domains. Assembled from enabled LMDB/PgSQL sources. Empty items are filtered out by the template. +postfix_virtual_mailbox_domains: +- "{{ postfix_lmdb_virtual_mailbox_domains_table if postfix_lmdb_enabled and postfix_lmdb_virtual_mailbox_domains_enabled else '' }}" +- "{{ postfix_pgsql_virtual_mailbox_domains_table if postfix_pgsql_enabled and postfix_pgsql_virtual_mailbox_domains_enabled else '' }}" + +## @param postfix_virtual_mailbox_limit The maximal size in bytes of an individual virtual(8) mailbox or maildir file, or zero (no limit). Use -1 to postfix build-in default. +postfix_virtual_mailbox_limit: -1 + +## @param postfix_virtual_mailbox_maps [array] Valid virtual mailbox addresses. Assembled from enabled LMDB/PgSQL sources. Empty items are filtered out by the template. +postfix_virtual_mailbox_maps: +- "{{ postfix_lmdb_virtual_mailbox_maps_table if postfix_lmdb_enabled and postfix_lmdb_virtual_mailbox_maps_enabled else '' }}" +- "{{ postfix_pgsql_virtual_mailbox_maps_table if postfix_pgsql_enabled and postfix_pgsql_virtual_mailbox_maps_enabled else '' }}" +- "{{ postfix_pgsql_virtual_alias_domain_mailbox_maps_table if postfix_pgsql_enabled and postfix_pgsql_virtual_mailbox_maps_enabled else '' }}" + +## @param postfix_virtual_transport The transport method for virtual mailboxes. For example via tcp, lmtp:[127.0.0.1] or unix socket lmtp:unix:private/lmpt-sock. Leave empty to use postfix build-in default value. +postfix_virtual_transport: "" + + +## @section LMDB integration +## @param postfix_lmdb_enabled Enable LMDB lookup tables for virtual maps +postfix_lmdb_enabled: false + +## @param postfix_lmdb_canonical_maps_enabled Enable LMDB canonical maps lookup table. +## @param postfix_lmdb_canonical_maps_table LMDB lookup table URI for canonical maps. +## @param postfix_lmdb_canonical_maps_table_entries [array] Address rewriting entries for both sender and recipient +## @param postfix_lmdb_canonical_maps_table_entries[].origin Original address or domain pattern +## @param postfix_lmdb_canonical_maps_table_entries[].replacement Replacement address or domain +postfix_lmdb_canonical_maps_enabled: false +postfix_lmdb_canonical_maps_table: "lmdb:/etc/postfix/canonical_maps" +postfix_lmdb_canonical_maps_table_entries: [] +# - origin: "user@ugly.domain" +# replacement: "user@pretty.domain" +# - origin: "@old.domain" +# replacement: "@new.domain" + +## @param postfix_lmdb_check_client_access_maps_enabled Enable LMDB check_client_access lookup table. +## @param postfix_lmdb_check_client_access_maps_table LMDB lookup table URI for client access control. +## @param postfix_lmdb_check_client_access_maps_table_entries [array] Access control entries by client hostname or IP +## @param postfix_lmdb_check_client_access_maps_table_entries[].pattern Hostname, domain, IP address or CIDR range +## @param postfix_lmdb_check_client_access_maps_table_entries[].action Action to take (OK, REJECT, DUNNO, INFO) +## @param postfix_lmdb_check_client_access_maps_table_entries[].reason [optional] Custom message (used with REJECT or INFO) +postfix_lmdb_check_client_access_maps_enabled: false +postfix_lmdb_check_client_access_maps_table: "lmdb:/etc/postfix/check_client_access_maps" +postfix_lmdb_check_client_access_maps_table_entries: [] +# - pattern: "example.local" +# action: "OK" +# - pattern: "123.123.123.0/24" +# action: "REJECT" +# reason: "Spam source" + +## @param postfix_lmdb_check_helo_access_maps_enabled Enable LMDB check_helo_access lookup table. +## @param postfix_lmdb_check_helo_access_maps_table LMDB lookup table URI for HELO/EHLO access control. +## @param postfix_lmdb_check_helo_access_maps_table_entries [array] Access control entries by HELO/EHLO hostname +## @param postfix_lmdb_check_helo_access_maps_table_entries[].pattern Hostname, domain, IP address or CIDR range +## @param postfix_lmdb_check_helo_access_maps_table_entries[].action Action to take (OK, REJECT, DUNNO, INFO) +## @param postfix_lmdb_check_helo_access_maps_table_entries[].reason [optional] Custom message (used with REJECT or INFO) +postfix_lmdb_check_helo_access_maps_enabled: false +postfix_lmdb_check_helo_access_maps_table: "lmdb:/etc/postfix/check_helo_access_maps" +postfix_lmdb_check_helo_access_maps_table_entries: [] +# - pattern: "spoofed.domain" +# action: "REJECT" +# reason: "Forged HELO" +# - pattern: "trusted.domain" +# action: "OK" + +## @param postfix_lmdb_check_recipient_access_maps_enabled Enable LMDB check_recipient_access lookup table. +## @param postfix_lmdb_check_recipient_access_maps_table LMDB lookup table URI for recipient access control. +## @param postfix_lmdb_check_recipient_access_maps_table_entries [array] Access control entries by recipient address +## @param postfix_lmdb_check_recipient_access_maps_table_entries[].pattern Email address, localpart@ or domain +## @param postfix_lmdb_check_recipient_access_maps_table_entries[].action Action to take (OK, REJECT, DUNNO, INFO) +## @param postfix_lmdb_check_recipient_access_maps_table_entries[].reason [optional] Custom message (used with REJECT or INFO) +postfix_lmdb_check_recipient_access_maps_enabled: false +postfix_lmdb_check_recipient_access_maps_table: "lmdb:/etc/postfix/check_recipient_access_maps" +postfix_lmdb_check_recipient_access_maps_table_entries: [] +# - pattern: "postmaster@example.local" +# action: "OK" +# - pattern: "blocked@example.local" +# action: "REJECT" +# reason: "Mailbox disabled" + +## @param postfix_lmdb_check_sender_access_maps_enabled Enable LMDB check_sender_access lookup table. +## @param postfix_lmdb_check_sender_access_maps_table LMDB lookup table URI for sender access control. +## @param postfix_lmdb_check_sender_access_maps_table_entries [array] Access control entries by sender address +## @param postfix_lmdb_check_sender_access_maps_table_entries[].pattern Email address, localpart@ or domain +## @param postfix_lmdb_check_sender_access_maps_table_entries[].action Action to take (OK, REJECT, DUNNO, INFO) +## @param postfix_lmdb_check_sender_access_maps_table_entries[].reason [optional] Custom message (used with REJECT or INFO) +postfix_lmdb_check_sender_access_maps_enabled: false +postfix_lmdb_check_sender_access_maps_table: "lmdb:/etc/postfix/check_sender_access_maps" +postfix_lmdb_check_sender_access_maps_table_entries: [] +# - pattern: "spammer@example.local" +# action: "REJECT" +# reason: "Sender blocked" +# - pattern: ".trusted.domain" +# action: "OK" + +## @param postfix_lmdb_recipient_canonical_maps_enabled Enable LMDB recipient canonical maps lookup table. +## @param postfix_lmdb_recipient_canonical_maps_table LMDB lookup table URI for recipient canonical maps. +## @param postfix_lmdb_recipient_canonical_maps_table_entries [array] Recipient address rewriting entries +## @param postfix_lmdb_recipient_canonical_maps_table_entries[].origin Original recipient address or domain +## @param postfix_lmdb_recipient_canonical_maps_table_entries[].replacement Replacement recipient address or domain +postfix_lmdb_recipient_canonical_maps_enabled: false +postfix_lmdb_recipient_canonical_maps_table: "lmdb:/etc/postfix/recipient_canonical_maps" +postfix_lmdb_recipient_canonical_maps_table_entries: [] +# - origin: "old-user@example.local" +# replacement: "new-user@example.local" +# - origin: "@old.domain" +# replacement: "@new.domain" + +## @param postfix_lmdb_relay_domains_enabled Enable LMDB relay domain lookup table. +## @param postfix_lmdb_relay_domains_table LMDB lookup table URI for relay domains. +## @param postfix_lmdb_relay_domains_table_entries [array] Domains for which this server acts as relay +## @param postfix_lmdb_relay_domains_table_entries[].domain Domain or subdomain pattern to match +## @param postfix_lmdb_relay_domains_table_entries[].action Action to take (OK, REJECT, DUNNO, etc.) +## @param postfix_lmdb_relay_domains_table_entries[].reason [optional] Custom rejection message (only used with REJECT) +postfix_lmdb_relay_domains_enabled: false +postfix_lmdb_relay_domains_table: "lmdb:/etc/postfix/relay_domain_maps" +postfix_lmdb_relay_domains_table_entries: [] +# - domain: "example.com" +# action: "OK" +# - domain: ".example.com" +# action: "OK" +# - domain: "untrusted.org" +# action: "REJECT" +# reason: "No relay for this domain" + +## @param postfix_lmdb_relay_recipients_enabled Enable LMDB relay recipient lookup table. +## @param postfix_lmdb_relay_recipients_table LMDB lookup table URI for relay recipients. +## @param postfix_lmdb_relay_recipients_table_entries [array] Valid recipients in relay domains +## @param postfix_lmdb_relay_recipients_table_entries[].recipient Recipient address or @domain wildcard +## @param postfix_lmdb_relay_recipients_table_entries[].action Action to take (OK, REJECT, DUNNO, etc.) +## @param postfix_lmdb_relay_recipients_table_entries[].reason [optional] Custom rejection message (only used with REJECT) +postfix_lmdb_relay_recipients_enabled: false +postfix_lmdb_relay_recipients_table: "lmdb:/etc/postfix/relay_recipient_maps" +postfix_lmdb_relay_recipients_table_entries: [] +# - recipient: "@example.com" +# action: "OK" +# - recipient: "admin@example.com" +# action: "OK" +# - recipient: "spammer@example.com" +# action: "REJECT" +# reason: "User unknown" + +## @param postfix_lmdb_relocated_maps_enabled Enable LMDB relocated maps lookup table. +## @param postfix_lmdb_relocated_maps_table LMDB lookup table URI for relocated maps. +## @param postfix_lmdb_relocated_maps_table_entries [array] Contact information for relocated users +## @param postfix_lmdb_relocated_maps_table_entries[].old_address Former address that no longer exists +## @param postfix_lmdb_relocated_maps_table_entries[].new_address New contact address for the user +postfix_lmdb_relocated_maps_enabled: false +postfix_lmdb_relocated_maps_table: "lmdb:/etc/postfix/relocated_maps" +postfix_lmdb_relocated_maps_table_entries: [] +# - old_address: "alice@example.local" +# new_address: "alice@newdomain.local" +# - old_address: "bob@example.local" +# new_address: "bob@otherdomain.local" + +## @param postfix_lmdb_sender_canonical_maps_enabled Enable LMDB sender canonical maps lookup table. +## @param postfix_lmdb_sender_canonical_maps_table LMDB lookup table URI for sender canonical maps. +## @param postfix_lmdb_sender_canonical_maps_table_entries [array] Sender address rewriting entries +## @param postfix_lmdb_sender_canonical_maps_table_entries[].origin Original sender address or domain +## @param postfix_lmdb_sender_canonical_maps_table_entries[].replacement Replacement sender address or domain +postfix_lmdb_sender_canonical_maps_enabled: false +postfix_lmdb_sender_canonical_maps_table: "lmdb:/etc/postfix/sender_canonical_maps" +postfix_lmdb_sender_canonical_maps_table_entries: [] +# - origin: "user@ugly.domain" +# replacement: "user@pretty.domain" +# - origin: "@internal.domain" +# replacement: "@public.domain" + +## @param postfix_lmdb_smtp_sasl_password_maps_enabled Enable LMDB SMTP SASL password maps lookup table. +## @param postfix_lmdb_smtp_sasl_password_maps_table LMDB lookup table URI for SMTP SASL password maps. +## @param postfix_lmdb_smtp_sasl_password_maps_table_entries [array] SASL credentials for relay host authentication +## @param postfix_lmdb_smtp_sasl_password_maps_table_entries[].destination Relay host or domain to authenticate against +## @param postfix_lmdb_smtp_sasl_password_maps_table_entries[].username SASL username +## @param postfix_lmdb_smtp_sasl_password_maps_table_entries[].password SASL password +postfix_lmdb_smtp_sasl_password_maps_enabled: false +postfix_lmdb_smtp_sasl_password_maps_table: "lmdb:/etc/postfix/sasl_password_maps" +postfix_lmdb_smtp_sasl_password_maps_table_entries: [] +# - destination: "[smtp.example.com]:587" +# username: "user" +# password: "secret" + +## @param postfix_lmdb_smtpd_sender_login_maps_enabled Enable LMDB sender login lookup table. +## @param postfix_lmdb_smtpd_sender_login_maps_table LMDB lookup table URI for sender login maps. +## @param postfix_lmdb_smtpd_sender_login_maps_table_entries [array] SASL login names that own sender addresses +## @param postfix_lmdb_smtpd_sender_login_maps_table_entries[].address Sender address (user@domain, user, or @domain) +## @param postfix_lmdb_smtpd_sender_login_maps_table_entries[].login SASL login name that owns the address +postfix_lmdb_smtpd_sender_login_maps_enabled: false +postfix_lmdb_smtpd_sender_login_maps_table: "lmdb:/etc/postfix/smtpd_sender_login_maps" +postfix_lmdb_smtpd_sender_login_maps_table_entries: [] +# - address: "user@example.com" +# login: "user@example.com" +# - address: "@example.com" +# login: "admin@example.com" + +## @param postfix_lmdb_tls_policy_maps_enabled Enable LMDB TLS policy maps lookup table. +## @param postfix_lmdb_tls_policy_maps_table LMDB lookup table URI for TLS policy maps. +## @param postfix_lmdb_tls_policy_maps_table_entries [array] Per-destination TLS security policy +## @param postfix_lmdb_tls_policy_maps_table_entries[].destination Domain, subdomain or [host]:port pattern +## @param postfix_lmdb_tls_policy_maps_table_entries[].policy TLS policy level (none, may, encrypt, verify, secure) +postfix_lmdb_tls_policy_maps_enabled: false +postfix_lmdb_tls_policy_maps_table: "lmdb:/etc/postfix/tls_policy_maps" +postfix_lmdb_tls_policy_maps_table_entries: [] +# - destination: "example.com" +# policy: "encrypt" +# - destination: "[mail.example.org]:587" +# policy: "secure match=nexthop" + +## @param postfix_lmdb_transport_maps_enabled Enable LMDB transport maps lookup table. +## @param postfix_lmdb_transport_maps_table LMDB lookup table URI for transport maps. +## @param postfix_lmdb_transport_maps_table_entries [array] Custom transport routing rules +## @param postfix_lmdb_transport_maps_table_entries[].pattern Domain or address pattern to match +## @param postfix_lmdb_transport_maps_table_entries[].transport Transport and next-hop destination +postfix_lmdb_transport_maps_enabled: false +postfix_lmdb_transport_maps_table: "lmdb:/etc/postfix/transport_maps" +postfix_lmdb_transport_maps_table_entries: [] +# - pattern: "example.com" +# transport: "smtp:[192.168.178.14]:25" +# - pattern: ".example.com" +# transport: "smtp:[192.168.178.14]:25" + +## @param postfix_lmdb_virtual_alias_maps_enabled Enable LMDB virtual alias lookup table. +## @param postfix_lmdb_virtual_alias_maps_table LMDB lookup table URI for virtual alias maps. +## @param postfix_lmdb_virtual_alias_maps_table_entries [array] Virtual alias address mappings +## @param postfix_lmdb_virtual_alias_maps_table_entries[].source Source address or @domain pattern +## @param postfix_lmdb_virtual_alias_maps_table_entries[].destination Destination address to forward to +postfix_lmdb_virtual_alias_maps_enabled: false +postfix_lmdb_virtual_alias_maps_table: "lmdb:/etc/postfix/virtual_alias_maps" +postfix_lmdb_virtual_alias_maps_table_entries: [] +# - source: "info@example.com" +# destination: "admin@example.com" +# - source: "@example.com" +# destination: "catchall@example.com" + +## @param postfix_lmdb_virtual_mailbox_domains_enabled Enable LMDB virtual mailbox domain lookup table. +## @param postfix_lmdb_virtual_mailbox_domains_table LMDB lookup table URI for virtual mailbox domains. +## @param postfix_lmdb_virtual_mailbox_domains_table_entries [array] Virtual mailbox domain entries +## @param postfix_lmdb_virtual_mailbox_domains_table_entries[].domain Domain name +## @param postfix_lmdb_virtual_mailbox_domains_table_entries[].action Action (typically OK) +postfix_lmdb_virtual_mailbox_domains_enabled: false +postfix_lmdb_virtual_mailbox_domains_table: "lmdb:/etc/postfix/virtual_mailbox_domains" +postfix_lmdb_virtual_mailbox_domains_table_entries: [] +# - domain: "example.com" +# action: "OK" +# - domain: "other.com" +# action: "OK" + +## @param postfix_lmdb_virtual_mailbox_maps_enabled Enable LMDB virtual mailbox maps lookup table. +## @param postfix_lmdb_virtual_mailbox_maps_table LMDB lookup table URI for virtual mailbox maps. +## @param postfix_lmdb_virtual_mailbox_maps_table_entries [array] Valid virtual mailbox addresses +## @param postfix_lmdb_virtual_mailbox_maps_table_entries[].address Email address or @domain pattern +## @param postfix_lmdb_virtual_mailbox_maps_table_entries[].action Action (typically OK) +postfix_lmdb_virtual_mailbox_maps_enabled: false +postfix_lmdb_virtual_mailbox_maps_table: "lmdb:/etc/postfix/virtual_mailbox_maps" +postfix_lmdb_virtual_mailbox_maps_table_entries: [] +# - address: "user@example.com" +# action: "OK" +# - address: "@example.com" +# action: "OK" + + +## @section PostgreSQL integration +## @param postfix_pgsql_enabled Enable PostgreSQL lookup tables for virtual maps +## @param postfix_pgsql_username PostgreSQL database user for Postfix lookups +## @param postfix_pgsql_password PostgreSQL database password for Postfix lookups +## @param postfix_pgsql_host PostgreSQL database host +## @param postfix_pgsql_port PostgreSQL database port +## @param postfix_pgsql_name PostgreSQL database name +postfix_pgsql_enabled: false +postfix_pgsql_username: "" +postfix_pgsql_password: "" +postfix_pgsql_host: "localhost" +postfix_pgsql_port: 5432 +postfix_pgsql_name: "postfix" + +## @param postfix_pgsql_relay_domains_enabled Enable PostgreSQL relay domain lookup. +## @param postfix_pgsql_relay_domains_table PostgreSQL lookup table URI for relay domains. +## @param postfix_pgsql_relay_domains_query SQL query to check if a domain is a relay domain. +postfix_pgsql_relay_domains_enabled: false +postfix_pgsql_relay_domains_table: "proxy:pgsql:/etc/postfix/pgsql_relay_domain_maps.cf" +postfix_pgsql_relay_domains_query: "" + +## @param postfix_pgsql_relay_recipient_maps_enabled Enable PostgreSQL relay recipient lookup. +## @param postfix_pgsql_relay_recipient_maps_table PostgreSQL lookup table URI for relay recipients. +## @param postfix_pgsql_relay_recipient_maps_query SQL query to check if a recipient is valid in a relay domain. +postfix_pgsql_relay_recipient_maps_enabled: false +postfix_pgsql_relay_recipient_maps_table: "proxy:pgsql:/etc/postfix/pgsql_relay_recipient_maps.cf" +postfix_pgsql_relay_recipient_maps_query: "" + +## @param postfix_pgsql_smtpd_sender_login_maps_enabled Enable PostgreSQL sender login lookup. +## @param postfix_pgsql_smtpd_sender_login_maps_table PostgreSQL lookup table URI for sender login maps. +## @param postfix_pgsql_smtpd_sender_login_maps_query SQL query to map sender addresses to login names. +postfix_pgsql_smtpd_sender_login_maps_enabled: false +postfix_pgsql_smtpd_sender_login_maps_table: "proxy:pgsql:/etc/postfix/pgsql_sender_login_maps.cf" +postfix_pgsql_smtpd_sender_login_maps_query: "" + +## @param postfix_pgsql_virtual_alias_maps_enabled Enable PostgreSQL virtual alias lookup. +## @param postfix_pgsql_virtual_alias_maps_table PostgreSQL lookup table URI for virtual alias maps. +## @param postfix_pgsql_virtual_alias_maps_query SQL query for virtual alias resolution. +postfix_pgsql_virtual_alias_maps_enabled: false +postfix_pgsql_virtual_alias_maps_table: "proxy:pgsql:/etc/postfix/pgsql_virtual_alias_maps.cf" +postfix_pgsql_virtual_alias_maps_query: "" + +## @param postfix_pgsql_virtual_alias_domain_maps_enabled Enable PostgreSQL virtual alias domain lookup. +## @param postfix_pgsql_virtual_alias_domain_maps_table PostgreSQL lookup table URI for virtual alias domain maps. +## @param postfix_pgsql_virtual_alias_domain_maps_query SQL query for virtual alias domain resolution. The query should return a single row with a single column named "FORWARD TO". +postfix_pgsql_virtual_alias_domain_maps_enabled: false +postfix_pgsql_virtual_alias_domain_maps_table: "proxy:pgsql:/etc/postfix/pgsql_virtual_alias_domain_maps.cf" +postfix_pgsql_virtual_alias_domain_maps_query: "" + +## @param postfix_pgsql_virtual_alias_domain_catchall_maps_enabled Enable PostgreSQL virtual alias domain catchall lookup. +## @param postfix_pgsql_virtual_alias_domain_catchall_maps_table PostgreSQL lookup table URI for virtual alias domain catchall maps. +## @param postfix_pgsql_virtual_alias_domain_catchall_maps_query SQL query for virtual alias domain catchall resolution. The query should return a single row with a single column named "FORWARD TO". +postfix_pgsql_virtual_alias_domain_catchall_maps_enabled: false +postfix_pgsql_virtual_alias_domain_catchall_maps_table: "proxy:pgsql:/etc/postfix/pgsql_virtual_alias_domain_catchall_maps.cf" +postfix_pgsql_virtual_alias_domain_catchall_maps_query: "" + +## @param postfix_pgsql_virtual_alias_domain_mailbox_maps_enabled Enable PostgreSQL virtual alias domain mailbox lookup. +## @param postfix_pgsql_virtual_alias_domain_mailbox_maps_table PostgreSQL lookup table URI for virtual alias domain mailbox maps. +## @param postfix_pgsql_virtual_alias_domain_mailbox_maps_query SQL query for virtual alias domain mailbox resolution. The query should return a single row with a single column named "FORWARD". +postfix_pgsql_virtual_alias_domain_mailbox_maps_enabled: false +postfix_pgsql_virtual_alias_domain_mailbox_maps_table: "proxy:pgsql:/etc/postfix/pgsql_virtual_alias_domain_mailbox_maps.cf" +postfix_pgsql_virtual_alias_domain_mailbox_maps_query: "" + +## @param postfix_pgsql_virtual_mailbox_domains_enabled Enable PostgreSQL virtual mailbox domain lookup. +## @param postfix_pgsql_virtual_mailbox_domains_table PostgreSQL lookup table URI for virtual mailbox domains. +## @param postfix_pgsql_virtual_mailbox_domains_query SQL query for virtual mailbox domain validation. +postfix_pgsql_virtual_mailbox_domains_enabled: false +postfix_pgsql_virtual_mailbox_domains_table: "proxy:pgsql:/etc/postfix/pgsql_virtual_mailbox_domains.cf" +postfix_pgsql_virtual_mailbox_domains_query: "" + +## @param postfix_pgsql_virtual_mailbox_maps_enabled Enable PostgreSQL virtual mailbox maps lookup. +## @param postfix_pgsql_virtual_mailbox_maps_table PostgreSQL lookup table URI for virtual mailbox maps. +## @param postfix_pgsql_virtual_mailbox_maps_query SQL query for virtual mailbox validation. +postfix_pgsql_virtual_mailbox_maps_enabled: false +postfix_pgsql_virtual_mailbox_maps_table: "proxy:pgsql:/etc/postfix/pgsql_virtual_mailbox_maps.cf" +postfix_pgsql_virtual_mailbox_maps_query: "" + +## @param postfix_pgsql_virtual_mailbox_limit_maps_enabled Enable PostgreSQL virtual mailbox limit lookup. +## @param postfix_pgsql_virtual_mailbox_limit_maps_table PostgreSQL lookup table URI for virtual mailbox limit maps. +## @param postfix_pgsql_virtual_mailbox_limit_maps_query SQL query for virtual mailbox limit retrieval. The query should return a single row with a single column named "QUOTA" +postfix_pgsql_virtual_mailbox_limit_maps_enabled: false +postfix_pgsql_virtual_mailbox_limit_maps_table: "proxy:pgsql:/etc/postfix/pgsql_virtual_mailbox_limit_maps.cf" +postfix_pgsql_virtual_mailbox_limit_maps_query: "" + +## @section Regular expression maps +## @param postfix_regexp_enabled Enable regular expression lookup tables for virtual maps +postfix_regexp_enabled: false + +## @param postfix_regexp_submission_header_cleanup_enabled Enable regular expression cleanup of submission headers. This is useful for removing or modifying headers in emails submitted by clients. +postfix_regexp_submission_header_cleanup_enabled: false +postfix_regexp_submission_header_cleanup_table: "regexp:/etc/postfix/submission_header_cleanup" +postfix_regexp_submission_header_cleanup_table_entries: [] +# - pattern: "/^Received:/" +# - pattern: "/^User-Agent:/" +# - pattern: "/^X-Mailer:/" +# - pattern: "/^X-Originating-IP:/" +# - pattern: "/^X-Spam-Flag:/" +# - pattern: "/^X-Spam-Level:/" +# - pattern: "/^X-Spam-Status:/" + + +## @section Postfix services +## @param postfix_services [array] List of Postfix services to configure. The services are defined in the master.cf file. Each service is a dictionary with the following keys: +## - name: The name of the service (e.g., smtp, smtpd, dnsblog, tlsproxy, submission, smtps, etc.) +## - type: The type of the service (e.g., inet, unix, fifo, etc.) +## - private: Whether the service is private (true or false). If the attribute is undefined, the build-in default is used. +## - unprivileged: Whether the service runs as an unprivileged user (true or false). If the attribute is undefined, the build-in default is used. +## - chroot: Whether the service runs in a chroot environment (true or false). If the attribute is undefined, the build-in default is used. +## - wakeup: Whether the service wakes up on demand (true or false). If the attribute is undefined, the build-in default is used. +## - maxproc: The maximum number of processes for the service (integer). If the attribute is undefined, the build-in default is used. +## - command: The command to run for the service (e.g., smtpd, pickup, qmgr, etc.) +## - args: A list of arguments to pass to the command (e.g., -o, -c, etc.) +postfix_services: +- name: "smtp" + type: "inet" + private: false + # unprivileged: true + # chroot: false + # wakeup: false + # maxproc: 100 + command: "smtpd" + args: [] + +- name: "pickup" + type: "unix" + private: false + # unprivileged: true + # chroot: false + wakeup: "60" + maxproc: "1" + command: "pickup" + args: [] + +- name: "cleanup" + type: "unix" + private: false + # unprivileged: true + # chroot: false + # wakeup: "" + maxproc: "0" + command: "cleanup" + args: [] + +- name: "qmgr" + type: "unix" + private: false + # unprivileged: true + # chroot: false + wakeup: "300" + maxproc: "1" + command: "qmgr" + args: [] + +- name: "tlsmgr" + type: "unix" + # private: false + # unprivileged: true + chroot: false + wakeup: "1000?" + maxproc: "1" + command: "tlsmgr" + args: [] + +- name: "rewrite" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + # maxproc: "0" + command: "trivial-rewrite" + args: [] + +- name: "bounce" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + maxproc: "0" + command: "bounce" + args: [] + +- name: "defer" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + maxproc: "0" + command: "bounce" + args: [] + +- name: "trace" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + maxproc: "0" + command: "bounce" + args: [] + +- name: "verify" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + maxproc: "1" + command: "verify" + args: [] + +- name: "flush" + type: "unix" + private: false + # unprivileged: true + chroot: false + wakeup: "1000?" + maxproc: "0" + command: "flush" + args: [] + +- name: "proxymap" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + # maxproc: 100 + command: "proxymap" + args: [] + +- name: "proxywrite" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + maxproc: "1" + command: "proxymap" + args: [] + +- name: "smtp" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + # maxproc: 100 + command: "smtp" + args: [] + +- name: "relay" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + # maxproc: 100 + command: "smtp" + args: + - "-o syslog_name=postfix/$service_name" + # - "-o smtp_helo_timeout=5" + # - "-o smtp_connect_timeout=5" + +- name: "showq" + type: "unix" + private: false + # unprivileged: true + chroot: false + # wakeup: "" + # maxproc: 100 + command: "showq" + args: [] + +- name: "error" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + # maxproc: 100 + command: "error" + args: [] + +- name: "retry" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + # maxproc: 100 + command: "error" + args: [] + +- name: "discard" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + # maxproc: 100 + command: "discard" + args: [] + +- name: "local" + type: "unix" + # private: false + unprivileged: false + chroot: false + # wakeup: "" + # maxproc: 100 + command: "local" + args: [] + +- name: "virtual" + type: "unix" + # private: false + unprivileged: false + chroot: false + # wakeup: "" + # maxproc: 100 + command: "virtual" + args: [] + +- name: "lmtp" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + # maxproc: 100 + command: "lmtp" + args: [] + +- name: "anvil" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + maxproc: "1" + command: "anvil" + args: [] + +- name: "scache" + type: "unix" + # private: false + # unprivileged: true + chroot: false + # wakeup: "" + maxproc: "1" + command: "scache" + args: [] + +- name: "postlog" + type: "unix-dgram" + private: false + # unprivileged: true + chroot: false + # wakeup: "" + maxproc: "1" + command: "postlogd" + args: [] diff --git a/handlers/main.yml b/handlers/main.yml new file mode 100644 index 0000000..469e567 --- /dev/null +++ b/handlers/main.yml @@ -0,0 +1,22 @@ +--- + +- name: Systemd reload + ansible.builtin.systemd: + daemon_reload: true + +- name: Postmap sasl_password_maps + ansible.builtin.command: + cmd: postmap /etc/postfix/sasl_password_maps + register: _postfix_postmap_sasl_cmd + changed_when: false + failed_when: _postfix_postmap_sasl_cmd.rc > 0 + +- name: Restart postfix + ansible.builtin.systemd: + name: postfix + state: restarted + +- name: Reload postfix + ansible.builtin.systemd: + name: postfix.service + state: reloaded diff --git a/meta/argument_specs.yaml b/meta/argument_specs.yaml new file mode 100644 index 0000000..37525b0 --- /dev/null +++ b/meta/argument_specs.yaml @@ -0,0 +1,797 @@ +--- +argument_specs: + main: + short_description: Postfix mail server + description: + - Install and configure a Postfix mail server with PostgreSQL virtual + mailbox support, TLS, SASL authentication, relay capabilities, and + access control. + options: + postfix_canonical_maps: + type: list + elements: str + default: [] + description: Address rewriting for both sender and recipient. Assembled from enabled LMDB sources. + + postfix_lmdb_canonical_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB canonical maps lookup table. + + postfix_lmdb_canonical_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/canonical_maps" + description: LMDB lookup table URI for canonical maps. + + postfix_lmdb_canonical_maps_table_entries: + type: list + elements: dict + default: [] + description: Address rewriting entries for both sender and recipient (LMDB lookup table). + options: + origin: + type: str + required: true + description: Original address or domain pattern. + replacement: + type: str + required: true + description: Replacement address or domain. + + postfix_check_client_access_maps: + type: list + elements: str + default: [] + description: Client access control tables. Assembled from enabled LMDB sources. + + postfix_lmdb_check_client_access_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB check_client_access lookup table. + + postfix_lmdb_check_client_access_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/check_client_access_maps" + description: LMDB lookup table URI for client access control. + + postfix_lmdb_check_client_access_maps_table_entries: + type: list + elements: dict + default: [] + description: Access control entries by client hostname or IP (LMDB lookup table). + options: + pattern: + type: str + required: true + description: Hostname, domain, IP address or CIDR range. + action: + type: str + required: true + description: Action to take (OK, REJECT, DUNNO, INFO). + reason: + type: str + required: false + description: Custom message (used with REJECT or INFO). + + postfix_check_helo_access_maps: + type: list + elements: str + default: [] + description: HELO/EHLO access control tables. Assembled from enabled LMDB sources. + + postfix_lmdb_check_helo_access_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB check_helo_access lookup table. + + postfix_lmdb_check_helo_access_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/check_helo_access_maps" + description: LMDB lookup table URI for HELO/EHLO access control. + + postfix_lmdb_check_helo_access_maps_table_entries: + type: list + elements: dict + default: [] + description: Access control entries by HELO/EHLO hostname (LMDB lookup table). + options: + pattern: + type: str + required: true + description: Hostname, domain, IP address or CIDR range. + action: + type: str + required: true + description: Action to take (OK, REJECT, DUNNO, INFO). + reason: + type: str + required: false + description: Custom message (used with REJECT or INFO). + + postfix_check_recipient_access_maps: + type: list + elements: str + default: [] + description: Recipient access control tables. Assembled from enabled LMDB sources. + + postfix_lmdb_check_recipient_access_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB check_recipient_access lookup table. + + postfix_lmdb_check_recipient_access_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/check_recipient_access_maps" + description: LMDB lookup table URI for recipient access control. + + postfix_lmdb_check_recipient_access_maps_table_entries: + type: list + elements: dict + default: [] + description: Access control entries by recipient address (LMDB lookup table). + options: + pattern: + type: str + required: true + description: Email address, localpart@ or domain. + action: + type: str + required: true + description: Action to take (OK, REJECT, DUNNO, INFO). + reason: + type: str + required: false + description: Custom message (used with REJECT or INFO). + + postfix_check_sender_access_maps: + type: list + elements: str + default: [] + description: Sender access control tables. Assembled from enabled LMDB sources. + + postfix_lmdb_check_sender_access_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB check_sender_access lookup table. + + postfix_lmdb_check_sender_access_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/check_sender_access_maps" + description: LMDB lookup table URI for sender access control. + + postfix_lmdb_check_sender_access_maps_table_entries: + type: list + elements: dict + default: [] + description: Access control entries by sender address (LMDB lookup table). + options: + pattern: + type: str + required: true + description: Email address, localpart@ or domain. + action: + type: str + required: true + description: Action to take (OK, REJECT, DUNNO, INFO). + reason: + type: str + required: false + description: Custom message (used with REJECT or INFO). + + postfix_lmdb_enabled: + type: bool + required: false + default: false + description: Enable LMDB lookup tables for virtual maps. + + postfix_lmdb_relay_domains_enabled: + type: bool + required: false + default: false + description: Enable LMDB relay domain lookup table. + + postfix_lmdb_relay_domains_table: + type: str + required: false + default: "lmdb:/etc/postfix/relay_domain_maps" + description: LMDB lookup table URI for relay domains. + + postfix_lmdb_relay_domains_table_entries: + type: list + elements: dict + default: [] + description: Domains for which this server acts as relay (LMDB lookup table). + options: + domain: + type: str + required: true + description: Domain or subdomain pattern to match. + action: + type: str + required: true + description: Action to take (OK, REJECT, DUNNO, etc.). + reason: + type: str + required: false + description: Custom rejection message (only used with REJECT). + + postfix_lmdb_relay_recipients_enabled: + type: bool + required: false + default: false + description: Enable LMDB relay recipient lookup table. + + postfix_lmdb_relay_recipients_table: + type: str + required: false + default: "lmdb:/etc/postfix/relay_recipient_maps" + description: LMDB lookup table URI for relay recipients. + + postfix_lmdb_relay_recipients_table_entries: + type: list + elements: dict + default: [] + description: Valid recipients in relay domains (LMDB lookup table). + options: + recipient: + type: str + required: true + description: Recipient address or @domain wildcard. + action: + type: str + required: true + description: Action to take (OK, REJECT, DUNNO, etc.). + reason: + type: str + required: false + description: Custom rejection message (only used with REJECT). + + postfix_lmdb_smtpd_sender_login_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB sender login lookup table. + + postfix_lmdb_smtpd_sender_login_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/smtpd_sender_login_maps" + description: LMDB lookup table URI for sender login maps. + + postfix_lmdb_smtpd_sender_login_maps_table_entries: + type: list + elements: dict + default: [] + description: SASL login names that own sender addresses (LMDB lookup table). + options: + address: + type: str + required: true + description: Sender address (user@domain, user, or @domain). + login: + type: str + required: true + description: SASL login name that owns the address. + + postfix_lmdb_virtual_alias_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB virtual alias lookup table. + + postfix_lmdb_virtual_alias_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/virtual_alias_maps" + description: LMDB lookup table URI for virtual alias maps. + + postfix_lmdb_virtual_alias_maps_table_entries: + type: list + elements: dict + default: [] + description: Virtual alias address mappings (LMDB lookup table). + options: + source: + type: str + required: true + description: Source address or @domain pattern. + destination: + type: str + required: true + description: Destination address to forward to. + + postfix_lmdb_virtual_mailbox_domains_enabled: + type: bool + required: false + default: false + description: Enable LMDB virtual mailbox domain lookup table. + + postfix_lmdb_virtual_mailbox_domains_table: + type: str + required: false + default: "lmdb:/etc/postfix/virtual_mailbox_domains" + description: LMDB lookup table URI for virtual mailbox domains. + + postfix_lmdb_virtual_mailbox_domains_table_entries: + type: list + elements: dict + default: [] + description: Virtual mailbox domain entries (LMDB lookup table). + options: + domain: + type: str + required: true + description: Domain name. + action: + type: str + required: true + description: Action (typically OK). + + postfix_lmdb_smtp_sasl_password_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB SMTP SASL password maps lookup table. + + postfix_lmdb_smtp_sasl_password_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/sasl_password_maps" + description: LMDB lookup table URI for SMTP SASL password maps. + + postfix_lmdb_smtp_sasl_password_maps_table_entries: + type: list + elements: dict + default: [] + description: SASL credentials for relay host authentication (LMDB lookup table). + options: + destination: + type: str + required: true + description: Relay host or domain to authenticate against. + username: + type: str + required: true + description: SASL username. + password: + type: str + required: true + description: SASL password. + + postfix_lmdb_sender_canonical_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB sender canonical maps lookup table. + + postfix_lmdb_sender_canonical_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/sender_canonical_maps" + description: LMDB lookup table URI for sender canonical maps. + + postfix_lmdb_sender_canonical_maps_table_entries: + type: list + elements: dict + default: [] + description: Sender address rewriting entries (LMDB lookup table). + options: + origin: + type: str + required: true + description: Original sender address or domain. + replacement: + type: str + required: true + description: Replacement sender address or domain. + + postfix_lmdb_tls_policy_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB TLS policy maps lookup table. + + postfix_lmdb_tls_policy_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/tls_policy_maps" + description: LMDB lookup table URI for TLS policy maps. + + postfix_lmdb_tls_policy_maps_table_entries: + type: list + elements: dict + default: [] + description: Per-destination TLS security policy (LMDB lookup table). + options: + destination: + type: str + required: true + description: Domain, subdomain or [host]:port pattern. + policy: + type: str + required: true + description: TLS policy level (none, may, encrypt, verify, secure). + + postfix_lmdb_recipient_canonical_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB recipient canonical maps lookup table. + + postfix_lmdb_recipient_canonical_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/recipient_canonical_maps" + description: LMDB lookup table URI for recipient canonical maps. + + postfix_lmdb_recipient_canonical_maps_table_entries: + type: list + elements: dict + default: [] + description: Recipient address rewriting entries (LMDB lookup table). + options: + origin: + type: str + required: true + description: Original recipient address or domain. + replacement: + type: str + required: true + description: Replacement recipient address or domain. + + postfix_lmdb_relocated_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB relocated maps lookup table. + + postfix_lmdb_relocated_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/relocated_maps" + description: LMDB lookup table URI for relocated maps. + + postfix_lmdb_relocated_maps_table_entries: + type: list + elements: dict + default: [] + description: Contact information for relocated users (LMDB lookup table). + options: + old_address: + type: str + required: true + description: Former address that no longer exists. + new_address: + type: str + required: true + description: New contact address for the user. + + postfix_lmdb_transport_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB transport maps lookup table. + + postfix_lmdb_transport_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/transport_maps" + description: LMDB lookup table URI for transport maps. + + postfix_lmdb_transport_maps_table_entries: + type: list + elements: dict + default: [] + description: Custom transport routing rules (LMDB lookup table). + options: + pattern: + type: str + required: true + description: Domain or address pattern to match. + transport: + type: str + required: true + description: Transport and next-hop destination. + + postfix_lmdb_virtual_mailbox_maps_enabled: + type: bool + required: false + default: false + description: Enable LMDB virtual mailbox maps lookup table. + + postfix_lmdb_virtual_mailbox_maps_table: + type: str + required: false + default: "lmdb:/etc/postfix/virtual_mailbox_maps" + description: LMDB lookup table URI for virtual mailbox maps. + + postfix_lmdb_virtual_mailbox_maps_table_entries: + type: list + elements: dict + default: [] + description: Valid virtual mailbox addresses (LMDB lookup table). + options: + address: + type: str + required: true + description: Email address or @domain pattern. + action: + type: str + required: true + description: Action (typically OK). + + postfix_pgsql_enabled: + type: bool + required: false + default: false + description: Enable PostgreSQL lookup tables for virtual maps. + + postfix_pgsql_username: + type: str + required: false + default: "my-username" + description: PostgreSQL database user for Postfix lookups. + + postfix_pgsql_password: + type: str + required: false + default: "my-password" + description: PostgreSQL database password for Postfix lookups. + + postfix_pgsql_host: + type: str + required: false + default: "localhost" + description: PostgreSQL database host. + + postfix_pgsql_port: + type: int + required: false + default: 5432 + description: PostgreSQL database port. + + postfix_pgsql_name: + type: str + required: false + default: "postfix" + description: PostgreSQL database name. + + postfix_pgsql_relay_domains_enabled: + type: bool + required: false + default: false + description: Enable PostgreSQL relay domain lookup. + + postfix_pgsql_relay_domains_table: + type: str + required: false + default: "proxy:pgsql:/etc/postfix/pgsql_relay_domain_maps.cf" + description: PostgreSQL lookup table URI for relay domains. + + postfix_pgsql_relay_domains_query: + type: str + required: false + default: "SELECT 'OK' FROM domain d WHERE d.domain='%d' AND d.active='1' AND d.backupmx='1' AND d.transport='relay'" + description: SQL query to check if a domain is a relay domain. + + postfix_pgsql_relay_recipient_maps_enabled: + type: bool + required: false + default: false + description: Enable PostgreSQL relay recipient lookup. + + postfix_pgsql_relay_recipient_maps_table: + type: str + required: false + default: "proxy:pgsql:/etc/postfix/pgsql_relay_recipient_maps.cf" + description: PostgreSQL lookup table URI for relay recipients. + + postfix_pgsql_relay_recipient_maps_query: + type: str + required: false + default: "SELECT 'OK' FROM domain d INNER JOIN mailbox m ON (d.domain = m.domain) WHERE m.local_part='%u' AND m.domain='%d' AND m.active = '1' AND d.active='1' AND d.transport='relay'" + description: SQL query to check if a recipient is valid in a relay domain. + + postfix_pgsql_smtpd_sender_login_maps_enabled: + type: bool + required: false + default: false + description: Enable PostgreSQL sender login lookup. + + postfix_pgsql_smtpd_sender_login_maps_table: + type: str + required: false + default: "proxy:pgsql:/etc/postfix/pgsql_sender_login_maps.cf" + description: PostgreSQL lookup table URI for sender login maps. + + postfix_pgsql_smtpd_sender_login_maps_query: + type: str + required: false + default: "SELECT username FROM mailbox WHERE username='%s' AND active='1'" + description: SQL query to map sender addresses to login names. + + postfix_pgsql_virtual_alias_maps_enabled: + type: bool + required: false + default: false + description: Enable PostgreSQL virtual alias lookup. + + postfix_pgsql_virtual_alias_maps_table: + type: str + required: false + default: "proxy:pgsql:/etc/postfix/pgsql_virtual_alias_maps.cf" + description: PostgreSQL lookup table URI for virtual alias maps. + + postfix_pgsql_virtual_alias_maps_query: + type: str + required: false + default: "SELECT goto FROM alias a WHERE a.address='%s' AND a.active = '1'" + description: SQL query for virtual alias resolution. + + postfix_pgsql_virtual_alias_domain_catchall_maps_query: + type: str + required: false + default: "SELECT goto FROM alias a, alias_domain ad WHERE ad.alias_domain = '%d' and a.address = CONCAT('@', ad.target_domain) AND a.active = '1' AND ad.active='1'" + description: SQL query for alias domain catchall resolution. + + postfix_pgsql_virtual_alias_domain_mailbox_maps_query: + type: str + required: false + default: "SELECT 'OK' FROM mailbox m, alias_domain ad WHERE ad.alias_domain = '%d' and m.username = CONCAT('%u', '@', ad.target_domain) AND m.active = '1' AND ad.active='1'" + description: SQL query for alias domain mailbox validation. + + postfix_pgsql_virtual_alias_domain_maps_query: + type: str + required: false + default: "SELECT goto FROM alias a, alias_domain ad WHERE ad.alias_domain = '%d' and a.address = CONCAT('%u', '@', ad.target_domain) AND a.active = '1' AND ad.active='1'" + description: SQL query for alias domain address resolution. + + postfix_pgsql_virtual_mailbox_domains_enabled: + type: bool + required: false + default: false + description: Enable PostgreSQL virtual mailbox domain lookup. + + postfix_pgsql_virtual_mailbox_domains_table: + type: str + required: false + default: "proxy:pgsql:/etc/postfix/pgsql_virtual_mailbox_domains.cf" + description: PostgreSQL lookup table URI for virtual mailbox domains. + + postfix_pgsql_virtual_mailbox_domains_query: + type: str + required: false + default: "SELECT d.domain FROM domain d WHERE d.domain='%s' AND d.backupmx = '0' AND d.active = '1'" + description: SQL query for virtual mailbox domain validation. + + postfix_pgsql_virtual_mailbox_maps_enabled: + type: bool + required: false + default: false + description: Enable PostgreSQL virtual mailbox maps lookup. + + postfix_pgsql_virtual_mailbox_maps_table: + type: str + required: false + default: "proxy:pgsql:/etc/postfix/pgsql_virtual_mailbox_maps.cf" + description: PostgreSQL lookup table URI for virtual mailbox maps. + + postfix_pgsql_virtual_mailbox_maps_query: + type: str + required: false + default: "SELECT 'OK' FROM mailbox m WHERE m.username='%s' AND active = '1'" + description: SQL query for virtual mailbox validation. + + postfix_pgsql_virtual_mailbox_limit_maps_query: + type: str + required: false + default: "SELECT quota FROM mailbox WHERE username='%s' AND active = '1'" + description: SQL query for mailbox quota lookup. + + postfix_mail_domain: + type: str + required: false + description: FQDN of the mail server, used as certificate name and myhostname. + + postfix_mynetworks: + type: list + elements: str + default: [] + description: Additional IP addresses or CIDR ranges to trust for relaying. + + postfix_proxy_interfaces: + type: str + default: "" + description: Public IP address when Postfix runs behind a proxy or NAT. + + postfix_recipient_canonical_maps: + type: list + elements: str + default: [] + description: Recipient address rewriting. Assembled from enabled LMDB sources. + + postfix_relay_domains: + type: list + elements: str + default: [] + description: Domains for which this server acts as relay. Assembled from enabled LMDB/PgSQL sources. + + postfix_relay_recipient_maps: + type: list + elements: str + default: [] + description: Valid recipients in relay domains. Assembled from enabled LMDB/PgSQL sources. + + postfix_smtpd_sender_login_maps: + type: list + elements: str + default: [] + description: SASL login names that own sender addresses. Assembled from enabled LMDB/PgSQL sources. + + postfix_relayhost: + type: str + required: false + description: Next-hop destination for non-local mail (e.g. "[smtp.example.com]:587"). + + postfix_relocated_maps: + type: list + elements: str + default: [] + description: Contact information for relocated users. Assembled from enabled LMDB sources. + + postfix_smtp_sasl_password_maps: + type: list + elements: str + default: [] + description: SMTP SASL password maps. Assembled from enabled LMDB sources. + + postfix_sender_canonical_maps: + type: list + elements: str + default: [] + description: Sender address rewriting. Assembled from enabled LMDB sources. + + postfix_smtp_sasl_auth_enable: + type: bool + default: false + description: Enable SASL authentication for the Postfix SMTP client. + + postfix_tls_policy_maps: + type: list + elements: str + default: [] + description: Per-destination TLS security policy. Assembled from enabled LMDB sources. + + postfix_transport_maps: + type: list + elements: str + default: [] + description: Custom transport routing rules. Assembled from enabled LMDB sources. + + postfix_virtual_alias_maps: + type: list + elements: str + default: [] + description: Virtual alias address mappings. Assembled from enabled LMDB/PgSQL sources. + + postfix_virtual_mailbox_domains: + type: list + elements: str + default: [] + description: Virtual mailbox domains. Assembled from enabled LMDB/PgSQL sources. + + postfix_virtual_mailbox_maps: + type: list + elements: str + default: [] + description: Valid virtual mailbox addresses. Assembled from enabled LMDB/PgSQL sources. diff --git a/meta/main.yaml b/meta/main.yaml new file mode 100644 index 0000000..e69152f --- /dev/null +++ b/meta/main.yaml @@ -0,0 +1,17 @@ +dependencies: [] +galaxy_info: + author: "Markus Pesch" + company: "Cryptic Systems" + description: "Role to install and maintain a Postfix mail server" + galaxy_tags: + - mta + - postfix + - email + license: "MIT" + min_ansible_version: "2.9" + namespace: volker-raschek + platforms: + - name: ArchLinux + versions: + - all + role_name: "postfix" diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f9b86be --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1389 @@ +{ + "name": "certificate-authority-ansible-role", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "certificate-authority-ansible-role", + "license": "MIT", + "devDependencies": { + "@bitnami/readme-generator-for-helm": "^2.5.0", + "markdownlint-cli": "^0.47.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + } + }, + "node_modules/@bitnami/readme-generator-for-helm": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@bitnami/readme-generator-for-helm/-/readme-generator-for-helm-2.7.2.tgz", + "integrity": "sha512-7eXyJzxQTQj2ajpHlIhadciCCYWOqN8ieaweU25bStHOZowQ2c2CQyjO/bX4gxIf73LoRKxHhEYgLTllJY9SIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "commander": "^13.1.0", + "dot-object": "^2.1.5", + "lodash": "^4.17.21", + "markdown-table": "^2.0.0", + "yaml": "^2.7.0" + }, + "bin": { + "readme-generator": "bin/index.js" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/katex": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.8.tgz", + "integrity": "sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dot-object": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/dot-object/-/dot-object-2.1.5.tgz", + "integrity": "sha512-xHF8EP4XH/Ba9fvAF2LDd5O3IITVolerVV6xvkxoM8zlGEiCUrggpAnHyOoKJKCrhvPcGATFAUwIujj7bRG5UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^6.1.0", + "glob": "^7.1.6" + }, + "bin": { + "dot-object": "bin/dot-object" + } + }, + "node_modules/dot-object/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ignore": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz", + "integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-7.0.0.tgz", + "integrity": "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/linkify-it": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", + "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz", + "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "repeat-string": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/markdownlint": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.40.0.tgz", + "integrity": "sha512-UKybllYNheWac61Ia7T6fzuQNDZimFIpCg2w6hHjgV1Qu0w1TV0LlSgryUGzM0bkKQCBhy2FDhEELB73Kb0kAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark": "4.0.2", + "micromark-core-commonmark": "2.0.3", + "micromark-extension-directive": "4.0.0", + "micromark-extension-gfm-autolink-literal": "2.1.0", + "micromark-extension-gfm-footnote": "2.1.0", + "micromark-extension-gfm-table": "2.1.1", + "micromark-extension-math": "3.1.0", + "micromark-util-types": "2.0.2", + "string-width": "8.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-cli": { + "version": "0.47.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.47.0.tgz", + "integrity": "sha512-HOcxeKFAdDoldvoYDofd85vI8LgNWy8vmYpCwnlLV46PJcodmGzD7COSSBlhHwsfT4o9KrAStGodImVBus31Bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "~14.0.2", + "deep-extend": "~0.6.0", + "ignore": "~7.0.5", + "js-yaml": "~4.1.1", + "jsonc-parser": "~3.3.1", + "jsonpointer": "~5.0.1", + "markdown-it": "~14.1.0", + "markdownlint": "~0.40.0", + "minimatch": "~10.1.1", + "run-con": "~1.3.2", + "smol-toml": "~1.5.2", + "tinyglobby": "~0.2.15" + }, + "bin": { + "markdownlint": "markdownlint.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/markdownlint-cli/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/markdownlint-cli/node_modules/brace-expansion": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/markdownlint-cli/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/markdownlint-cli/node_modules/minimatch": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.3.tgz", + "integrity": "sha512-IF6URNyBX7Z6XfvjpaNy5meRxPZiIf2OqtOoSLs+hLJ9pJAScnM1RjrFcbCaD85y42KcI+oZmKjFIJKYDFjQfg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mdurl": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.1.0.tgz", + "integrity": "sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-directive": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-directive/-/micromark-extension-directive-4.0.0.tgz", + "integrity": "sha512-/C2nqVmXXmiseSSuCdItCMho7ybwwop6RrrRPk0KbOHW21JKoCldC+8rFOaundDoRBUWBnJJcxeA/Kvi34WQXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "parse-entities": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-math": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz", + "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/katex": "^0.16.0", + "devlop": "^1.0.0", + "katex": "^0.16.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/run-con": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.3.tgz", + "integrity": "sha512-Lb7OKM9aaykzyoNiHGhSVCjZsvbyy6qDMp2vDXL+MoCfz3GfNJtHYH7uYsU3QNMyInBk++xx+EZ8xZ8Sxs5fNQ==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~7.0.0", + "minimist": "^1.2.8", + "strip-json-comments": "~3.1.1" + }, + "bin": { + "run-con": "cli.js" + } + }, + "node_modules/smol-toml": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.5.2.tgz", + "integrity": "sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "node_modules/string-width": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..efd1794 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "postfix-ansible-role", + "homepage": "https://git.cryptic.systems/volker.raschek/postfix-ansible-role.git", + "license": "MIT", + "private": true, + "engineStrict": true, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "scripts": { + "readme:lint": "markdownlint *.md -f", + "readme:parameters": "readme-generator -v defaults/main.yaml -r README.md" + }, + "devDependencies": { + "@bitnami/readme-generator-for-helm": "^2.5.0", + "markdownlint-cli": "^0.47.0" + } +} diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..84f88f7 --- /dev/null +++ b/renovate.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "local>volker.raschek/renovate-config:default#master", + "local>volker.raschek/renovate-config:container#master", + "local>volker.raschek/renovate-config:actions#master", + "local>volker.raschek/renovate-config:regexp#master" + ] +} \ No newline at end of file diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..4e0ae86 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,303 @@ +--- + +- name: Install postfix and third party applications + ansible.builtin.package: + name: "{{ item }}" + state: "present" + with_items: + - postfix + - postfix-lmdb + - postfix-mysql + - postfix-pcre + - postfix-pgsql + - s-nail # provides mailx + +- name: Create postfix configuration directory + ansible.builtin.file: + name: "/etc/postfix" + owner: "root" + group: "root" + mode: "0755" + state: "directory" + +- name: Prepare mynetworks + block: + - name: Set postfix_mynetworks + ansible.builtin.set_fact: + postfix_mynetworks: [] + when: postfix_mynetworks is not defined + - name: Append missing local network to postfix_mynetworks + ansible.builtin.set_fact: + postfix_mynetworks: "{{ postfix_mynetworks + [item] }}" + when: item not in postfix_mynetworks + with_items: + - "127.0.0.0/8" + - "[::ffff:127.0.0.0]/104" + - "[::1]/128" + +- name: Install template configs + ansible.builtin.template: + src: "etc/postfix/{{ item }}.j2" + dest: "/etc/postfix/{{ item }}" + owner: "root" + group: postfix + mode: "0640" + with_items: + - main.cf + - master.cf + notify: + - Restart postfix + +- name: Create alias files + when: postfix_alias_database_enabled and item.enabled + ansible.builtin.template: + src: "etc/postfix/{{ item.src }}" + dest: "{{ item.dest | regex_replace('^.*:/', '/') }}" + owner: "root" + group: postfix + mode: "0640" + with_items: + - { src: "aliases.j2", dest: "{{ postfix_alias_database_table }}", enabled: "{{ postfix_alias_database_enabled }}" } + +- name: Create alias db via postalias + when: postfix_alias_database_enabled and item.enabled + ansible.builtin.command: + cmd: postalias "{{ item.dest | regex_replace('^.*:/', '/') }}" + changed_when: false + with_items: + - { src: "aliases.j2", dest: "{{ postfix_alias_database_table }}", enabled: "{{ postfix_alias_database_enabled }}" } + +- name: Remove alias files + when: not postfix_alias_database_enabled or (postfix_alias_database_enabled and not item.enabled) + ansible.builtin.file: + path: "{{ item.dest | regex_replace('^.*:/', '/') }}" + state: "absent" + with_items: + - { src: "aliases.j2", dest: "{{ postfix_alias_database_table }}", enabled: "{{ postfix_alias_database_enabled }}" } + +- name: Remove alias db files + when: not postfix_alias_database_enabled or (postfix_alias_database_enabled and not item.enabled) + ansible.builtin.file: + path: "{{ item.dest | regex_replace('^.*:/', '/') }}.db" + state: "absent" + with_items: + - { src: "aliases.j2", dest: "{{ postfix_alias_database_table }}", enabled: "{{ postfix_alias_database_enabled }}" } + +- name: Create lmdb lookup files + when: postfix_lmdb_enabled and item.enabled + ansible.builtin.template: + src: "etc/postfix/{{ item.src }}" + dest: "{{ item.dest | regex_replace('^.*:/', '/') }}" + owner: "root" + group: postfix + mode: "0640" + with_items: + - { src: "canonical_maps.j2", dest: "{{ postfix_lmdb_canonical_maps_table }}", enabled: "{{ postfix_lmdb_canonical_maps_enabled }}" } + - { src: "check_client_access_maps.j2", dest: "{{ postfix_lmdb_check_client_access_maps_table }}", enabled: "{{ postfix_lmdb_check_client_access_maps_enabled }}" } + - { src: "check_helo_access_maps.j2", dest: "{{ postfix_lmdb_check_helo_access_maps_table }}", enabled: "{{ postfix_lmdb_check_helo_access_maps_enabled }}" } + - { src: "check_recipient_access_maps.j2", dest: "{{ postfix_lmdb_check_recipient_access_maps_table }}", enabled: "{{ postfix_lmdb_check_recipient_access_maps_enabled }}" } + - { src: "check_sender_access_maps.j2", dest: "{{ postfix_lmdb_check_sender_access_maps_table }}", enabled: "{{ postfix_lmdb_check_sender_access_maps_enabled }}" } + - { src: "recipient_canonical_maps.j2", dest: "{{ postfix_lmdb_recipient_canonical_maps_table }}", enabled: "{{ postfix_lmdb_recipient_canonical_maps_enabled }}" } + - { src: "relay_domain_maps.j2", dest: "{{ postfix_lmdb_relay_domains_table }}", enabled: "{{ postfix_lmdb_relay_domains_enabled }}" } + - { src: "relay_recipient_maps.j2", dest: "{{ postfix_lmdb_relay_recipients_table }}", enabled: "{{ postfix_lmdb_relay_recipients_enabled }}" } + - { src: "relocated_maps.j2", dest: "{{ postfix_lmdb_relocated_maps_table }}", enabled: "{{ postfix_lmdb_relocated_maps_enabled }}" } + - { src: "sender_canonical_maps.j2", dest: "{{ postfix_lmdb_sender_canonical_maps_table }}", enabled: "{{ postfix_lmdb_sender_canonical_maps_enabled }}" } + - { src: "smtpd_sender_login_maps.j2", dest: "{{ postfix_lmdb_smtpd_sender_login_maps_table }}", enabled: "{{ postfix_lmdb_smtpd_sender_login_maps_enabled }}" } + - { src: "tls_policy_maps.j2", dest: "{{ postfix_lmdb_tls_policy_maps_table }}", enabled: "{{ postfix_lmdb_tls_policy_maps_enabled }}" } + - { src: "transport_maps.j2", dest: "{{ postfix_lmdb_transport_maps_table }}", enabled: "{{ postfix_lmdb_transport_maps_enabled }}" } + - { src: "virtual_alias_maps.j2", dest: "{{ postfix_lmdb_virtual_alias_maps_table }}", enabled: "{{ postfix_lmdb_virtual_alias_maps_enabled }}" } + - { src: "virtual_mailbox_domains.j2", dest: "{{ postfix_lmdb_virtual_mailbox_domains_table }}", enabled: "{{ postfix_lmdb_virtual_mailbox_domains_enabled }}" } + - { src: "virtual_mailbox_maps.j2", dest: "{{ postfix_lmdb_virtual_mailbox_maps_table }}", enabled: "{{ postfix_lmdb_virtual_mailbox_maps_enabled }}" } + notify: + - Restart postfix + +- name: Create lmdb lookup tables via postmap + when: postfix_lmdb_enabled and item.enabled + ansible.builtin.command: + cmd: postmap "{{ item.dest | regex_replace('^.*:/', '/') }}" + creates: "{{ item.dest | regex_replace('^.*:/', '/') }}.lmdb" + with_items: + - { src: "canonical_maps.j2", dest: "{{ postfix_lmdb_canonical_maps_table }}", enabled: "{{ postfix_lmdb_canonical_maps_enabled }}" } + - { src: "check_client_access_maps.j2", dest: "{{ postfix_lmdb_check_client_access_maps_table }}", enabled: "{{ postfix_lmdb_check_client_access_maps_enabled }}" } + - { src: "check_helo_access_maps.j2", dest: "{{ postfix_lmdb_check_helo_access_maps_table }}", enabled: "{{ postfix_lmdb_check_helo_access_maps_enabled }}" } + - { src: "check_recipient_access_maps.j2", dest: "{{ postfix_lmdb_check_recipient_access_maps_table }}", enabled: "{{ postfix_lmdb_check_recipient_access_maps_enabled }}" } + - { src: "check_sender_access_maps.j2", dest: "{{ postfix_lmdb_check_sender_access_maps_table }}", enabled: "{{ postfix_lmdb_check_sender_access_maps_enabled }}" } + - { src: "recipient_canonical_maps.j2", dest: "{{ postfix_lmdb_recipient_canonical_maps_table }}", enabled: "{{ postfix_lmdb_recipient_canonical_maps_enabled }}" } + - { src: "relay_domain_maps.j2", dest: "{{ postfix_lmdb_relay_domains_table }}", enabled: "{{ postfix_lmdb_relay_domains_enabled }}" } + - { src: "relay_recipient_maps.j2", dest: "{{ postfix_lmdb_relay_recipients_table }}", enabled: "{{ postfix_lmdb_relay_recipients_enabled }}" } + - { src: "relocated_maps.j2", dest: "{{ postfix_lmdb_relocated_maps_table }}", enabled: "{{ postfix_lmdb_relocated_maps_enabled }}" } + - { src: "sender_canonical_maps.j2", dest: "{{ postfix_lmdb_sender_canonical_maps_table }}", enabled: "{{ postfix_lmdb_sender_canonical_maps_enabled }}" } + - { src: "smtpd_sender_login_maps.j2", dest: "{{ postfix_lmdb_smtpd_sender_login_maps_table }}", enabled: "{{ postfix_lmdb_smtpd_sender_login_maps_enabled }}" } + - { src: "tls_policy_maps.j2", dest: "{{ postfix_lmdb_tls_policy_maps_table }}", enabled: "{{ postfix_lmdb_tls_policy_maps_enabled }}" } + - { src: "transport_maps.j2", dest: "{{ postfix_lmdb_transport_maps_table }}", enabled: "{{ postfix_lmdb_transport_maps_enabled }}" } + - { src: "virtual_alias_maps.j2", dest: "{{ postfix_lmdb_virtual_alias_maps_table }}", enabled: "{{ postfix_lmdb_virtual_alias_maps_enabled }}" } + - { src: "virtual_mailbox_domains.j2", dest: "{{ postfix_lmdb_virtual_mailbox_domains_table }}", enabled: "{{ postfix_lmdb_virtual_mailbox_domains_enabled }}" } + - { src: "virtual_mailbox_maps.j2", dest: "{{ postfix_lmdb_virtual_mailbox_maps_table }}", enabled: "{{ postfix_lmdb_virtual_mailbox_maps_enabled }}" } + +- name: Remove lmdb lookup tables + when: not postfix_lmdb_enabled or (postfix_lmdb_enabled and not item.enabled) + ansible.builtin.file: + path: "{{ item.path | regex_replace('^.*:/', '/') }}" + state: "absent" + with_items: + - { path: "{{ postfix_lmdb_canonical_maps_table }}", enabled: "{{ postfix_lmdb_canonical_maps_enabled }}" } + - { path: "{{ postfix_lmdb_check_client_access_maps_table }}", enabled: "{{ postfix_lmdb_check_client_access_maps_enabled }}" } + - { path: "{{ postfix_lmdb_check_helo_access_maps_table }}", enabled: "{{ postfix_lmdb_check_helo_access_maps_enabled }}" } + - { path: "{{ postfix_lmdb_check_recipient_access_maps_table }}", enabled: "{{ postfix_lmdb_check_recipient_access_maps_enabled }}" } + - { path: "{{ postfix_lmdb_check_sender_access_maps_table }}", enabled: "{{ postfix_lmdb_check_sender_access_maps_enabled }}" } + - { path: "{{ postfix_lmdb_recipient_canonical_maps_table }}", enabled: "{{ postfix_lmdb_recipient_canonical_maps_enabled }}" } + - { path: "{{ postfix_lmdb_relay_domains_table }}", enabled: "{{ postfix_lmdb_relay_domains_enabled }}" } + - { path: "{{ postfix_lmdb_relay_recipients_table }}", enabled: "{{ postfix_lmdb_relay_recipients_enabled }}" } + - { path: "{{ postfix_lmdb_relocated_maps_table }}", enabled: "{{ postfix_lmdb_relocated_maps_enabled }}" } + - { path: "{{ postfix_lmdb_sender_canonical_maps_table }}", enabled: "{{ postfix_lmdb_sender_canonical_maps_enabled }}" } + - { path: "{{ postfix_lmdb_smtpd_sender_login_maps_table }}", enabled: "{{ postfix_lmdb_smtpd_sender_login_maps_enabled }}" } + - { path: "{{ postfix_lmdb_tls_policy_maps_table }}", enabled: "{{ postfix_lmdb_tls_policy_maps_enabled }}" } + - { path: "{{ postfix_lmdb_transport_maps_table }}", enabled: "{{ postfix_lmdb_transport_maps_enabled }}" } + - { path: "{{ postfix_lmdb_virtual_alias_maps_table }}", enabled: "{{ postfix_lmdb_virtual_alias_maps_enabled }}" } + - { path: "{{ postfix_lmdb_virtual_mailbox_domains_table }}", enabled: "{{ postfix_lmdb_virtual_mailbox_domains_enabled }}" } + - { path: "{{ postfix_lmdb_virtual_mailbox_maps_table }}", enabled: "{{ postfix_lmdb_virtual_mailbox_maps_enabled }}" } + notify: + - Restart postfix + +- name: Remove lmdb lookup tables + when: not postfix_lmdb_enabled or (postfix_lmdb_enabled and not item.enabled) + ansible.builtin.file: + path: "{{ item.path | regex_replace('^.*:/', '/') }}.lmdb" + state: "absent" + with_items: + - { path: "{{ postfix_lmdb_canonical_maps_table }}", enabled: "{{ postfix_lmdb_canonical_maps_enabled }}" } + - { path: "{{ postfix_lmdb_check_client_access_maps_table }}", enabled: "{{ postfix_lmdb_check_client_access_maps_enabled }}" } + - { path: "{{ postfix_lmdb_check_helo_access_maps_table }}", enabled: "{{ postfix_lmdb_check_helo_access_maps_enabled }}" } + - { path: "{{ postfix_lmdb_check_recipient_access_maps_table }}", enabled: "{{ postfix_lmdb_check_recipient_access_maps_enabled }}" } + - { path: "{{ postfix_lmdb_check_sender_access_maps_table }}", enabled: "{{ postfix_lmdb_check_sender_access_maps_enabled }}" } + - { path: "{{ postfix_lmdb_recipient_canonical_maps_table }}", enabled: "{{ postfix_lmdb_recipient_canonical_maps_enabled }}" } + - { path: "{{ postfix_lmdb_relay_domains_table }}", enabled: "{{ postfix_lmdb_relay_domains_enabled }}" } + - { path: "{{ postfix_lmdb_relay_recipients_table }}", enabled: "{{ postfix_lmdb_relay_recipients_enabled }}" } + - { path: "{{ postfix_lmdb_relocated_maps_table }}", enabled: "{{ postfix_lmdb_relocated_maps_enabled }}" } + - { path: "{{ postfix_lmdb_sender_canonical_maps_table }}", enabled: "{{ postfix_lmdb_sender_canonical_maps_enabled }}" } + - { path: "{{ postfix_lmdb_smtpd_sender_login_maps_table }}", enabled: "{{ postfix_lmdb_smtpd_sender_login_maps_enabled }}" } + - { path: "{{ postfix_lmdb_tls_policy_maps_table }}", enabled: "{{ postfix_lmdb_tls_policy_maps_enabled }}" } + - { path: "{{ postfix_lmdb_transport_maps_table }}", enabled: "{{ postfix_lmdb_transport_maps_enabled }}" } + - { path: "{{ postfix_lmdb_virtual_alias_maps_table }}", enabled: "{{ postfix_lmdb_virtual_alias_maps_enabled }}" } + - { path: "{{ postfix_lmdb_virtual_mailbox_domains_table }}", enabled: "{{ postfix_lmdb_virtual_mailbox_domains_enabled }}" } + - { path: "{{ postfix_lmdb_virtual_mailbox_maps_table }}", enabled: "{{ postfix_lmdb_virtual_mailbox_maps_enabled }}" } + notify: + - Restart postfix + +- name: Create PostgreSQL lookup files + when: postfix_pgsql_enabled and item.enabled + ansible.builtin.template: + src: "etc/postfix/{{ item.src }}" + dest: "{{ item.dest | regex_replace('^.*:/', '/') }}" + owner: "root" + group: postfix + mode: "0640" + with_items: + - { src: "pgsql_relay_domain_maps.cf.j2", dest: "{{ postfix_pgsql_relay_domains_table }}", enabled: "{{ postfix_pgsql_relay_domains_enabled }}" } + - { src: "pgsql_relay_recipient_maps.cf.j2", dest: "{{ postfix_pgsql_relay_recipient_maps_table }}", enabled: "{{ postfix_pgsql_relay_recipient_maps_enabled }}" } + - { src: "pgsql_sender_login_maps.cf.j2", dest: "{{ postfix_pgsql_smtpd_sender_login_maps_table }}", enabled: "{{ postfix_pgsql_smtpd_sender_login_maps_enabled }}" } + - { src: "pgsql_virtual_alias_domain_catchall_maps.cf.j2", dest: "{{ postfix_pgsql_virtual_alias_domain_catchall_maps_table }}", enabled: "{{ postfix_pgsql_virtual_alias_domain_catchall_maps_enabled }}" } + - { src: "pgsql_virtual_alias_domain_mailbox_maps.cf.j2", dest: "{{ postfix_pgsql_virtual_alias_domain_mailbox_maps_table }}", enabled: "{{ postfix_pgsql_virtual_alias_domain_mailbox_maps_enabled }}" } + - { src: "pgsql_virtual_alias_domain_maps.cf.j2", dest: "{{ postfix_pgsql_virtual_alias_domain_maps_table }}", enabled: "{{ postfix_pgsql_virtual_alias_domain_maps_enabled }}" } + - { src: "pgsql_virtual_alias_maps.cf.j2", dest: "{{ postfix_pgsql_virtual_alias_maps_table }}", enabled: "{{ postfix_pgsql_virtual_alias_maps_enabled }}" } + - { src: "pgsql_virtual_mailbox_domains.cf.j2", dest: "{{ postfix_pgsql_virtual_mailbox_domains_table }}", enabled: "{{ postfix_pgsql_virtual_mailbox_domains_enabled }}" } + - { src: "pgsql_virtual_mailbox_limit_maps.cf.j2", dest: "{{ postfix_pgsql_virtual_mailbox_limit_maps_table }}", enabled: "{{ postfix_pgsql_virtual_mailbox_limit_maps_enabled }}" } + - { src: "pgsql_virtual_mailbox_maps.cf.j2", dest: "{{ postfix_pgsql_virtual_mailbox_maps_table }}", enabled: "{{ postfix_pgsql_virtual_mailbox_maps_enabled }}" } + notify: + - Restart postfix + +- name: Remove PostgreSQL lookup files + when: not postfix_pgsql_enabled or (postfix_pgsql_enabled and not item.enabled) + ansible.builtin.file: + path: "{{ item.path | regex_replace('^.*:/', '/') }}" + state: "absent" + with_items: + - { path: "{{ postfix_pgsql_relay_domains_table }}", enabled: "{{ postfix_pgsql_relay_domains_enabled }}" } + - { path: "{{ postfix_pgsql_relay_recipient_maps_table }}", enabled: "{{ postfix_pgsql_relay_recipient_maps_enabled }}" } + - { path: "{{ postfix_pgsql_smtpd_sender_login_maps_table }}", enabled: "{{ postfix_pgsql_smtpd_sender_login_maps_enabled }}" } + - { path: "{{ postfix_pgsql_virtual_alias_domain_catchall_maps_table }}", enabled: "{{ postfix_pgsql_virtual_alias_domain_catchall_maps_enabled }}" } + - { path: "{{ postfix_pgsql_virtual_alias_domain_mailbox_maps_table }}", enabled: "{{ postfix_pgsql_virtual_alias_domain_mailbox_maps_enabled }}" } + - { path: "{{ postfix_pgsql_virtual_alias_domain_maps_table }}", enabled: "{{ postfix_pgsql_virtual_alias_domain_maps_enabled }}" } + - { path: "{{ postfix_pgsql_virtual_alias_maps_table }}", enabled: "{{ postfix_pgsql_virtual_alias_maps_enabled }}" } + - { path: "{{ postfix_pgsql_virtual_mailbox_domains_table }}", enabled: "{{ postfix_pgsql_virtual_mailbox_domains_enabled }}" } + - { path: "{{ postfix_pgsql_virtual_mailbox_limit_maps_table }}", enabled: "{{ postfix_pgsql_virtual_mailbox_limit_maps_enabled }}" } + - { path: "{{ postfix_pgsql_virtual_mailbox_maps_table }}", enabled: "{{ postfix_pgsql_virtual_mailbox_maps_enabled }}" } + notify: + - Restart postfix + +- name: Create Regexp lookup files + when: postfix_regexp_enabled and item.enabled + ansible.builtin.template: + src: "etc/postfix/{{ item.src }}" + dest: "{{ item.dest | regex_replace('^.*:/', '/') }}" + owner: "root" + group: postfix + mode: "0640" + with_items: + - { src: "submission_header_cleanup.j2", dest: "{{ postfix_regexp_submission_header_cleanup_table }}", enabled: "{{ postfix_regexp_submission_header_cleanup_enabled }}" } + notify: + - Restart postfix + +- name: Remove Regexp lookup files + when: not postfix_regexp_enabled or (postfix_regexp_enabled and not item.enabled) + ansible.builtin.file: + path: "{{ item.path | regex_replace('^.*:/', '/') }}" + state: "absent" + with_items: + - { path: "{{ postfix_regexp_submission_header_cleanup_table }}", enabled: "{{ postfix_regexp_submission_header_cleanup_enabled }}" } + notify: + - Restart postfix + +- name: Install SASL relay authentication + when: postfix_smtp_sasl_auth_enable | default(false) + ansible.builtin.template: + src: "etc/postfix/sasl_password_maps.j2" + dest: "/etc/postfix/sasl_password_maps" + owner: "root" + group: "root" + mode: "0600" + notify: + - Postmap sasl_password_maps + - Restart postfix + +- name: Install lets encrypt renewal hook for postfix + tags: [ letsencrypt-hooks ] + when: postfix_myhostname is defined and postfix_myhostname | length > 0 + block: + - name: Create directory for letsencrypt renewal hooks + ansible.builtin.file: + path: "/etc/letsencrypt/renewal-hooks/post" + owner: "root" + group: "root" + mode: "0755" + - name: Create letsencrypt renewal hook for postfix + ansible.builtin.template: + src: "etc/letsencrypt/renewal-hooks/post/postfix.sh.j2" + dest: "/etc/letsencrypt/renewal-hooks/post/postfix.sh" + owner: "root" + group: "root" + mode: "0755" + +- name: Start and enable postfix + ansible.builtin.systemd: + name: postfix + enabled: true + state: started + +- name: Install systemd-email script + ansible.builtin.template: + src: "usr/local/sbin/systemd-email.sh.j2" + dest: "/usr/local/sbin/systemd-email.sh" + owner: "root" + group: "root" + mode: "0755" + +- name: Install systemd-status + ansible.builtin.template: + src: "etc/systemd/system/status-email@.service.j2" + dest: "/etc/systemd/system/status-email@.service" + owner: "root" + group: "root" + mode: "0644" + notify: + - Systemd reload diff --git a/templates/etc/letsencrypt/renewal-hooks/post/postfix.sh.j2 b/templates/etc/letsencrypt/renewal-hooks/post/postfix.sh.j2 new file mode 100644 index 0000000..a7011e5 --- /dev/null +++ b/templates/etc/letsencrypt/renewal-hooks/post/postfix.sh.j2 @@ -0,0 +1,50 @@ +#!/bin/bash + +# +# {{ ansible_managed }} +# + +set -e + +LOG_FILE="${0}.log" + +function logInfo() { + TIMESTAMP=$(date '+%Y-%m-%d_%H:%M:%S' ) + echo "${TIMESTAMP}: INFO: ${1}" + echo "${TIMESTAMP}: INFO: ${1}" >> "${LOG_FILE}" +} + +function logFatal() { + TIMESTAMP=$(date '+%Y-%m-%d_%H:%M:%S' ) + echo "${TIMESTAMP}: FATAL: ${1}" + echo "${TIMESTAMP}: FATAL: ${1}" >> "${LOG_FILE}" + exit 1 +} + +POSTFIX_LETSENCRYPT_DOMAIN="{{ postfix_myhostname }}" + +# The shell variable $RENEWED_DOMAINS will contain a space-delimited +# list of renewed certificate domains (for example, "example.com www.example.com") +# (default: None) +if [ -z ${RENEWED_DOMAINS+x} ]; then + logInfo "Environment variable RENEWED_DOMAINS not defined. Skipping." + exit 0 +fi + +{% raw %} +RENEWED_DOMAINS_ARRAY=(${RENEWED_DOMAINS}) +if [ ${#RENEWED_DOMAINS_ARRAY[@]} -eq 0 ]; then + logInfo "Environment variable RENEWED_DOMAINS_ARRAY is empty. Skipping." + exit 0 +fi +{% endraw %} + +for RENEWED_DOMAIN in "${RENEWED_DOMAINS_ARRAY[@]}"; do + case ${RENEWED_DOMAIN} in + "${POSTFIX_LETSENCRYPT_DOMAIN}") + systemctl restart postfix.service + logInfo "Systemd service restarted!" + exit 0 + ;; + esac +done \ No newline at end of file diff --git a/templates/etc/postfix/aliases.j2 b/templates/etc/postfix/aliases.j2 new file mode 100644 index 0000000..570ecc3 --- /dev/null +++ b/templates/etc/postfix/aliases.j2 @@ -0,0 +1,7 @@ +# +# {{ ansible_managed }} +# + +{% for item in postfix_alias_database_entries | default([]) %} +{{ item.origin }} {{ item.user }} +{% endfor %} diff --git a/templates/etc/postfix/canonical_maps.j2 b/templates/etc/postfix/canonical_maps.j2 new file mode 100644 index 0000000..47fcbf7 --- /dev/null +++ b/templates/etc/postfix/canonical_maps.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +# Replace only recipient and sender e-mail addresses. +# http://www.postfix.org/postconf.5.html#canonical_maps +{% for item in postfix_lmdb_canonical_maps_table_entries | default([]) %} +{{ item.origin }} {{ item.replacement }} +{% endfor %} \ No newline at end of file diff --git a/templates/etc/postfix/check_client_access_maps.j2 b/templates/etc/postfix/check_client_access_maps.j2 new file mode 100644 index 0000000..d6b417c --- /dev/null +++ b/templates/etc/postfix/check_client_access_maps.j2 @@ -0,0 +1,11 @@ +# +# {{ ansible_managed }} +# + +# Search the specified access database for the client hostname, parent domains, +# client IP address, or networks obtained by stripping least significant octets. +# http://www.postfix.org/postconf.5.html#check_client_access +# http://www.postfix.org/access.5.html +{% for item in postfix_lmdb_check_client_access_maps_table_entries | default([]) %} +{{ item.pattern }} {{ item.action }}{% if item.reason is defined %} {{ item.reason }}{% endif %} +{% endfor %} diff --git a/templates/etc/postfix/check_helo_access_maps.j2 b/templates/etc/postfix/check_helo_access_maps.j2 new file mode 100644 index 0000000..83c2e81 --- /dev/null +++ b/templates/etc/postfix/check_helo_access_maps.j2 @@ -0,0 +1,11 @@ +# +# {{ ansible_managed }} +# + +# Search the specified access(5) database for the HELO or EHLO hostname or +# parent domains, and execute the corresponding action. +# http://www.postfix.org/postconf.5.html#check_helo_access +# http://www.postfix.org/access.5.html +{% for item in postfix_lmdb_check_helo_access_maps_table_entries | default([]) %} +{{ item.pattern }} {{ item.action }}{% if item.reason is defined %} {{ item.reason }}{% endif %} +{% endfor %} diff --git a/templates/etc/postfix/check_recipient_access_maps.j2 b/templates/etc/postfix/check_recipient_access_maps.j2 new file mode 100644 index 0000000..7690579 --- /dev/null +++ b/templates/etc/postfix/check_recipient_access_maps.j2 @@ -0,0 +1,11 @@ +# +# {{ ansible_managed }} +# + +# Search the specified access(5) database for the resolved RCPT TO address, +# domain, parent domains, or localpart@, and execute the corresponding action. +# http://www.postfix.org/postconf.5.html#check_recipient_access +# http://www.postfix.org/access.5.html +{% for item in postfix_lmdb_check_recipient_access_maps_table_entries | default([]) %} +{{ item.pattern }} {{ item.action }}{% if item.reason is defined %} {{ item.reason }}{% endif %} +{% endfor %} diff --git a/templates/etc/postfix/check_sender_access_maps.j2 b/templates/etc/postfix/check_sender_access_maps.j2 new file mode 100644 index 0000000..d9d8f65 --- /dev/null +++ b/templates/etc/postfix/check_sender_access_maps.j2 @@ -0,0 +1,11 @@ +# +# {{ ansible_managed }} +# + +# Search the specified access(5) database for the MAIL FROM address, domain, +# parent domains, or localpart@, and execute the corresponding action. +# http://www.postfix.org/postconf.5.html#check_sender_access +# http://www.postfix.org/access.5.html +{% for item in postfix_lmdb_check_sender_access_maps_table_entries | default([]) %} +{{ item.pattern }} {{ item.action }}{% if item.reason is defined %} {{ item.reason }}{% endif %} +{% endfor %} diff --git a/templates/etc/postfix/main.cf.j2 b/templates/etc/postfix/main.cf.j2 new file mode 100644 index 0000000..1c00b72 --- /dev/null +++ b/templates/etc/postfix/main.cf.j2 @@ -0,0 +1,1135 @@ +# +# {{ ansible_managed }} +# + +# address_verify_map +# Lookup table for persistent address verification status storage. The table is +# maintained by the verify(8) service, and is opened before the process releases +# privileges. +# http://www.postfix.org/postconf.5.html#address_verify_map +{% if postfix_address_verify_db is defined and postfix_address_verify_db | length > 0 %} +address_verify_map = {{ postfix_address_verify_db }} +{% else %} +# address_verify_map = +{% endif %} + +# address_verify_negative_expire_time +# The time after which a failed probe expires from the address verification +# cache. +# http://www.postfix.org/postconf.5.html#address_verify_negative_expire_time +{% if postfix_address_verify_negative_expire_time is defined and postfix_address_verify_negative_expire_time | length > 0 %} +address_verify_negative_expire_time = {{ postfix_address_verify_negative_expire_time }} +{% else %} +# address_verify_negative_expire_time = +{% endif %} + +# address_verify_negative_refresh_time +# The time after which a failed address verification probe needs to be refreshed +# http://www.postfix.org/postconf.5.html#address_verify_negative_refresh_time +{% if postfix_address_verify_negative_refresh_time is defined and postfix_address_verify_negative_refresh_time | length > 0 %} +address_verify_negative_refresh_time = {{ postfix_address_verify_negative_refresh_time }} +{% else %} +# address_verify_negative_refresh_time = +{% endif %} + +# address_verify_positive_expire_time +# The time after which a successful probe expires from the address verification cache. +# http://www.postfix.org/postconf.5.html#address_verify_positive_expire_time +{% if postfix_address_verify_positive_expire_time is defined and postfix_address_verify_positive_expire_time | length > 0 %} +address_verify_positive_expire_time = {{ postfix_address_verify_positive_expire_time }} +{% else %} +# address_verify_positive_expire_time = +{% endif %} + +# address_verify_positive_refresh_time +# The time after which a successful address verification probe needs to be +# refreshed. The address verification status is not updated when the probe fails +# (optimistic caching). +{% if postfix_address_verify_positive_refresh_time is defined and postfix_address_verify_positive_refresh_time | length > 0 %} +address_verify_positive_refresh_time = {{ postfix_address_verify_positive_refresh_time }} +{% else %} +# address_verify_positive_refresh_time = +{% endif %} + +# alias_database +# The alias databases for local(8) delivery that are updated with "newaliases" +# or with "sendmail -bi". +# +# This is a separate configuration parameter because not all the tables +# specified with $alias_maps have to be local files. +# http://www.postfix.org/postconf.5.html#alias_database +{% if postfix_alias_database is defined and postfix_alias_database | length > 0 %} +alias_database = {{ postfix_alias_database }} +{% else %} +# alias_database = +{% endif %} + +# alias_maps +# The alias databases that are used for local(8) delivery. See aliases(5) for +# syntax details. Specify zero or more "type:name" lookup tables, separated by +# whitespace or comma. Tables will be searched in the specified order until a +# match is found. Note: these lookups are recursive. +{% if postfix_alias_maps is defined and postfix_alias_maps | length > 0 %} +alias_maps = {{ postfix_alias_maps }} +{% else %} +# alias_maps = +{% endif %} + +# append_at_myorigin +# With locally submitted mail, append the string "@$myorigin" to mail addresses +# without domain information. With remotely submitted mail, append the string +# "@$remote_header_rewrite_domain" instead. +# http://www.postfix.org/postconf.5.html#append_at_myorigin +append_at_myorigin = {{ "yes" if postfix_append_at_myorigin | default(true) else "no" }} + +# append_dot_mydomain +# With locally submitted mail, append the string ".$mydomain" to addresses that +# have no ".domain" information. With remotely submitted mail, append the string +# ".$remote_header_rewrite_domain" instea +# http://www.postfix.org/postconf.5.html#append_dot_mydomain +append_dot_mydomain = {{ "yes" if postfix_append_dot_mydomain | default(false) else "no" }} + +# biff +# Whether or not to use the local biff service. This service sends "new mail" +# notifications to users who have requested new mail notification with the UNIX +# command "biff y". +# +# For compatibility reasons this feature is on by default. On systems with lots +# of interactive users, the biff service can be a performance drain. Specify +# "biff = no" in main.cf to disable. +# http://www.postfix.org/postconf.5.html#biff +biff = {{ "yes" if postfix_biff | default(false) else "no" }} + +# canonical_maps +# Optional address mapping lookup tables for message headers and envelopes. The +# mapping is applied to both sender and recipient addresses, in both envelopes +# and in headers, as controlled with the canonical_classes parameter. This is +# typically used to clean up dirty addresses from legacy mail systems, or to +# replace login names by Firstname.Lastname. +# http://www.postfix.org/postconf.5.html#canonical_maps +{% if postfix_canonical_maps is defined and (postfix_canonical_maps | reject('equalto', '') | list | length) > 0 %} +canonical_maps = {{ postfix_canonical_maps | reject('equalto', '') | join(', ') }} +{% else %} +# canonical_maps = +{% endif %} + +# compatibility_level +# A safety net that causes Postfix to run with backwards-compatible default +# settings after an upgrade to a newer Postfix version. +# http://www.postfix.org/postconf.5.html#compatibility_level +compatibility_level = {{ postfix_compatibility_level | default('2') }} + +# default_database_type +# The default database type for use in newaliases(1), postalias(1) and +# postmap(1) commands. On many UNIX systems the default type is either dbm or +# hash. The default setting is frozen when the Postfix system is built. +# http://www.postfix.org/postconf.5.html#default_database_type +default_database_type = lmdb + +# delay_warning_time +# The time after which the sender receives a copy of the message headers of mail +# that is still queued. The confirm_delay_cleared parameter controls sender +# notification when the delay clears up. +# http://www.postfix.org/postconf.5.html#delay_warning_time +{% if postfix_delay_warning_time is defined and postfix_delay_warning_time | length > 0 %} +delay_warning_time = {{ postfix_delay_warning_time }} +{% else %} +# delay_warning_time = +{% endif %} + +# disable_vrfy_command +# Disable the SMTP VRFY command. This stops some techniques used to harvest +# email addresses. +# http://www.postfix.org/postconf.5.html#disable_vrfy_command +disable_vrfy_command = {{ "yes" if postfix_disable_vrfy_command | default(true) else "no" }} + +# home_mailbox +# Optional pathname of a mailbox file relative to a local(8) user's home +# directory. Specify a pathname ending in "/" for qmail-style delivery. +# http://www.postfix.org/postconf.5.html#home_mailbox +{% if postfix_home_mailbox is defined and postfix_home_mailbox | length > 0 %} +home_mailbox = {{ postfix_home_mailbox }} +{% else %} +# home_mailbox = +{% endif %} + +# inet_interfaces +# The network interface addresses that this mail system receives mail on. +# Specify "all" to receive mail on all network interfaces (default), and +# "loopback-only" to receive mail on loopback network interfaces only (Postfix +# version 2.2 and later). The parameter also controls delivery of mail to +# user@[ip.address]. +# http://www.postfix.org/postconf.5.html#inet_interfaces +{% if postfix_inet_interfaces is defined and postfix_inet_interfaces | length > 0 %} +inet_interfaces = {{ postfix_inet_interfaces }} +{% else %} +# inet_interfaces = +{% endif %} + +# inet_protocols +# The Internet protocols Postfix will attempt to use when making or accepting +# connections. Specify one or more of "ipv4" or "ipv6", separated by whitespace +# or commas. The form "all" is equivalent to "ipv4, ipv6" or "ipv4", depending +# on whether the operating system implements IPv6. +# http://www.postfix.org/postconf.5.html#inet_protocols +{% if postfix_inet_protocols is defined and postfix_inet_protocols | length > 0 %} +inet_protocols = {{ postfix_inet_protocols }} +{% else %} +# inet_protocols = +{% endif %} + +# mailbox_size_limit +# The maximal size of any local(8) individual mailbox or maildir file, or zero +# (no limit). In fact, this limits the size of any file that is written to upon +# local delivery, including files written by external commands that are executed +# by the local(8) delivery agent. +# +# This limit must not be smaller than the message size limit. +# http://www.postfix.org/postconf.5.html#mailbox_size_limit +{% if postfix_mailbox_size_limit is defined and postfix_mailbox_size_limit != -1 %} +mailbox_size_limit = {{ postfix_mailbox_size_limit }} +{% else %} +# mailbox_size_limit = +{% endif %} + +# mail_name +# The mail system name that is displayed in Received: headers, in the SMTP +# greeting banner, and in bounced mail. +# http://www.postfix.org/postconf.5.html#mail_name +{% if postfix_mail_name is defined and postfix_mail_name | length > 0 %} +mail_name = {{ postfix_mail_name }} +{% else %} +mail_name = Postfix +{% endif %} + +# mail_owner +# The UNIX system account that owns the Postfix queue and most Postfix daemon +# processes. Specify the name of an unprivileged user account that does not +# share a user or group ID with other accounts, and that owns no other files or +# processes on the system. In particular, don't specify nobody or daemon. PLEASE +# USE A DEDICATED USER ID AND GROUP ID. +# http://www.postfix.org/postconf.5.html#mail_owner +{% if postfix_mail_owner is defined and postfix_mail_owner | length > 0 %} +mail_owner = {{ postfix_mail_owner }} +{% else %} +# mail_owner = +{% endif %} + +# message_size_limit +# The maximal size in bytes of a message, including envelope information. +# http://www.postfix.org/postconf.5.html#message_size_limit +{% if postfix_message_size_limit is defined and postfix_message_size_limit != -1 %} +message_size_limit = {{ postfix_message_size_limit | default(10240000) }} +{% else %} +# message_size_limit = +{% endif %} + +# milter_default_action +# The default action when a Milter (mail filter) response is unavailable (for +# example, bad Postfix configuration or Milter failure). +# http://www.postfix.org/postconf.5.html#milter_default_action +{% if postfix_milter_default_action is defined and postfix_milter_default_action | length > 0 %} +milter_default_action = {{ postfix_milter_default_action }} +{% else %} +# milter_default_action = accept +{% endif %} + +# milter_mail_macros +# The macros that are sent to Milter (mail filter) applications after the SMTP +# MAIL FROM command. +# http://www.postfix.org/postconf.5.html#milter_mail_macros +{% if postfix_milter_mail_macros is defined and postfix_milter_mail_macros | length > 0 %} +milter_mail_macros = {{ postfix_milter_mail_macros }} +{% else %} +# milter_mail_macros = +{% endif %} + +# milter_protocol +# The mail filter protocol version and optional protocol extensions for +# communication with a Milter application; prior to Postfix 2.6 the default +# protocol is 2. Postfix sends this version number during the initial protocol +# handshake. It should match the version number that is expected by the mail +# filter application (or by its Milter library). +# http://www.postfix.org/postconf.5.html#milter_protocol +{% if postfix_milter_protocol is defined and postfix_milter_protocol | string | length > 0 %} +milter_protocol = {{ postfix_milter_protocol }} +{% else %} +# milter_protocol = +{% endif %} + +# mua_client_restrictions +# Optional restrictions that the Postfix SMTP server applies in the context of a +# mail user agent connection request. Only used and referenced in masters.cf. +{% if postfix_mua_client_restrictions is defined and postfix_mua_client_restrictions | length > 0 %} +mua_client_restrictions = +{% for restriction in postfix_mua_client_restrictions %} + {{ restriction }}{% if not loop.last %},{% endif %} +{% endfor %} +{% else %} +# mua_client_restrictions = +{% endif %} + +# mua_relay_restrictions +# Access restrictions for mail relay control that the Postfix SMTP server +# applies in the context of the RCPT TO command, before +# smtpd_recipient_restrictions. Only used and referenced in masters.cf. +# http://www.postfix.org/postconf.5.html#smtpd_relay_restrictions +{% if postfix_mua_relay_restrictions is defined and postfix_mua_relay_restrictions | length > 0 %} +mua_relay_restrictions = +{% for restriction in postfix_mua_relay_restrictions %} + {{ restriction }}{% if not loop.last %},{% endif %} +{% endfor %} +{% else %} +# mua_relay_restrictions = +{% endif %} + +# mua_sender_restrictions +# Optional restrictions that the Postfix SMTP server applies in the context of a +# mail user agent MAIL FROM command. Only used and referenced in masters.cf. +# http://www.postfix.org/postconf.5.html#smtpd_sender_restrictions +{% if postfix_mua_sender_restrictions is defined and postfix_mua_sender_restrictions | length > 0 %} +mua_sender_restrictions = +{% for restriction in postfix_mua_sender_restrictions %} + {{ restriction }}{% if not loop.last %},{% endif %} +{% endfor %} +{% else %} +# mua_sender_restrictions = +{% endif %} + +# mydestination +# The list of domains that are delivered via the $local_transport mail delivery +# transport. By default this is the Postfix local(8) delivery agent which looks +# up all recipients in /etc/passwd and /etc/aliases. The SMTP server validates +# recipient addresses with $local_recipient_maps and rejects non-existent +# recipients. +# http://www.postfix.org/postconf.5.html#mydestination +{% if postfix_mydestination is defined and (postfix_mydestination | reject('equalto', '') | list | length) > 0 %} +mydestination = {{ postfix_mydestination | join(', ') }} +{% else %} +# mydestination = +{% endif %} + +# mydomain +# The internet domain name of this mail system. The default is to use +# $myhostname minus the first component, or "localdomain" (Postfix 2.3 and +# later). $mydomain is used as a default value for many other configuration +# parameters. +# http://www.postfix.org/postconf.5.html#mydomain +{% if postfix_mydomain is defined and postfix_mydomain | length > 0 %} +mydomain = {{ postfix_mydomain }} +{% else %} +# mydomain = +{% endif %} + +# myhostname +# The internet hostname of this mail system. The default is to use the +# fully-qualified domain name (FQDN) from gethostname(), or to use the non-FQDN +# result from gethostname() and append ".$mydomain". $myhostname is used as a +# default value for many other configuration parameters. +# http://www.postfix.org/postconf.5.html#myhostname +{% if postfix_myhostname is defined and postfix_myhostname | length > 0 %} +myhostname = {{ postfix_myhostname }} +{% else %} +# myhostname = +{% endif %} + +# mynetworks +# The list of "trusted" remote SMTP clients that have more privileges than +# "strangers". +# +# In particular, "trusted" SMTP clients are allowed to relay mail through +# Postfix. See the smtpd_relay_restrictions parameter description in the +# postconf(5) manual. +# +# You can specify the list of "trusted" network addresses by hand or you can let +# Postfix do it for you (which is the default). See the description of the +# mynetworks_style parameter for more information. If you specify the mynetworks +# list by hand, Postfix ignores the mynetworks_style setting. +# http://www.postfix.org/postconf.5.html#mynetworks +{% if postfix_mynetworks is defined and (postfix_mynetworks | reject('equalto', '') | list | length) > 0 %} +mynetworks = {{ postfix_mynetworks | join(', ') }} +{% else %} +# mynetworks = +{% endif %} + +# mynetworks_style +# The method to generate the default value for the mynetworks parameter. This is +# the list of trusted networks for relay access control etc. +# - Specify "mynetworks_style = host" when Postfix should "trust" only the local +# machine. +# - Specify "mynetworks_style = subnet" when Postfix should "trust" remote SMTP +# clients in the same IP subnetworks as the local machine. On Linux, this +# works correctly only with interfaces specified with the "ifconfig" command. +# - Specify "mynetworks_style = class" when Postfix should "trust" remote SMTP +# clients in the same IP class A/B/C networks as the local machine. Caution: +# this may cause Postfix to "trust" your entire provider's network. Instead, +# specify an explicit mynetworks list by hand, as described with the +# mynetworks configuration parameter. +# http://www.postfix.org/postconf.5.html#mynetworks_style +{% if postfix_mynetworks_style is defined and postfix_mynetworks_style | length > 0 %} +mynetworks_style = {{ postfix_mynetworks_style }} +{% else %} +# mynetworks_style = +{% endif %} + +# myorigin +# The domain name that locally-posted mail appears to come from, and that +# locally posted mail is delivered to. The default, $myhostname, is adequate for +# small sites. If you run a domain with multiple machines, you should (1) change +# this to $mydomain and (2) set up a domain-wide alias database that aliases +# each user to user@that.users.mailhost. +# http://www.postfix.org/postconf.5.html#myorigin +{% if postfix_myorigin is defined and postfix_myorigin | length > 0 %} +myorigin = {{ postfix_myorigin }} +{% else %} +# myorigin = +{% endif %} + +# non_smtpd_milters +# A list of Milter (mail filter) applications for new mail that does not arrive +# via the Postfix smtpd(8) server. This includes local submission via the +# sendmail(1) command line, new mail that arrives via the Postfix qmqpd(8) +# server, and old mail that is re-injected into the queue with "postsuper -r". +# Specify space or comma as a separator. +{% if postfix_non_smtpd_milters is defined and (postfix_non_smtpd_milters | reject('equalto', '') | list | length) > 0 %} +non_smtpd_milters = {{ postfix_non_smtpd_milters | reject('equalto', '') | join(', ') }} +{% else %} +# non_smtpd_milters = +{% endif %} + +# Proxy-proxy_interfaces +# The network interface addresses that this mail system receives mail on by way +# of a proxy or network address translation unit. +# http://www.postfix.org/postconf.5.html#proxy_interfaces +{% if postfix_proxy_interfaces is defined and postfix_proxy_interfaces | length > 0 %} +proxy_interfaces = {{ postfix_proxy_interfaces }} +{% else %} +# proxy_interfaces = +{% endif %} + +# recipient_canonical_map +# Optional address mapping lookup tables for envelope and header recipient +# addresses. +# http://www.postfix.org/postconf.5.html#recipient_canonical_maps +{% if postfix_recipient_canonical_maps is defined and (postfix_recipient_canonical_maps | reject('equalto', '') | list | length) > 0 %} +recipient_canonical_maps = {{ postfix_recipient_canonical_maps | reject('equalto', '') | join(', ') }} +{% else %} +# recipient_canonical_maps = +{% endif %} + +# recipient_delimiter +# The set of characters that can separate an email address localpart, user name, +# or a .forward file name from its extension. For example, with +# "recipient_delimiter = +", the software tries user+foo@example.com before +# trying user@example.com, user+foo before trying user, and .forward+foo before +# trying .forward. +# +# More formally, an email address localpart or user name is separated from its +# extension by the first character that matches the recipient_delimiter set. The +# delimiter character and extension may then be used to generate an extended +# .forward file name. This implementation recognizes one delimiter character and +# one extension per email address localpart or email address. +# http://www.postfix.org/postconf.5.html#recipient_delimiter +{% if postfix_recipient_delimiter is defined and postfix_recipient_delimiter | length > 0 %} +recipient_delimiter = {{ postfix_recipient_delimiter }} +{% else %} +# recipient_delimiter = +{% endif %} + +# relay_domains +# What destination domains (and subdomains thereof) this system will relay mail +# to. For details about how the relay_domains value is used, see the description +# of the permit_auth_destination and reject_unauth_destination SMTP recipient +# restrictions. +# +# Domains that match $relay_domains are delivered with the $relay_transport mail +# delivery transport. The SMTP server validates recipient addresses with +# $relay_recipient_maps and rejects non-existent recipients. +# http://www.postfix.org/postconf.5.html#relay_domains +{% if postfix_relay_domains is defined and (postfix_relay_domains | reject('equalto', '') | list | length) > 0 %} +relay_domains = {{ postfix_relay_domains | reject('equalto', '') | join(', ') }} +{% else %} +# relay_domains = +{% endif %} + +# relay_recipient_maps +# Optional lookup tables with all valid addresses in the domains that match +# $relay_domains. Specify @domain as a wild-card for domains that have no valid +# recipient list, and become a source of backscatter mail: Postfix accepts spam +# for non-existent recipients and then floods innocent people with undeliverable +# mail. Technically, tables listed with $relay_recipient_maps are used as lists: +# Postfix needs to know only if a lookup string is found or not, but it does not +# use the result from table lookup. +# http://www.postfix.org/postconf.5.html#relay_recipient_maps +{% if postfix_relay_recipient_maps is defined and (postfix_relay_recipient_maps | reject('equalto', '') | list | length) > 0 %} +relay_recipient_maps = {{ postfix_relay_recipient_maps | reject('equalto', '') | join(', ') }} +{% else %} +# relay_recipient_maps = +{% endif %} + +# relayhost +# The next-hop destination(s) for non-local mail; overrides the non-local +# domain routing found in the transport(5) table. Specify a host or host:port, +# or enclose in [] to disable MX lookups. +# http://www.postfix.org/postconf.5.html#relayhost +{% if postfix_relayhost is defined and postfix_relayhost %} +relayhost = {{ postfix_relayhost }} +{% else %} +# relayhost = +{% endif %} + +# relocated_maps +# Optional lookup tables with new contact information for users or domains that +# no longer exist. The table format and lookups are documented in relocated(5). +# http://www.postfix.org/postconf.5.html#relocated_maps +{% if postfix_relocated_maps is defined and (postfix_relocated_maps | reject('equalto', '') | list | length) > 0 %} +relocated_maps = {{ postfix_relocated_maps | reject('equalto', '') | join(', ') }} +{% else %} +# relocated_maps = +{% endif %} + +# sender_canonical_maps +# Optional address mapping lookup tables for envelope and header sender +# addresses. The table format and lookups are documented in canonical(5). +# +# Example: you want to rewrite the SENDER address "user@ugly.domain" to +# "user@pretty.domain", while still being able to send mail to the RECIPIENT +# address "user@ugly.domain". +# http://www.postfix.org/postconf.5.html#sender_canonical_maps +{% if postfix_sender_canonical_maps is defined and (postfix_sender_canonical_maps | reject('equalto', '') | list | length) > 0 %} +sender_canonical_maps = {{ postfix_sender_canonical_maps | reject('equalto', '') | join(', ') }} +{% else %} +# sender_canonical_maps = +{% endif %} + +# smtpd_forbid_bare_newline +# Disconnect remote SMTP clients that send bare newlines, violating the RFC 5321 +# requirement that lines must end in . +# Postfix 3.9+: valid values are "normalize", "reject", "no" ("yes" is deprecated). +# http://www.postfix.org/postconf.5.html#smtpd_forbid_bare_newline +{% if postfix_smtpd_forbid_bare_newline is defined and postfix_smtpd_forbid_bare_newline | string | length > 0 %} +smtpd_forbid_bare_newline = {{ postfix_smtpd_forbid_bare_newline }} +{% else %} +# smtpd_forbid_bare_newline = +{% endif %} + +# smtpd_forbid_bare_newline_exclusions +# Exclude the specified clients from smtpd_forbid_bare_newline enforcement. It +# uses the same syntax and parent-domain matching behavior as mynetworks. +# http://www.postfix.org/postconf.5.html#smtpd_forbid_bare_newline_exclusions +{% if postfix_smtpd_forbid_bare_newline_exclusions is defined and postfix_smtpd_forbid_bare_newline_exclusions | length > 0 %} +smtpd_forbid_bare_newline_exclusions = {{ postfix_smtpd_forbid_bare_newline_exclusions }} +{% else %} +# smtpd_forbid_bare_newline_exclusions = +{% endif %} + +# smtp_sasl_auth_enable +# Enable SASL authentication in the Postfix SMTP client. By default, the Postfix +# SMTP client uses no authentication. +# http://www.postfix.org/postconf.5.html#smtp_sasl_auth_enable +{% if postfix_smtp_sasl_auth_enable | default(false) %} +smtp_sasl_auth_enable = yes +{% else %} +# smtp_sasl_auth_enable = yes +{% endif %} + +# smtp_sasl_password_maps +# Optional Postfix SMTP client lookup tables with one username:password entry per +# sender, remote hostname or next-hop domain. +# http://www.postfix.org/postconf.5.html#smtp_sasl_password_maps +{% if postfix_smtp_sasl_password_maps is defined and (postfix_smtp_sasl_password_maps | reject('equalto', '') | list | length) > 0 %} +smtp_sasl_password_maps = {{ postfix_smtp_sasl_password_maps | reject('equalto', '') | join(', ') }} +{% else %} +# smtp_sasl_password_maps = +{% endif %} + +# smtp_sasl_security_options +# Postfix SMTP client SASL security options. +# http://www.postfix.org/postconf.5.html#smtp_sasl_security_options +{% if postfix_smtp_sasl_auth_enable | default(false) %} +smtp_sasl_security_options = noanonymous +{% else %} +# smtp_sasl_security_options = noanonymous +{% endif %} + +# smtp_tls_CApath +# Directory with PEM format Certification Authority certificates that the +# Postfix SMTP client uses to verify a remote SMTP server certificate. +# http://www.postfix.org/postconf.5.html#smtp_tls_CApath +{% if postfix_smtp_tls_capath is defined and postfix_smtp_tls_capath | length > 0 %} +smtp_tls_CApath = {{ postfix_smtp_tls_capath }} +{% else %} +# smtp_tls_CApath = +{% endif %} + +# smtp_tls_cert_file +# File with the Postfix SMTP client RSA certificate in PEM format. This file may +# also contain the Postfix SMTP client private RSA key, and these may be the +# same as the Postfix SMTP server RSA certificate and key file. +{% if postfix_smtp_tls_cert_file is defined and postfix_smtp_tls_cert_file | length > 0 %} +smtp_tls_cert_file = {{ postfix_smtp_tls_cert_file }} +{% else %} +# smtp_tls_cert_file = +{% endif %} +{% if postfix_smtp_tls_key_file is defined and postfix_smtp_tls_key_file | length > 0 %} +smtp_tls_key_file = {{ postfix_smtp_tls_key_file }} +{% else %} +# smtp_tls_key_file = +{% endif %} + +# smtp_tls_loglevel Enable additional Postfix SMTP client logging of TLS +# activity. Each logging level also includes the information that is logged at a +# lower logging level. +# - 0: Disable logging of TLS activity. +# - 1: Log only a summary message on TLS handshake completion — no logging of +# remote SMTP server certificate trust-chain verification errors if server +# certificate verification is not required. With Postfix 2.8 and earlier, log +# the summary message and unconditionally log trust-chain verification errors. +# - 2: Also log levels during TLS negotiation. +# - 3: Also log hexadecimal and ASCII dump of TLS negotiation process. +# - 4: Also log hexadecimal and ASCII dump of complete transmission after +# STARTTLS. +# http://www.postfix.org/postconf.5.html#smtp_tls_loglevel +{% if postfix_smtp_tls_loglevel is defined and postfix_smtp_tls_loglevel != -1 %} +smtp_tls_loglevel = {{ postfix_smtp_tls_loglevel }} +{% else %} +# smtp_tls_loglevel = +{% endif %} + +# smtp_tls_mandatory_ciphers +# The minimum TLS cipher grade that the Postfix SMTP client will use with +# mandatory TLS encryption. The default value "medium" is suitable for most +# destinations with which you may want to enforce TLS, and is beyond the reach +# of today's cryptanalytic methods. +# http://www.postfix.org/postconf.5.html#smtp_tls_mandatory_ciphers +{% if postfix_smtp_tls_mandatory_ciphers is defined and postfix_smtp_tls_mandatory_ciphers | length > 0 %} +smtp_tls_mandatory_ciphers = {{ postfix_smtp_tls_mandatory_ciphers }} +{% else %} +# smtp_tls_mandatory_ciphers = +{% endif %} + +# smtp_tls_mandatory_protocols +# TLS protocols that the Postfix SMTP client will use with mandatory TLS +# encryption. +# http://www.postfix.org/postconf.5.html#smtp_tls_mandatory_protocols +{% if postfix_smtp_tls_mandatory_protocols is defined and postfix_smtp_tls_mandatory_protocols | length > 0 %} +smtp_tls_mandatory_protocols = {{ postfix_smtp_tls_mandatory_protocols }} +{% else %} +# smtp_tls_mandatory_protocols = +{% endif %} + +# smtp_tls_policy_maps +# Optional lookup tables with the Postfix SMTP client TLS security policy by +# next-hop destination. +# http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps +{% if postfix_tls_policy_maps is defined and (postfix_tls_policy_maps | reject('equalto', '') | list | length) > 0 %} +smtp_tls_policy_maps = {{ postfix_tls_policy_maps | reject('equalto', '') | join(', ') }} +{% else %} +# smtp_tls_policy_maps = +{% endif %} + +# smtp_tls_protocols +# TLS protocols that the Postfix SMTP client will use with opportunistic TLS +# encryption. +{% if postfix_smtp_tls_protocols is defined and postfix_smtp_tls_protocols | length > 0 %} +smtp_tls_protocols = {{ postfix_smtp_tls_protocols }} +{% else %} +# smtp_tls_protocols = +{% endif %} + +# smtp_tls_security_level +# The default SMTP TLS security level for the Postfix SMTP client; when a +# non-empty value is specified, this overrides the obsolete parameters +# smtp_use_tls, smtp_enforce_tls, and smtp_tls_enforce_peernam. +# http://www.postfix.org/postconf.5.html#smtp_tls_security_level +{% if postfix_smtp_tls_security_level is defined and postfix_smtp_tls_security_level | length > 0 %} +smtp_tls_security_level = {{ postfix_smtp_tls_security_level }} +{% else %} +# smtp_tls_security_level = +{% endif %} + +# smtp_tls_session_cache_database +# Name of the file containing the optional Postfix SMTP client TLS session +# cache. Specify a database type that supports enumeration, such as btree or +# sdbm; there is no need to support concurrent access. +{% if postfix_smtp_tls_session_cache_database is defined and postfix_smtp_tls_session_cache_database | length > 0 %} +smtp_tls_session_cache_database = {{ postfix_smtp_tls_session_cache_database }} +{% else %} +# smtp_tls_session_cache_database = +{% endif %} + +# smtpd_banner +# The text that follows the 220 status code in the SMTP greeting banner. Some +# people like to see the mail version advertised. By default, Postfix shows no +# version. +# You MUST specify $myhostname at the start of the text. This is required by the +# SMTP protocol. +# http://www.postfix.org/postconf.5.html#smtpd_banner +{% if postfix_smtpd_banner is defined and postfix_smtpd_banner | length > 0 %} +smtpd_banner = {{ postfix_smtpd_banner }} +{% else %} +# smtpd_banner = +{% endif %} + +# smtpd_helo_required +# Require that a remote SMTP client introduces itself with the HELO or EHLO +# command before sending the MAIL command or other commands that require EHLO +# negotiation. +# http://www.postfix.org/postconf.5.html#smtpd_helo_required +smtpd_helo_required = {{ "yes" if postfix_smtpd_helo_required | default(true) else "no" }} + +# Die Restrictions - Das Herz von Postfix +# Die Restrictions durchlaufen wie angegeben folgende Reihenfolge. +# 1. smtpd_client_restrictions Prüft auf IP-Adresse oder Hostname +# 2. smtpd_helo_restrictions Prüft nach HELO oder EHLO +# 3. smtpd_sender_restrictions Prüft nach MAIL FROM: +# 4. smtpd_relay_restrictions Prüft nach RELAY +# 5. smtpd_recipient_restrictions Prüft mach RCPT TO: +# 6. smtpd_data_restrictions Prüft ab beginng von DATA +# 7. smtpd_end_of_data_restrictions Prüft nach ende von DATA +# 8. smtpd etrn_restrictions + +# smtpd_client_restrictions +# Optional restrictions that the Postfix SMTP server applies in the context of a +# client connection request. +# http://www.postfix.org/postconf.5.html#smtpd_client_restrictions +{% if postfix_smtpd_client_restrictions is defined and (postfix_smtpd_client_restrictions | reject('equalto', '') | list | length) > 0 %} +smtpd_client_restrictions = +{% for restriction in postfix_smtpd_client_restrictions | reject('equalto', '') | list %} + {{ restriction }}{% if not loop.last %},{% endif %} +{% endfor %} +{% else %} +# smtpd_client_restrictions = +{% endif %} + +# smtpd_helo_restrictions +# Optional restrictions that the Postfix SMTP server applies in the context of a client HELO command. +# http://www.postfix.org/postconf.5.html#smtpd_helo_restrictions +{% if postfix_smtpd_helo_restrictions is defined and (postfix_smtpd_helo_restrictions | reject('equalto', '') | list | length) > 0 %} +smtpd_helo_restrictions = +{% for restriction in postfix_smtpd_helo_restrictions | reject('equalto', '') | list %} + {{ restriction }}{% if not loop.last %},{% endif %} +{% endfor %} +{% else %} +# smtpd_helo_restrictions = +{% endif %} + +# smtpd_milters +# A list of Milter (mail filter) applications for new mail that arrives via the +# Postfix smtpd(8) server. Specify space or comma as separator. +# http://www.postfix.org/postconf.5.html#smtpd_milters +{% if postfix_smtpd_milters is defined and (postfix_smtpd_milters | reject('equalto', '') | list | length) > 0 %} +smtpd_milters = +{% for milters in postfix_smtpd_milters | reject('equalto', '') | list %} + {{ milters }}{% if not loop.last %},{% endif %} +{% endfor %} +{% else %} +# smtpd_milters = +{% endif %} + +# smtpd_sender_restrictions +# Optional restrictions that the Postfix SMTP server applies in the context of a +# client MAIL FROM command. +# http://www.postfix.org/postconf.5.html#smtpd_sender_restrictions +{% if postfix_smtpd_sender_restrictions is defined and (postfix_smtpd_sender_restrictions | reject('equalto', '') | list | length) > 0 %} +smtpd_sender_restrictions = +{% for restriction in postfix_smtpd_sender_restrictions | reject('equalto', '') | list %} + {{ restriction }}{% if not loop.last %},{% endif %} +{% endfor %} +{% else %} +# smtpd_sender_restrictions = +{% endif %} + +# smtpd_relay_restrictions +# Access restrictions for mail relay control that the Postfix SMTP server +# applies in the context of the RCPT TO command, before +# smtpd_recipient_restrictions. +# http://www.postfix.org/postconf.5.html#smtpd_relay_restrictions +{% if postfix_smtpd_relay_restrictions is defined and (postfix_smtpd_relay_restrictions | reject('equalto', '') | list | length) > 0 %} +smtpd_relay_restrictions = +{% for restriction in postfix_smtpd_relay_restrictions | reject('equalto', '') | list %} + {{ restriction }}{% if not loop.last %},{% endif %} +{% endfor %} +{% else %} +# smtpd_relay_restrictions = +{% endif %} + +# smtpd_recipient_restrictions +# Optional restrictions that the Postfix SMTP server applies in the context of a +# client RCPT TO command, after smtpd_relay_restrictions. +# http://www.postfix.org/postconf.5.html#smtpd_recipient_restrictions +{% if postfix_smtpd_recipient_restrictions is defined and (postfix_smtpd_recipient_restrictions | reject('equalto', '') | list | length) > 0 %} +smtpd_recipient_restrictions = +{% for table in postfix_check_client_access_maps | default([]) | reject('equalto', '') | list %} + check_client_access {{ table }}, +{% endfor %} +{% for table in postfix_check_helo_access_maps | default([]) | reject('equalto', '') | list %} + check_helo_access {{ table }}, +{% endfor %} +{% for table in postfix_check_sender_access_maps | default([]) | reject('equalto', '') | list %} + check_sender_access {{ table }}, +{% endfor %} +{% for table in postfix_check_recipient_access_maps | default([]) | reject('equalto', '') | list %} + check_recipient_access {{ table }}, +{% endfor %} +{% for restriction in postfix_smtpd_recipient_restrictions | reject('equalto', '') | list %} + {{ restriction }}{% if not loop.last %},{% endif %} + +{% endfor %} +{% else %} +# smtpd_recipient_restrictions = +{% endif %} + +# smtpd_data_restrictions +# Optional access restrictions that the Postfix SMTP server applies in the +# context of the SMTP DATA command. +# http://www.postfix.org/postconf.5.html#smtpd_data_restrictions +{% if postfix_smtpd_data_restrictions is defined and (postfix_smtpd_data_restrictions | reject('equalto', '') | list | length) > 0 %} +smtpd_data_restrictions = +{% for restriction in postfix_smtpd_data_restrictions | reject('equalto', '') | list %} + {{ restriction }}{% if not loop.last %},{% endif %} +{% endfor %} +{% else %} +# smtpd_data_restrictions = +{% endif %} + +# smtpd_end_of_data_restrictions +# Optional access restrictions that the Postfix SMTP server applies in the +# context of the SMTP END-OF-DATA command. +# http://www.postfix.org/postconf.5.html#smtpd_end_of_data_restrictions +{% if postfix_smtpd_end_of_data_restrictions is defined and (postfix_smtpd_end_of_data_restrictions | reject('equalto', '') | list | length) > 0 %} +smtpd_end_of_data_restrictions = +{% for restriction in postfix_smtpd_end_of_data_restrictions | reject('equalto', '') | list %} + {{ restriction }}{% if not loop.last %},{% endif %} +{% endfor %} +{% else %} +# smtpd_end_of_data_restrictions = +{% endif %} + +# smtpd_etrn_restrictions +# Optional restrictions that the Postfix SMTP server applies in the context of a +# client ETRN command. +# http://www.postfix.org/postconf.5.html#smtpd_etrn_restrictions +{% if postfix_smtpd_etrn_restrictions is defined and (postfix_smtpd_etrn_restrictions | reject('equalto', '') | list | length) > 0 %} +smtpd_etrn_restrictions = +{% for restriction in postfix_smtpd_etrn_restrictions | reject('equalto', '') | list %} + {{ restriction }}{% if not loop.last %},{% endif %} +{% endfor %} +{% else %} +# smtpd_etrn_restrictions = +{% endif %} + +# smtpd_sasl_authenticated_header +# Report the SASL authenticated user name in the smtpd(8) Received message +# header. +# http://www.postfix.org/postconf.5.html#smtpd_sasl_authenticated_header +smtpd_sasl_authenticated_header = {{ "yes" if postfix_smtpd_sasl_authenticated_header | default(true) else "no" }} + +# smtpd_sasl_auth_enable +# Enable SASL authentication in the Postfix SMTP server. By default, the Postfix +# SMTP server does not use authentication. +# +# If a remote SMTP client is authenticated, the permit_sasl_authenticated access +# restriction can be used to permit relay access +smtpd_sasl_auth_enable = {{ "yes" if postfix_smtpd_sasl_auth_enable | default(true) else "no" }} + +# smtpd_sasl_path +# Implementation-specific information that the Postfix SMTP server passes +# through to the SASL plug-in implementation that is selected with +# smtpd_sasl_type. Typically this specifies the name of a configuration file or +# rendezvous point. +# http://www.postfix.org/postconf.5.html#smtpd_sasl_path +# smtpd_sasl_path = /var/run/dovecot/auth-client +# smtpd_sasl_path = inet:localhost:5200 + +# private/dovecot-auth is relative to /var/spool/postfix/private/dovecot-auth, created by dovevot +{% if postfix_smtpd_sasl_path is defined and postfix_smtpd_sasl_path | length > 0 %} +smtpd_sasl_path = {{ postfix_smtpd_sasl_path }} +{% else %} +# smtpd_sasl_path = +{% endif %} + +# smtpd_sasl_security_options +# Postfix SMTP server SASL security options; as of Postfix 2.3 the list of +# available features depends on the SASL server implementation that is selected +# with smtpd_sasl_type. +# +# Restrict what authentication mechanisms the Postfix SMTP server will offer to +# the client. The list of available authentication mechanisms is system +# dependent. +# http://www.postfix.org/postconf.5.html#smtpd_sasl_security_options +{% if postfix_smtpd_sasl_security_options is defined and (postfix_smtpd_sasl_security_options | reject('equalto', '') | list | length) > 0 %} +smtpd_sasl_security_options = {{ postfix_smtpd_sasl_security_options | reject('equalto', '') | join(', ') }} +{% else %} +# smtpd_sasl_security_options = +{% endif %} + +# smtpd_sasl_tls_security_options +# The SASL authentication security options that the Postfix SMTP server uses for +# TLS encrypted SMTP sessions. Default $smtpd_sasl_security_options +# http://www.postfix.org/postconf.5.html#smtpd_sasl_tls_security_options +{% if postfix_smtpd_sasl_tls_security_options is defined and (postfix_smtpd_sasl_tls_security_options | reject('equalto', '') | list | length) > 0 %} +smtpd_sasl_tls_security_options = {{ postfix_smtpd_sasl_tls_security_options | reject('equalto', '') | join(', ') }} +{% else %} +# smtpd_sasl_tls_security_options = +{% endif %} + +# smtpd_sasl_type +# The SASL plug-in type that the Postfix SMTP server should use for +# authentication. +# http://www.postfix.org/postconf.5.html#smtpd_sasl_type +{% if postfix_smtpd_sasl_type is defined and postfix_smtpd_sasl_type | length > 0 %} +smtpd_sasl_type = {{ postfix_smtpd_sasl_type }} +{% else %} +# smtpd_sasl_type = +{% endif %} + +# smtpd_sender_login_maps +# Optional lookup table with the SASL login names that own the sender (MAIL +# FROM) addresses. +# +# With lookups from indexed files such as DB or DBM, or from networked tables +# such as NIS, LDAP or SQL, the following search operations are done with a +# sender address of user@domain: +# - user@domain: This table lookup is always done and has the highest +# precedence. +# - user: This table lookup is done only when the domain part of the sender +# address matches $myorigin, $mydestination, $inet_interfaces or +# $proxy_interfaces. +# - @domain: This table lookup is done last and has the lowest precedence. +# http://www.postfix.org/postconf.5.html#smtpd_sender_login_maps +{% if postfix_smtpd_sender_login_maps is defined and (postfix_smtpd_sender_login_maps | reject('equalto', '') | list | length) > 0 %} +smtpd_sender_login_maps = {{ postfix_smtpd_sender_login_maps | reject('equalto', '') | join(', ') }} +{% else %} +# smtpd_sender_login_maps = +{% endif %} + +# smtpd_tls_auth_only +# When TLS encryption is optional in the Postfix SMTP server, do not announce or +# accept SASL authentication over unencrypted connections. +# http://www.postfix.org/postconf.5.html#smtpd_tls_auth_only +smtpd_tls_auth_only = {{ "yes" if postfix_smtpd_tls_auth_only | default(true) else "no" }} + +# smtpd_tls_CApath +# A directory containing (PEM format) CA certificates of root CAs trusted to +# sign either remote SMTP client certificates or intermediate CA certificates. +# http://www.postfix.org/postconf.5.html#smtpd_tls_CApath +{% if postfix_smtpd_tls_capath is defined and postfix_smtpd_tls_capath | length > 0 %} +smtpd_tls_CApath = {{ postfix_smtpd_tls_capath }} +{% else %} +# smtpd_tls_CApath = +{% endif %} + +# smtpd_tls_cert_file +# File with the Postfix SMTP server RSA certificate in PEM format. This file may +# also contain the Postfix SMTP server private RSA key. +# http://www.postfix.org/postconf.5.html#smtpd_tls_cert_file +{% if postfix_smtpd_tls_cert_file is defined and postfix_smtpd_tls_cert_file | length > 0 %} +smtpd_tls_cert_file = {{ postfix_smtpd_tls_cert_file }} +{% else %} +# smtpd_tls_cert_file = +{% endif %} +{% if postfix_smtpd_tls_key_file is defined and postfix_smtpd_tls_key_file | length > 0 %} +smtpd_tls_key_file = {{ postfix_smtpd_tls_key_file }} +{% else %} +# smtpd_tls_key_file = +{% endif %} + +# smtpd_tls_loglevel +# Enable additional Postfix SMTP server logging of TLS activity. Each logging +# level also includes the information that is logged at a lower logging level. +# - 0: Disable logging of TLS activity. +# - 1: Log only a summary message on TLS handshake completion — no logging of +# client certificate trust-chain verification errors if client certificate +# verification is not required. With Postfix 2.8 and earlier, log the summary +# message, peer certificate summary information and unconditionally log +# trust-chain verification errors. +# - 2: Also log levels during TLS negotiation. +# - 3: Also log hexadecimal and ASCII dump of TLS negotiation process. +# - 4: Also log hexadecimal and ASCII dump of complete transmission after +# STARTTLS. +# http://www.postfix.org/postconf.5.html#smtpd_tls_loglevel +{% if postfix_smtpd_tls_loglevel is defined and postfix_smtpd_tls_loglevel != -1 %} +smtpd_tls_loglevel = {{ postfix_smtpd_tls_loglevel }} +{% else %} +# smtpd_tls_loglevel = +{% endif %} + +# smtpd_tls_mandatory_ciphers +# The minimum TLS cipher grade that the Postfix SMTP server will use with +# mandatory TLS encryption. The default grade ("medium") is sufficiently strong +# that any benefit from globally restricting TLS sessions to a more stringent +# grade is likely negligible, especially given the fact that many +# implementations still do not offer any stronger ("high" grade) ciphers, while +# those that do, will always use "high" grade ciphers. So insisting on "high" +# grade ciphers is generally counter-productive. Allowing "export" or "low" +# ciphers is typically not a good idea, as systems limited to just these are +# limited to obsolete browsers. No known SMTP clients fail to support at least +# one "medium" or "high" grade cipher. +# http://www.postfix.org/postconf.5.html#smtpd_tls_mandatory_ciphers +{% if postfix_smtpd_tls_mandatory_ciphers is defined and postfix_smtpd_tls_mandatory_ciphers | length > 0 %} +smtpd_tls_mandatory_ciphers = {{ postfix_smtpd_tls_mandatory_ciphers }} +{% else %} +# smtpd_tls_mandatory_ciphers = +{% endif %} + +# smtpd_tls_mandatory_protocols +# TLS protocols accepted by the Postfix SMTP server with mandatory TLS +# encryption. If the list is empty, the server supports all available TLS +# protocol versions. A non-empty value is a list of protocol names to include or +# exclude, separated by whitespace, commas or colons. +# http://www.postfix.org/postconf.5.html#smtpd_tls_mandatory_protocols +{% if postfix_smtpd_tls_mandatory_protocols is defined and postfix_smtpd_tls_mandatory_protocols | length > 0 %} +smtpd_tls_mandatory_protocols = {{ postfix_smtpd_tls_mandatory_protocols }} +{% else %} +# smtpd_tls_mandatory_protocols = +{% endif %} + +# TLS protocols accepted by the Postfix SMTP server with opportunistic TLS +# encryption. If the list is empty, the server supports all available TLS +# protocol versions. A non-empty value is a list of protocol names to include or +# exclude, separated by whitespace, commas or colons. +# http://www.postfix.org/postconf.5.html#smtpd_tls_protocols +{% if postfix_smtpd_tls_protocols is defined and postfix_smtpd_tls_protocols | length > 0 %} +smtpd_tls_protocols = {{ postfix_smtpd_tls_protocols }} +{% else %} +# smtpd_tls_protocols = +{% endif %} + +# smtpd_tls_security_level +# The SMTP TLS security level for the Postfix SMTP server; when a non-empty +# value is specified, this overrides the obsolete parameters smtpd_use_tls and +# smtpd_enforce_tls. This parameter is ignored with "smtpd_tls_wrappermode = +# yes". +# http://www.postfix.org/postconf.5.html#smtpd_tls_security_level +{% if postfix_smtpd_tls_security_level is defined and postfix_smtpd_tls_security_level | length > 0 %} +smtpd_tls_security_level = {{ postfix_smtpd_tls_security_level }} +{% else %} +# smtpd_tls_security_level = +{% endif %} + +# smtpd_tls_session_cache_database +# Name of the file containing the optional Postfix SMTP server TLS session +# cache. Specify a database type that supports enumeration, such as btree or +# sdbm; there is no need to support concurrent access. The file is created if it +# does not exist. +# http://www.postfix.org/postconf.5.html#smtpd_tls_session_cache_database +{% if postfix_smtpd_tls_session_cache_database is defined and postfix_smtpd_tls_session_cache_database | length > 0 %} +smtpd_tls_session_cache_database = {{ postfix_smtpd_tls_session_cache_database }} +{% else %} +# smtpd_tls_session_cache_database = +{% endif %} + +# strict_rfc821_envelopes +# Require that addresses received in SMTP MAIL FROM and RCPT TO commands are +# enclosed with <>, and that those addresses do not contain RFC 822 style +# comments or phrases. This stops mail from poorly written software. +# http://www.postfix.org/postconf.5.html#strict_rfc821_envelopes +strict_rfc821_envelopes = {{ "yes" if postfix_strict_rfc821_envelopes | default(true) else "no" }} + +# tls_preempt_cipherlist +# With SSLv3 and later, use the Postfix SMTP server's cipher preference order +# instead of the remote client's cipher preference order. +# +# By default, the OpenSSL server selects the client's most preferred cipher that +# the server supports. With SSLv3 and later, the server may choose its own most +# preferred cipher that is supported (offered) by the client. Setting +# "tls_preempt_cipherlist = yes" enables server cipher preferences. +# http://www.postfix.org/postconf.5.html#tls_preempt_cipherlist +tls_preempt_cipherlist = {{ "yes" if postfix_tls_preempt_cipherlist | default(true) else "no" }} + +# tls_ssl_options +# List or bit-mask of OpenSSL options to enable. +# - NO_COMPRESSION: +# Disable SSL compression even if supported by the OpenSSL +# library. Compression is CPU-intensive, and compression before encryption +# does not always improve security. +# http://www.postfix.org/postconf.5.html#tls_ssl_options +{% if postfix_tls_ssl_options is defined and postfix_tls_ssl_options | length > 0 %} +tls_ssl_options = {{ postfix_tls_ssl_options }} +{% else %} +# tls_ssl_options = +{% endif %} + +# transport_maps +# Optional lookup tables with mappings from mail address or domain to message +# delivery transport and next-hop destination. +# http://www.postfix.org/postconf.5.html#transport_maps +{% if postfix_transport_maps is defined and (postfix_transport_maps | reject('equalto', '') | list | length) > 0 %} +transport_maps = {{ postfix_transport_maps | reject('equalto', '') | join(', ') }} +{% else %} +# transport_maps = +{% endif %} + +# virtual_alias_domains +# Postfix is final destination for the specified list of virtual alias domains, +# that is, domains for which all addresses are aliased to addresses in other +# local or remote domains. The SMTP server validates recipient addresses with +# $virtual_alias_maps and rejects non-existent recipients. +# http://www.postfix.org/postconf.5.html#virtual_alias_domains +{% if postfix_virtual_alias_domains is defined and postfix_virtual_alias_domains | length > 0 %} +virtual_alias_domains = {{ postfix_virtual_alias_domains }} +{% else %} +# virtual_alias_domains = +{% endif %} + +# virtual_alias_maps +# Optional lookup tables that alias specific mail addresses or domains to other +# local or remote address. The table format and lookups are documented in +# virtual(5). +# http://www.postfix.org/postconf.5.html#virtual_alias_maps +{% if postfix_virtual_alias_maps is defined and (postfix_virtual_alias_maps | reject('equalto', '') | list | length) > 0 %} +virtual_alias_maps = {{ postfix_virtual_alias_maps | reject('equalto', '') | join(', ') }} +{% else %} +# virtual_alias_maps = +{% endif %} + +# virtual_mailbox_domains +# Postfix is final destination for the specified list of domains; mail is +# delivered via the $virtual_transport mail delivery transport. By default this +# is the Postfix virtual(8) delivery agent. The SMTP server validates recipient +# addresses with $virtual_mailbox_maps and rejects mail for non-existent +# recipients. +# http://www.postfix.org/postconf.5.html#virtual_mailbox_domains +{% if postfix_virtual_mailbox_domains is defined and (postfix_virtual_mailbox_domains | reject('equalto', '') | list | length) > 0 %} +virtual_mailbox_domains = {{ postfix_virtual_mailbox_domains | reject('equalto', '') | join(', ') }} +{% else %} +# virtual_mailbox_domains = +{% endif %} + +# virtual_mailbox_limit +# The maximal size in bytes of an individual virtual(8) mailbox or maildir file, or zero (no limit). +# http://www.postfix.org/postconf.5.html#virtual_mailbox_limit +{% if postfix_virtual_mailbox_limit is defined and postfix_virtual_mailbox_limit != -1 %} +virtual_mailbox_limit = {{ postfix_virtual_mailbox_limit }} +{% else %} +# virtual_mailbox_limit = +{% endif %} + +# virtual_mailbox_maps +# Optional lookup tables with all valid addresses in the domains that match +# $virtual_mailbox_domains. +# +# In a lookup table, specify a left-hand side of "@domain.tld" to match any user +# in the specified domain that does not have a specific "user@domain.tld" entry. +# +# When a recipient address has an optional address extension +# (user+foo@domain.tld), the virtual(8) delivery agent looks up the full address +# first, and when the lookup fails, it looks up the unextended address. +# http://www.postfix.org/postconf.5.html#virtual_mailbox_maps +{% if postfix_virtual_mailbox_maps is defined and (postfix_virtual_mailbox_maps | reject('equalto', '') | list | length) > 0 %} +virtual_mailbox_maps = {{ postfix_virtual_mailbox_maps | reject('equalto', '') | join(', ') }} +{% else %} +# virtual_mailbox_maps = +{% endif %} + +# virtual_transport +# The default mail delivery transport and next-hop destination for final +# delivery to domains listed with $virtual_mailbox_domains. This information can +# be overruled with the transport(5) table. +# http://www.postfix.org/postconf.5.html#virtual_transport +{% if postfix_virtual_transport is defined and postfix_virtual_transport | length > 0 %} +virtual_transport = {{ postfix_virtual_transport }} +{% else %} +# virtual_transport = +{% endif %} diff --git a/templates/etc/postfix/master.cf.j2 b/templates/etc/postfix/master.cf.j2 new file mode 100644 index 0000000..a824036 --- /dev/null +++ b/templates/etc/postfix/master.cf.j2 @@ -0,0 +1,25 @@ +# +# {{ ansible_managed }} +# + +# Postfix master process configuration file. For details on the format +# of the file, see the master(5) manual page (command: "man 5 master" or +# on-line: http://www.postfix.org/master.5.html). +# +# Do not forget to execute "postfix reload" after editing this file. +# +# ========================================================================== +# service type private unpriv chroot wakeup maxproc command + args +# (yes) (yes) (no) (never) (100) +# ========================================================================== +{% for service in postfix_services %} +{% set priv = ('y' if service.private else 'n') if service.private is defined else '-' %} +{% set unpriv = ('y' if service.unprivileged else 'n') if service.unprivileged is defined else '-' %} +{% set chrt = ('y' if service.chroot else 'n') if service.chroot is defined else '-' %} +{% set wkup = service.wakeup | default('-') | string %} +{% set mproc = service.maxproc | default('-') | string %} +{{ "%-9s %-5s %-7s %-7s %-7s %-7s %-7s %s" | format(service.name, service.type, priv, unpriv, chrt, wkup, mproc, service.command) }} +{% for arg in service.args | default([]) %} + {{ arg }} +{% endfor %} +{% endfor %} diff --git a/templates/etc/postfix/pgsql_relay_domain_maps.cf.j2 b/templates/etc/postfix/pgsql_relay_domain_maps.cf.j2 new file mode 100644 index 0000000..d93c12b --- /dev/null +++ b/templates/etc/postfix/pgsql_relay_domain_maps.cf.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +hosts = {{ postfix_pgsql_host }}:{{ postfix_pgsql_port }} +user = {{ postfix_pgsql_username }} +password = {{ postfix_pgsql_password }} +dbname = {{ postfix_pgsql_name }} +query = {{ postfix_pgsql_relay_domains_query }} diff --git a/templates/etc/postfix/pgsql_relay_recipient_maps.cf.j2 b/templates/etc/postfix/pgsql_relay_recipient_maps.cf.j2 new file mode 100644 index 0000000..9ba99a7 --- /dev/null +++ b/templates/etc/postfix/pgsql_relay_recipient_maps.cf.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +hosts = {{ postfix_pgsql_host }}:{{ postfix_pgsql_port }} +user = {{ postfix_pgsql_username }} +password = {{ postfix_pgsql_password }} +dbname = {{ postfix_pgsql_name }} +query = {{ postfix_pgsql_relay_recipient_maps_query }} diff --git a/templates/etc/postfix/pgsql_sender_login_maps.cf.j2 b/templates/etc/postfix/pgsql_sender_login_maps.cf.j2 new file mode 100644 index 0000000..c2c6bf6 --- /dev/null +++ b/templates/etc/postfix/pgsql_sender_login_maps.cf.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +hosts = {{ postfix_pgsql_host }}:{{ postfix_pgsql_port }} +user = {{ postfix_pgsql_username }} +password = {{ postfix_pgsql_password }} +dbname = {{ postfix_pgsql_name }} +query = {{ postfix_pgsql_smtpd_sender_login_maps_query }} diff --git a/templates/etc/postfix/pgsql_virtual_alias_domain_catchall_maps.cf.j2 b/templates/etc/postfix/pgsql_virtual_alias_domain_catchall_maps.cf.j2 new file mode 100644 index 0000000..da92b86 --- /dev/null +++ b/templates/etc/postfix/pgsql_virtual_alias_domain_catchall_maps.cf.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +hosts = {{ postfix_pgsql_host }}:{{ postfix_pgsql_port }} +user = {{ postfix_pgsql_username }} +password = {{ postfix_pgsql_password }} +dbname = {{ postfix_pgsql_name }} +query = {{ postfix_pgsql_virtual_alias_domain_catchall_maps_query }} diff --git a/templates/etc/postfix/pgsql_virtual_alias_domain_mailbox_maps.cf.j2 b/templates/etc/postfix/pgsql_virtual_alias_domain_mailbox_maps.cf.j2 new file mode 100644 index 0000000..f8b30d3 --- /dev/null +++ b/templates/etc/postfix/pgsql_virtual_alias_domain_mailbox_maps.cf.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +hosts = {{ postfix_pgsql_host }}:{{ postfix_pgsql_port }} +user = {{ postfix_pgsql_username }} +password = {{ postfix_pgsql_password }} +dbname = {{ postfix_pgsql_name }} +query = {{ postfix_pgsql_virtual_alias_domain_mailbox_maps_query }} diff --git a/templates/etc/postfix/pgsql_virtual_alias_domain_maps.cf.j2 b/templates/etc/postfix/pgsql_virtual_alias_domain_maps.cf.j2 new file mode 100644 index 0000000..43d4ab4 --- /dev/null +++ b/templates/etc/postfix/pgsql_virtual_alias_domain_maps.cf.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +hosts = {{ postfix_pgsql_host }}:{{ postfix_pgsql_port }} +user = {{ postfix_pgsql_username }} +password = {{ postfix_pgsql_password }} +dbname = {{ postfix_pgsql_name }} +query = {{ postfix_pgsql_virtual_alias_domain_maps_query }} diff --git a/templates/etc/postfix/pgsql_virtual_alias_maps.cf.j2 b/templates/etc/postfix/pgsql_virtual_alias_maps.cf.j2 new file mode 100644 index 0000000..1048fce --- /dev/null +++ b/templates/etc/postfix/pgsql_virtual_alias_maps.cf.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +hosts = {{ postfix_pgsql_host }}:{{ postfix_pgsql_port }} +user = {{ postfix_pgsql_username }} +password = {{ postfix_pgsql_password }} +dbname = {{ postfix_pgsql_name }} +query = {{ postfix_pgsql_virtual_alias_maps_query }} diff --git a/templates/etc/postfix/pgsql_virtual_mailbox_domains.cf.j2 b/templates/etc/postfix/pgsql_virtual_mailbox_domains.cf.j2 new file mode 100644 index 0000000..b694e58 --- /dev/null +++ b/templates/etc/postfix/pgsql_virtual_mailbox_domains.cf.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +hosts = {{ postfix_pgsql_host }}:{{ postfix_pgsql_port }} +user = {{ postfix_pgsql_username }} +password = {{ postfix_pgsql_password }} +dbname = {{ postfix_pgsql_name }} +query = {{ postfix_pgsql_virtual_mailbox_domains_query }} diff --git a/templates/etc/postfix/pgsql_virtual_mailbox_limit_maps.cf.j2 b/templates/etc/postfix/pgsql_virtual_mailbox_limit_maps.cf.j2 new file mode 100644 index 0000000..174eda4 --- /dev/null +++ b/templates/etc/postfix/pgsql_virtual_mailbox_limit_maps.cf.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +hosts = {{ postfix_pgsql_host }}:{{ postfix_pgsql_port }} +user = {{ postfix_pgsql_username }} +password = {{ postfix_pgsql_password }} +dbname = {{ postfix_pgsql_name }} +query = {{ postfix_pgsql_virtual_mailbox_limit_maps_query }} diff --git a/templates/etc/postfix/pgsql_virtual_mailbox_maps.cf.j2 b/templates/etc/postfix/pgsql_virtual_mailbox_maps.cf.j2 new file mode 100644 index 0000000..9ab89a2 --- /dev/null +++ b/templates/etc/postfix/pgsql_virtual_mailbox_maps.cf.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +hosts = {{ postfix_pgsql_host }}:{{ postfix_pgsql_port }} +user = {{ postfix_pgsql_username }} +password = {{ postfix_pgsql_password }} +dbname = {{ postfix_pgsql_name }} +query = {{ postfix_pgsql_virtual_mailbox_maps_query }} diff --git a/templates/etc/postfix/recipient_canonical_maps.j2 b/templates/etc/postfix/recipient_canonical_maps.j2 new file mode 100644 index 0000000..2f98912 --- /dev/null +++ b/templates/etc/postfix/recipient_canonical_maps.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +# Replace only recipient e-mail addresses. +# http://www.postfix.org/postconf.5.html#recipient_canonical_maps +{% for item in postfix_lmdb_recipient_canonical_maps_table_entries | default([]) %} +{{ item.origin }} {{ item.replacement }} +{% endfor %} \ No newline at end of file diff --git a/templates/etc/postfix/relay_domain_maps.j2 b/templates/etc/postfix/relay_domain_maps.j2 new file mode 100644 index 0000000..742f147 --- /dev/null +++ b/templates/etc/postfix/relay_domain_maps.j2 @@ -0,0 +1,11 @@ +# +# {{ ansible_managed }} +# + +# Domains that match $relay_domains are delivered with the $relay_transport mail +# delivery transport. The SMTP server validates recipient addresses with +# $relay_recipient_maps and rejects non-existent recipients. +# http://www.postfix.org/postconf.5.html#relay_domains +{% for item in postfix_lmdb_relay_domains_table_entries | default([]) %} +{{ item.domain }} {{ item.action }}{% if item.reason is defined %} {{ item.reason }}{% endif %} +{% endfor %} diff --git a/templates/etc/postfix/relay_recipient_maps.j2 b/templates/etc/postfix/relay_recipient_maps.j2 new file mode 100644 index 0000000..2537363 --- /dev/null +++ b/templates/etc/postfix/relay_recipient_maps.j2 @@ -0,0 +1,15 @@ +# +# {{ ansible_managed }} +# + +# Optional lookup tables with all valid addresses in the domains that match +# $relay_domains. Specify @domain as a wild-card for domains that have no valid +# recipient list, and become a source of backscatter mail: Postfix accepts spam +# for non-existent recipients and then floods innocent people with undeliverable +# mail. Technically, tables listed with $relay_recipient_maps are used as lists: +# Postfix needs to know only if a lookup string is found or not, but it does not +# use the result from table lookup. +# http://www.postfix.org/postconf.5.html#relay_recipient_maps +{% for item in postfix_lmdb_relay_recipients_table_entries | default([]) %} +{{ item.recipient }} {{ item.action }}{% if item.reason is defined %} {{ item.reason }}{% endif %} +{% endfor %} diff --git a/templates/etc/postfix/relocated_maps.j2 b/templates/etc/postfix/relocated_maps.j2 new file mode 100644 index 0000000..3ddd771 --- /dev/null +++ b/templates/etc/postfix/relocated_maps.j2 @@ -0,0 +1,10 @@ +# +# {{ ansible_managed }} +# + +# Optional lookup tables with new contact information for users or domains that +# no longer exist. +# http://www.postfix.org/postconf.5.html#relocated_maps +{% for item in postfix_lmdb_relocated_maps_table_entries | default([]) %} +{{ item.old_address }} {{ item.new_address }} +{% endfor %} diff --git a/templates/etc/postfix/sasl_password_maps.j2 b/templates/etc/postfix/sasl_password_maps.j2 new file mode 100644 index 0000000..2d8a3eb --- /dev/null +++ b/templates/etc/postfix/sasl_password_maps.j2 @@ -0,0 +1,7 @@ +# +# {{ ansible_managed }} +# + +{% for item in postfix_lmdb_smtp_sasl_password_maps_table_entries | default([]) %} +{{ item.destination }} {{ item.username }}:{{ item.password }} +{% endfor %} diff --git a/templates/etc/postfix/sender_canonical_maps.j2 b/templates/etc/postfix/sender_canonical_maps.j2 new file mode 100644 index 0000000..475397c --- /dev/null +++ b/templates/etc/postfix/sender_canonical_maps.j2 @@ -0,0 +1,9 @@ +# +# {{ ansible_managed }} +# + +# Replace only sender e-mail addresses. +# http://www.postfix.org/postconf.5.html#sender_canonical_maps +{% for item in postfix_lmdb_sender_canonical_maps_table_entries | default([]) %} +{{ item.origin }} {{ item.replacement }} +{% endfor %} \ No newline at end of file diff --git a/templates/etc/postfix/smtpd_sender_login_maps.j2 b/templates/etc/postfix/smtpd_sender_login_maps.j2 new file mode 100644 index 0000000..756a3c6 --- /dev/null +++ b/templates/etc/postfix/smtpd_sender_login_maps.j2 @@ -0,0 +1,17 @@ +# +# {{ ansible_managed }} +# + +# Optional lookup table with the SASL login names that own the sender (MAIL +# FROM) addresses. Used by reject_sender_login_mismatch and +# reject_authenticated_sender_login_mismatch restrictions. +# +# Lookup operations for a sender address user@domain: +# - user@domain: always done, highest precedence +# - user: only when domain matches $myorigin, $mydestination, $inet_interfaces +# or $proxy_interfaces +# - @domain: done last, lowest precedence +# http://www.postfix.org/postconf.5.html#smtpd_sender_login_maps +{% for item in postfix_lmdb_smtpd_sender_login_maps_table_entries | default([]) %} +{{ item.address }} {{ item.login }} +{% endfor %} diff --git a/templates/etc/postfix/submission_header_cleanup.j2 b/templates/etc/postfix/submission_header_cleanup.j2 new file mode 100644 index 0000000..03cb5ca --- /dev/null +++ b/templates/etc/postfix/submission_header_cleanup.j2 @@ -0,0 +1,10 @@ +# +# {{ ansible_managed }} +# + +# Removes information from the email header that is +# questionable from a data protection point of view. + +{% for entry in postfix_regexp_submission_header_cleanup_table_entries | default([]) %} +{{ entry.pattern }} IGNORE +{% endfor %} diff --git a/templates/etc/postfix/tls_policy_maps.j2 b/templates/etc/postfix/tls_policy_maps.j2 new file mode 100644 index 0000000..9c0aa34 --- /dev/null +++ b/templates/etc/postfix/tls_policy_maps.j2 @@ -0,0 +1,10 @@ +# +# {{ ansible_managed }} +# + +# Optional lookup tables with the Postfix SMTP client TLS security policy by +# next-hop destination. +# http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps +{% for item in postfix_lmdb_tls_policy_maps_table_entries | default([]) %} +{{ item.destination }} {{ item.policy }} +{% endfor %} diff --git a/templates/etc/postfix/transport_maps.j2 b/templates/etc/postfix/transport_maps.j2 new file mode 100644 index 0000000..9699d0c --- /dev/null +++ b/templates/etc/postfix/transport_maps.j2 @@ -0,0 +1,10 @@ +# +# {{ ansible_managed }} +# + +# Optional lookup tables with mappings from mail address or domain to message +# delivery transport and/or next-hop destination. +# http://www.postfix.org/postconf.5.html#transport_maps +{% for item in postfix_lmdb_transport_maps_table_entries | default([]) %} +{{ item.pattern }} {{ item.transport }} +{% endfor %} \ No newline at end of file diff --git a/templates/etc/postfix/virtual_alias_maps.j2 b/templates/etc/postfix/virtual_alias_maps.j2 new file mode 100644 index 0000000..dde37a1 --- /dev/null +++ b/templates/etc/postfix/virtual_alias_maps.j2 @@ -0,0 +1,11 @@ +# +# {{ ansible_managed }} +# + +# Optional lookup tables that alias specific mail addresses or domains to other +# local or remote address. The table format and lookups are documented in +# virtual(5). +# http://www.postfix.org/postconf.5.html#virtual_alias_maps +{% for item in postfix_lmdb_virtual_alias_maps_table_entries | default([]) %} +{{ item.source }} {{ item.destination }} +{% endfor %} \ No newline at end of file diff --git a/templates/etc/postfix/virtual_mailbox_domains.j2 b/templates/etc/postfix/virtual_mailbox_domains.j2 new file mode 100644 index 0000000..c72ea02 --- /dev/null +++ b/templates/etc/postfix/virtual_mailbox_domains.j2 @@ -0,0 +1,14 @@ +# +# {{ ansible_managed }} +# + +# Postfix is the final destination for the specified list of domains; mail is +# delivered via the $virtual_transport mail delivery transport. By default this +# is the Postfix virtual(8) delivery agent. The SMTP server validates recipient +# addresses with $virtual_mailbox_maps and rejects mail for non-existent +# recipients. See also the virtual mailbox domain class in the +# ADDRESS_CLASS_README file. +# http://www.postfix.org/postconf.5.html#virtual_mailbox_domains +{% for item in postfix_lmdb_virtual_mailbox_domains_table_entries | default([]) %} +{{ item.domain }} {{ item.action }} +{% endfor %} \ No newline at end of file diff --git a/templates/etc/postfix/virtual_mailbox_maps.j2 b/templates/etc/postfix/virtual_mailbox_maps.j2 new file mode 100644 index 0000000..06a766c --- /dev/null +++ b/templates/etc/postfix/virtual_mailbox_maps.j2 @@ -0,0 +1,14 @@ +# +# {{ ansible_managed }} +# + +# Optional lookup tables with all valid addresses in the domains that match +# $virtual_mailbox_domains. Specify zero or more "type:name" lookup tables, +# separated by whitespace or comma. Tables will be searched in the specified +# order until a match is found. In a lookup table, specify a left-hand side of +# "@domain.tld" to match any user in the specified domain that does not have a +# specific "user@domain.tld" entry. +# http://www.postfix.org/postconf.5.html#virtual_mailbox_maps +{% for item in postfix_lmdb_virtual_mailbox_maps_table_entries | default([]) %} +{{ item.address }} {{ item.action }} +{% endfor %} diff --git a/templates/etc/systemd/system/status-email@.service.j2 b/templates/etc/systemd/system/status-email@.service.j2 new file mode 100644 index 0000000..6501328 --- /dev/null +++ b/templates/etc/systemd/system/status-email@.service.j2 @@ -0,0 +1,12 @@ +# +# {{ ansible_managed }} +# + +[Unit] +Description=Unit to execute a notification service for systemd logfiles +Requires=network-online.target +After=network-online.target + +[Service] +Type=simple +ExecStart=/usr/local/sbin/systemd-email.sh markus.pesch@cryptic.systems %i diff --git a/templates/usr/local/sbin/systemd-email.sh.j2 b/templates/usr/local/sbin/systemd-email.sh.j2 new file mode 100644 index 0000000..01221b4 --- /dev/null +++ b/templates/usr/local/sbin/systemd-email.sh.j2 @@ -0,0 +1,9 @@ +#!/bin/bash + +# +# {{ ansible_managed }} +# + +TIMESTAMP="$(systemctl show "${2}" -p AssertTimestamp | awk '{print $2 " " $3;}')" + +journalctl --unit "${2}" --since "${TIMESTAMP}" | gpg --auto-key-locate clear,nodefault,wkd --trust-model always --encrypt --armor --recipient "${1}" | mail -s "${2}" "${1}"